oak-domain/lib/compiler/schemalBuilder.js

5727 lines
332 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildSchema = exports.getProjectionKeys = exports.buildSchemaBackup = exports.analyzeEntities = exports.getAnalizedSchema = exports.registerDeducedRelationMap = exports.registerFixedDestinationPathMap = exports.registerIgnoredRelationPathMap = exports.registerFreeEntities = exports.registerIgnoredForeignKeyMap = exports.translateLocaleObject = exports.constructAttributes = void 0;
const tslib_1 = require("tslib");
const path_1 = tslib_1.__importDefault(require("path"));
const assert_1 = tslib_1.__importDefault(require("assert"));
const fs_1 = require("fs");
const fs_extra_1 = require("fs-extra");
const lodash_1 = require("lodash");
const ts = tslib_1.__importStar(require("typescript"));
const { factory } = ts;
const env_1 = require("./env");
const string_1 = require("../utils/string");
const Schema = {};
const OneToMany = {};
const ManyToOne = {};
const ReversePointerEntities = {};
const ReversePointerRelations = {};
const ActionImportStatements = () => [
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, undefined, factory.createIdentifier("ActionDef"))])), factory.createStringLiteral(`${(0, env_1.TYPE_PATH_IN_OAK_DOMAIN)()}Action`), undefined),
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier("GenericAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("AppendOnlyAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("ReadOnlyAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("ExcludeUpdateAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("ExcludeRemoveAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("RelationAction")),
])), factory.createStringLiteral((0, env_1.ACTION_CONSTANT_IN_OAK_DOMAIN)()), undefined)
];
const StyleAsts = {};
const ActionAsts = {};
const SchemaAsts = {};
/**
* 部分项目目前存在引用了Schema但是不依赖于其包因此目前先在此去重。
* 后续要修正这种行为让继承的schema分层编译
* @param many
* @param one
* @param key
* @param notNull
*/
function addRelationship(many, one, key, notNull) {
const { [many]: manySet } = ManyToOne;
const one2 = one === 'Schema' ? many : one;
if (manySet) {
if (!manySet.find(ele => ele[1] === key && ele[0] === one2)) {
manySet.push([one2, key, notNull]);
}
}
else {
(0, lodash_1.assign)(ManyToOne, {
[many]: [[one2, key, notNull]],
});
}
const { [one2]: oneSet } = OneToMany;
if (oneSet) {
if (!oneSet.find(ele => ele[1] === key && ele[0] === many)) {
oneSet.push([many, key, notNull]);
}
}
else {
(0, lodash_1.assign)(OneToMany, {
[one2]: [[many, key, notNull]],
});
}
}
/**
* 对relationship去重。一旦发生对象重定义这里就有可能重复
*/
function uniqRelationships() {
for (const entity in ManyToOne) {
ManyToOne[entity] = (0, lodash_1.uniqBy)(ManyToOne[entity], (ele) => `${ele[0]}-${ele[1]}`);
}
for (const entity in OneToMany) {
OneToMany[entity] = (0, lodash_1.uniqBy)(OneToMany[entity], (ele) => `${ele[0]}-${ele[1]}`);
}
for (const entity in ReversePointerRelations) {
OneToMany[entity] = (0, lodash_1.uniq)(OneToMany[entity]);
}
}
function createForeignRef(entity, foreignKey, ref) {
if (entity === foreignKey) {
return factory.createIdentifier(ref);
}
return factory.createQualifiedName(factory.createIdentifier(foreignKey), factory.createIdentifier(ref));
}
function createIndexedForeignRef(foreignEntity, ref) {
return factory.createIndexedAccessTypeNode(factory.createTypeReferenceNode(factory.createIdentifier(foreignEntity), undefined), factory.createLiteralTypeNode(factory.createStringLiteral(ref)));
}
function pushStatementIntoActionAst(moduleName, node, sourceFile) {
// let actionNames;
let actionDefName;
/* if (ts.isTypeAliasDeclaration(node) && node.name.text === 'ParticularAction') {
const { type } = node;
if (ts.isUnionTypeNode(type)) {
actionNames = type.types.map(
(ele) => {
assert(ts.isTypeReferenceNode(ele));
const text = (<ts.Identifier>ele.typeName).text;
assert(text.endsWith('Action'));
return firstLetterLowerCase(text.slice(0, text.length - 6));
}
)
}
else {
assert(ts.isTypeReferenceNode(type));
const text = (<ts.Identifier>type.typeName).text;
assert(text.endsWith('Action'));
actionNames = [firstLetterLowerCase(text.slice(0, text.length - 6))];
}
} */
if (ts.isVariableStatement(node)) {
const { declarationList: { declarations } } = node;
declarations.forEach((declaration) => {
if (ts.isIdentifier(declaration.name) && declaration.name.text.endsWith('ActionDef')) {
const { text } = declaration.name;
actionDefName = (0, string_1.firstLetterLowerCase)(text.slice(0, text.length - 9));
}
});
}
if (ActionAsts[moduleName]) {
ActionAsts[moduleName].statements.push(node);
/* if (actionNames) {
ActionAsts[moduleName].actionNames = actionNames;
} */
if (actionDefName) {
ActionAsts[moduleName].actionDefNames.push(actionDefName);
}
}
else {
(0, lodash_1.assign)(ActionAsts, {
[moduleName]: {
statements: [...ActionImportStatements(), node],
sourceFile,
importActionFrom: {},
importStateFrom: {},
importActionDefFrom: {},
// actionNames,
actionDefNames: actionDefName ? [actionDefName] : [],
}
});
}
}
function pushStatementIntoSchemaAst(moduleName, statement, sourceFile) {
if (SchemaAsts[moduleName]) {
SchemaAsts[moduleName].statements.push(statement);
if (!SchemaAsts[moduleName].sourceFile && sourceFile) {
SchemaAsts[moduleName].sourceFile = sourceFile;
}
}
else {
(0, lodash_1.assign)(SchemaAsts, {
[moduleName]: {
statements: [statement],
sourceFile,
}
});
}
}
/**
* 检查ActionDef是否满足合法的定义
* 1、ActionDef, Action, State三者命名是否一致
* @param actionDefNode
*/
function checkActionDefNameConsistent(filename, actionDefNode) {
const { name, type } = actionDefNode;
(0, assert_1.default)(ts.isTypeReferenceNode(type), "ActionDef应该是一个类型引用");
const { typeArguments } = type;
(0, assert_1.default)(typeArguments.length === 2);
const [actionNode, stateNode] = typeArguments;
(0, assert_1.default)(ts.isIdentifier(name), `文件${filename}中的ActionDef${name.text}不是一个有效的变量`);
(0, assert_1.default)(name.text.endsWith('ActionDef'), `文件${filename}中的ActionDef${name.text}未以ActionDef结尾`);
(0, assert_1.default)(ts.isTypeReferenceNode(actionNode) && ts.isTypeReferenceNode(stateNode), `文件${filename}中的ActionDef${name.text}类型声明中的action和state非法`);
(0, assert_1.default)(ts.isIdentifier(actionNode.typeName) && ts.isIdentifier(stateNode.typeName));
(0, assert_1.default)(actionNode.typeName.text.endsWith('Action'), `文件${filename}中的ActionDef${name.text}所引用的Action${actionNode.typeName}未以Action结尾`);
(0, assert_1.default)(stateNode.typeName.text.endsWith('State'), `文件${filename}中的ActionDef${name.text}所引用的State${stateNode.typeName}未以State结尾`);
const adfName = name.text.slice(0, name.text.length - 9);
const aName = actionNode.typeName.text.slice(0, actionNode.typeName.text.length - 6);
const sName = stateNode.typeName.text.slice(0, stateNode.typeName.text.length - 5);
(0, assert_1.default)(adfName === aName && aName === sName, `文件${filename}中的ActionDef${name.text}中ActionDef, Action和State的命名规则不一致 需要
${adfName}ActionDef, ${adfName}Action, ${adfName}State`);
}
function checkStringLiteralLegal(filename, obj, text, ele) {
(0, assert_1.default)(ts.isLiteralTypeNode(ele) && ts.isStringLiteral(ele.literal), `${filename}中引用的${obj} ${text}中存在不是stringliteral的类型`);
(0, assert_1.default)(!ele.literal.text.includes('$'), `${filename}中引用的action${text}中的${obj}${ele.literal.text}」包含非法字符$`);
(0, assert_1.default)(ele.literal.text.length > 0, `${filename}中引用的action${text}中的${obj}${ele.literal.text}」长度非法`);
(0, assert_1.default)(ele.literal.text.length < env_1.STRING_LITERAL_MAX_LENGTH, `${filename}中引用的${obj} ${text}中的「${ele.literal.text}」长度过长`);
return ele.literal.text;
}
function addImportedFrom(moduleName, name, node) {
const ast = ActionAsts[moduleName];
let importFrom = typeof node === 'string' ? node : '';
let propertyName;
if (typeof node === 'object') {
const { moduleSpecifier, importClause } = node;
(0, assert_1.default)(ts.isStringLiteral(moduleSpecifier), `${moduleName}中的${name}未引用正确的moduleSpecifier`);
(0, assert_1.default)(importClause, `${moduleName}中的${name}未引用正确的importClause`);
const { namedBindings } = importClause;
(0, assert_1.default)(namedBindings, `${moduleName}中的${name}未引用正确的namedBindings`);
(0, assert_1.default)(ts.isNamedImports(namedBindings));
const importSpecifier = namedBindings.elements.find((ele) => ele.name.text === name);
(0, assert_1.default)(importSpecifier, `${moduleName}中的${name}未引用正确的importSpecifier`);
propertyName = importSpecifier.propertyName && importSpecifier.propertyName.text;
importFrom = moduleSpecifier.text;
}
if (name.endsWith('Action')) {
(0, lodash_1.assign)(ast.importActionFrom, {
[name]: [importFrom, propertyName],
});
}
else if (name.endsWith('ActionDef')) {
(0, lodash_1.assign)(ast.importActionDefFrom, {
[name]: [importFrom, propertyName],
});
}
else {
(0, assert_1.default)(name.endsWith("State"), `${moduleName}中的${name}未以State结尾`);
(0, lodash_1.assign)(ast.importStateFrom, {
[name]: [importFrom, propertyName],
});
}
}
/**
* 计算编译后文件的正确导入路径
* @param sourceFilePath 源文件路径(相对于项目根目录),例如: 'src/entities/User.ts'
* @param outputFilePath 输出文件路径(相对于项目根目录),例如: 'src/oak-app-domain/User/_baseschema.ts'
* @param importPath 原始导入路径,例如: '../types/Config' 或 '@/utils/helper'
* @param projectRoot 项目根目录,默认为当前目录
* @returns 新的相对导入路径
*/
function resolveCompiledImportPath(sourceFilePath, outputFilePath, importPath, projectRoot = '.', relative) {
// 如果不是相对路径(例如 node_modules 的包或别名路径),直接返回
if (!importPath.startsWith('.')) {
return importPath;
}
if (sourceFilePath.startsWith("node_modules")) {
// 如果是node_modules下的文件保持原有的处理逻辑
return importPath.startsWith('.') ? (relative
? path_1.default.join(relative, importPath).replace(/\\/g, '/')
: path_1.default.join('..', importPath).replace(/\\/g, '/')) : importPath;
}
// 1. 获取源文件所在目录
const sourceDir = path_1.default.dirname(sourceFilePath);
// 2. 解析原始导入路径,得到目标文件的绝对路径(相对于项目根目录)
const targetAbsolutePath = path_1.default.join(projectRoot, sourceDir, importPath);
const normalizedTargetPath = path_1.default.normalize(targetAbsolutePath);
// 3. 获取输出文件所在目录
const outputDir = path_1.default.dirname(outputFilePath);
const normalizedOutputDir = path_1.default.normalize(path_1.default.join(projectRoot, outputDir));
// 4. 计算从输出目录到目标文件的相对路径
let relativePath = path_1.default.relative(normalizedOutputDir, normalizedTargetPath);
// 5. 标准化路径分隔符为 '/'
relativePath = relativePath.replace(/\\/g, '/');
// 6. 确保相对路径以 './' 或 '../' 开头
if (!relativePath.startsWith('.')) {
relativePath = './' + relativePath;
}
return relativePath;
}
function analyzeExternalAttrImport(node, program, importAttrFrom, relativePath) {
const checker = program.getTypeChecker();
const symbol = checker.getSymbolAtLocation(node.typeName);
let declaration = symbol?.getDeclarations()[0];
/* const typee = checker.getDeclaredTypeOfSymbol(symbol!);
const declaration = typee.aliasSymbol!.getDeclarations()![0]; */
if (ts.isImportSpecifier(declaration)) {
const name = declaration.name.text;
const importDeclartion = declaration.parent.parent.parent;
(0, assert_1.default)(ts.isImportDeclaration(importDeclartion), `未找到${name}的importDeclaration`);
const { moduleSpecifier, importClause } = importDeclartion;
(0, assert_1.default)(ts.isStringLiteral(moduleSpecifier), `未找到${name}的moduleSpecifier`);
(0, assert_1.default)(importClause, `未找到${name}的importClause`);
const { namedBindings } = importClause;
(0, assert_1.default)(namedBindings, `未找到${name}的namedBindings`);
(0, assert_1.default)(ts.isNamedImports(namedBindings), `未找到${name}的namedImports`);
const importSpecifier = namedBindings.elements.find((ele) => ele.name.text === name);
(0, assert_1.default)(importSpecifier, `未找到${name}的importSpecifier`);
const propertyName = importSpecifier.propertyName && importSpecifier.propertyName.text;
const importFrom = moduleSpecifier.text;
// const importFromRelatively = importFrom.startsWith('.') ? (relativePath
// ? PathLib.join(
// relativePath,
// importFrom
// ).replace(/\\/g, '/')
// : PathLib.join(
// '..',
// importFrom
// ).replace(/\\/g, '/')) : importFrom;
const sourceFilePath = declaration.getSourceFile().fileName;
(0, lodash_1.assign)(importAttrFrom, {
// [name]: [importFromRelatively, propertyName],
[name]: [importFrom, propertyName, sourceFilePath, relativePath],
});
}
else if (ts.isTypeAliasDeclaration(declaration)) {
const traverseTsAst = (node) => {
// 递归遍历每个节点
ts.forEachChild(node, (child) => {
if (ts.isTypeReferenceNode(child)) {
analyzeExternalAttrImport(child, program, importAttrFrom, relativePath);
}
else {
traverseTsAst(child);
}
});
};
traverseTsAst(declaration);
}
}
function tryGetStringLiteralValues(moduleName, filename, obj, node, program) {
const checker = program.getTypeChecker();
const symbol = checker.getSymbolAtLocation(node.typeName);
let declaration = symbol?.getDeclarations()[0];
/* const typee = checker.getDeclaredTypeOfSymbol(symbol!);
const declaration = typee.aliasSymbol!.getDeclarations()![0]; */
const values = [];
if (ts.isImportSpecifier(declaration)) {
const typee = checker.getDeclaredTypeOfSymbol(symbol);
if (typee.isStringLiteral()) {
values.push(typee.value);
}
else if (typee.isUnion()) {
values.push(...typee.types.map(ele => {
if (ele.isStringLiteral()) {
return ele.value;
}
}).filter(ele => !!ele));
}
if (['state', 'action'].includes(obj)) {
(0, assert_1.default)(values.length > 0, `${filename}中的${obj} ${node.typeName.getText()}未定义`);
const importDeclartion = declaration.parent.parent.parent;
(0, assert_1.default)(ts.isImportDeclaration(importDeclartion), '未找到importDeclaration');
addImportedFrom(moduleName, declaration.name.text, importDeclartion);
}
}
else if (ts.isTypeAliasDeclaration(declaration)) {
// 本地定义的type
const { name, type } = declaration;
if (ts.isUnionTypeNode(type)) {
values.push(...(type.types.map(ele => {
if (ts.isLiteralTypeNode(ele)) {
return checkStringLiteralLegal(filename, obj, name.text, ele);
}
else if (ts.isTypeReferenceNode(ele)) {
return tryGetStringLiteralValues(moduleName, filename, obj, ele, program);
}
else {
throw new Error(`暂时不能处理的type${ele.getText()}`);
}
})).flat());
}
else if (ts.isLiteralTypeNode(type)) {
const action = checkStringLiteralLegal(filename, obj, name.text, type);
values.push(action);
}
if (['state', 'action'].includes(obj)) {
(0, assert_1.default)(values.length > 0, `${filename}中的${obj} ${node.typeName.getText()}未定义`);
const ast = ActionAsts[moduleName];
addImportedFrom(moduleName, declaration.name.text, './');
}
}
return values;
}
const RESERVED_ACTION_NAMES = ['GenericAction', 'ParticularAction', 'ExcludeRemoveAction', 'ExcludeUpdateAction', 'ReadOnlyAction', 'AppendOnlyAction', 'RelationAction'];
const action_1 = require("../actions/action");
const DataType_1 = require("../types/DataType");
const Entity_1 = require("../types/Entity");
const uuid_1 = require("../utils/uuid");
const OriginActionDict = {
'crud': 'GenericAction',
'excludeUpdate': 'ExcludeUpdateAction',
'excludeRemove': 'ExcludeRemoveAction',
'appendOnly': 'AppendOnlyAction',
'readOnly': 'ReadOnlyAction',
};
function dealWithActionTypeNode(moduleName, filename, actionTypeNode, program, sourceFile) {
const actionTexts = action_1.genericActions.map(ele => ele);
if (moduleName === 'User') {
actionTexts.push(...action_1.relationActions);
}
if (ts.isUnionTypeNode(actionTypeNode)) {
const actionNames = actionTypeNode.types.map(ele => {
if (ts.isTypeReferenceNode(ele) && ts.isIdentifier(ele.typeName)) {
return ele.typeName.text;
}
}).filter(ele => !!ele);
(0, assert_1.default)((0, lodash_1.intersection)(actionNames, RESERVED_ACTION_NAMES).length === 0, `${filename}中的Action命名不能是「${RESERVED_ACTION_NAMES.join(',')}」之一`);
actionTypeNode.types.forEach(ele => {
if (ts.isTypeReferenceNode(ele)) {
// 这里递归了类型定义去查找所有的action字符串
const actionStrings = tryGetStringLiteralValues(moduleName, filename, 'action', ele, program);
(0, assert_1.default)(actionStrings.length > 0, `${filename}中的Action所引用的Type定义为空`);
actionTexts.push(...actionStrings);
}
else {
(0, assert_1.default)(ts.isLiteralTypeNode(ele) && ts.isStringLiteral(ele.literal), `${moduleName}】action的定义既非Type也不是string`);
actionTexts.push(ele.literal.text);
}
});
}
else if (ts.isTypeReferenceNode(actionTypeNode)) {
if (ts.isIdentifier(actionTypeNode.typeName)) {
(0, assert_1.default)(!RESERVED_ACTION_NAMES.includes(actionTypeNode.typeName.text), `${filename}中的Action命名不能是「${RESERVED_ACTION_NAMES.join(',')}」之一`);
}
const actionStrings = tryGetStringLiteralValues(moduleName, filename, 'action', actionTypeNode, program);
(0, assert_1.default)(actionStrings.length > 0, `${filename}中的Action定义为空`);
actionTexts.push(...actionStrings);
}
else {
(0, assert_1.default)(ts.isLiteralTypeNode(actionTypeNode) && ts.isStringLiteral(actionTypeNode.literal), `${moduleName}】action的定义既非Type也不是string`);
actionTexts.push(actionTypeNode.literal.text);
}
// 所有的action定义不能有重名
const ActionDict = {};
actionTexts.forEach((action) => {
(0, assert_1.default)(action.length <= env_1.STRING_LITERAL_MAX_LENGTH, `${filename}中的Action「${action}」命名长度大于${env_1.STRING_LITERAL_MAX_LENGTH}`);
(0, assert_1.default)(/^[a-z][a-z|A-Z]+$/.test(action), `${filename}中的Action「${action}」命名不合法,必须以小字字母开头且只能包含字母`);
if (ActionDict.hasOwnProperty(action)) {
throw new Error(`文件${filename}Action定义上的【${action}】动作存在同名`);
}
else {
(0, lodash_1.assign)(ActionDict, {
[action]: 1,
});
}
});
pushStatementIntoActionAst(moduleName, factory.createVariableStatement([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([factory.createVariableDeclaration(factory.createIdentifier("actions"), undefined, undefined, factory.createArrayLiteralExpression(actionTexts.map(ele => factory.createStringLiteral(ele)), false))], ts.NodeFlags.Const)), sourceFile);
}
function dealWithActionDefInitializer(moduleName, initializer, program) {
if (ts.isIdentifier(initializer) || ts.isCallExpression(initializer)) {
// 是从别处的引用注入到mportActionDefFrom
const checker = program.getTypeChecker();
const identifier = ts.isIdentifier(initializer) ? initializer : initializer.expression;
(0, assert_1.default)(ts.isIdentifier(identifier), "ActionDef的initializer不是一个Identifier");
const symbol = checker.getSymbolAtLocation(identifier);
const declaration = symbol?.getDeclarations()[0];
(0, assert_1.default)(ts.isImportSpecifier(declaration), "ActionDef的initializer不是一个ImportSpecifier");
const importDeclartion = declaration.parent.parent.parent;
addImportedFrom(moduleName, identifier.text, importDeclartion);
}
else {
// 本地定义的actionDef不用处理
(0, assert_1.default)(ts.isObjectLiteralExpression(initializer), moduleName);
}
}
/**
* entity的引用一定要以 import { Schema as XXX } from '..../XXX'这种形式
* @param declaration
* @param filename
* @returns
*/
function getEntityImported(declaration) {
const { moduleSpecifier, importClause } = declaration;
let entityImported;
if (ts.isStringLiteral(moduleSpecifier)) {
const { name: importedFileName } = path_1.default.parse(moduleSpecifier.text);
const { namedBindings } = importClause;
if (namedBindings && ts.isNamedImports(namedBindings)) {
const { elements } = namedBindings;
if (elements.find(ele => ts.isImportSpecifier(ele) && ele.name.text === importedFileName && ele.propertyName?.text === 'Schema')) {
entityImported = importedFileName;
}
}
}
return entityImported;
}
function checkLocaleEnumAttrs(node, attrs, filename) {
const { members } = node;
const memberKeys = members.map((ele) => {
(0, assert_1.default)(ts.isPropertySignature(ele) && ts.isIdentifier(ele.name), 'locale定义中的属性必须是identifier');
return ele.name.text;
});
const lack = (0, lodash_1.difference)(attrs, memberKeys);
if (lack.length > 0) {
throw new Error(`${filename}中缺少了对${lack.join(',')}属性的locale定义`);
}
}
function checkLocaleExpressionPropertyExists(root, attr, exists, filename) {
const { properties } = root;
properties.forEach((ele) => {
(0, assert_1.default)(ts.isPropertyAssignment(ele) && (ts.isIdentifier(ele.name) || ts.isStringLiteral(ele.name)) && ts.isObjectLiteralExpression(ele.initializer));
const { properties: p2 } = ele.initializer;
const pp = p2.find((ele2) => {
(0, assert_1.default)(ts.isPropertyAssignment(ele2) && ts.isIdentifier(ele2.name), 'locale定义中的属性必须是identifier');
return ele2.name.text === attr;
});
if (exists && !pp) {
throw new Error(`${filename}中的locale定义中的${ele.name.text}中缺少了${attr}的定义`);
}
else if (!exists && pp) {
throw new Error(`${filename}中的locale定义中的${ele.name.text}中有多余的${attr}定义`);
}
});
}
/* function getStringEnumValues(filename: string, program: ts.Program, obj: string, node: ts.TypeReferenceNode) {
const checker = program.getTypeChecker();
const symbol = checker.getSymbolAtLocation(node.typeName);
let declaration = symbol?.getDeclarations()![0]!;
if (ts.isImportSpecifier(declaration)) {
const typee = checker.getDeclaredTypeOfSymbol(symbol!);
declaration = typee.aliasSymbol?.getDeclarations()![0]!;
}
if (declaration && ts.isTypeAliasDeclaration(declaration)) {
if (ts.isUnionTypeNode(declaration.type) && ts.isLiteralTypeNode(declaration.type.types[0])) {
return declaration.type.types.map(
ele => checkStringLiteralLegal(filename, obj, (<ts.TypeAliasDeclaration>declaration).name.text, ele)
)
}
if (ts.isLiteralTypeNode(declaration.type)) {
const value = checkStringLiteralLegal(filename, obj, declaration.name.text, declaration.type);
return [value];
}
}
} */
function checkNameLegal(filename, attrName, upperCase) {
(0, assert_1.default)(attrName.length <= env_1.ENTITY_NAME_MAX_LENGTH, `文件「${filename}」:「${attrName}」的名称定义过长,不能超过「${env_1.ENTITY_NAME_MAX_LENGTH}」长度`);
if (upperCase) {
(0, assert_1.default)(/[A-Z][a-z|A-Z|0-9]+/i.test(attrName), `文件「${filename}」:「${attrName}」的名称必须以大写字母开始,且只能包含字母和数字`);
}
else if (upperCase === false) {
(0, assert_1.default)(/[a-z][a-z|A-Z|0-9]+/i.test(attrName), `文件「${filename}」:「${attrName}」的名称必须以小写字母开始,且只能包含字母和数字`);
}
else {
(0, assert_1.default)(/[a-z|A-Z][a-z|A-Z|0-9]+/i.test(attrName), `文件「${filename}」:「${attrName}」的名称必须以字母开始,且只能包含字母和数字`);
}
}
/**
* 分析import语句这里注意要去重
* @param node
* @param referencedSchemas
* @param additionalImports
* @param relativePath
*/
function analyzeImportDeclaration(node, referencedSchemas, additionalImports, filename, relativePath) {
const entityImported = getEntityImported(node);
if (entityImported) {
referencedSchemas.push(entityImported);
}
else {
/* const { moduleSpecifier, importClause } = node;
assert(ts.isStringLiteral(moduleSpecifier), `${filename}中的import出现了非stringLiteral类型的import module specifier无法处理`);
const { text } = moduleSpecifier;
// 和数据类型相关的会自动引入这里忽略见initialStatements
// 如果是相对路径,编译后的路径默认要深一层
const moduleSpecifier2Text = text.startsWith('.') ? (relativePath
? PathLib.join(
relativePath,
text
).replace(/\\/g, '/')
: PathLib.join(
'..',
text
).replace(/\\/g, '/')) : text;
// 去重
if (importClause) {
const { name, namedBindings } = importClause;
assert(namedBindings && ts.isNamedImports(namedBindings));
assert(!name, `「${filename}」schema定义中出现了import NAME from请避免`);
const unrepeatedSpecifiers: ts.ImportSpecifier[] = [];
for (const ele2 of namedBindings.elements) {
let repeated = false;
for (const imports of additionalImports) {
const { moduleSpecifier: ms, importClause: ic } = imports;
assert(ts.isStringLiteral(ms));
if (ic && ic.namedBindings) {
assert(ts.isNamedImports(ic.namedBindings));
const { elements } = ic.namedBindings;
for (const ele of elements) {
const { name: n, propertyName: pn } = ele;
if (n.text === ele2.name.text || (pn?.text && pn?.text === ele2.propertyName?.text)) {
assert(n.text === ele2.name.text && pn?.text === ele2.propertyName?.text, `解析「${filename}」时发现了name和propertyName不全等的import语句。${[n.text, pn?.text, ele2.name.text, ele2.propertyName?.text].filter(ele => !!ele).join(',')}可能是在Schema的继承链上出现请修正`);
assert(moduleSpecifier.text === ms.text, `解析「${filename}」时发现了name和propertyName完全相等的import语句但它们的from目标不完全相同。${[moduleSpecifier.text, ms.text].join(',')}可能是在Schema的继承链上出现请修正`);
repeated = true;
break;
}
}
}
if (repeated) {
break;
}
}
if (!repeated) {
unrepeatedSpecifiers.push(ele2);
}
}
if (unrepeatedSpecifiers.length > 0) {
additionalImports.push(
factory.updateImportDeclaration(
node,
undefined,
factory.createImportClause(false, undefined, factory.createNamedImports(unrepeatedSpecifiers)),
factory.createStringLiteral(moduleSpecifier2Text),
undefined
)
);
}
}
else {
additionalImports.push(
factory.updateImportDeclaration(
node,
undefined,
undefined,
factory.createStringLiteral(moduleSpecifier2Text),
undefined
)
);
} */
}
}
/**
* 处理模块的导入得到导入文件的sourcefile
*/
function dealImportedFile(path, fileSpecifierPath, filename, program) {
let importedFilepath = '';
const getExistedFileName = () => {
if ((0, fs_1.existsSync)(`${importedFilepath}.ts`)) {
return `${importedFilepath}.ts`;
}
else if ((0, fs_1.existsSync)(`${importedFilepath}.d.ts`)) {
return `${importedFilepath}.d.ts`;
}
return '';
};
if (fileSpecifierPath.startsWith('.')) {
importedFilepath = path_1.default.join(path, fileSpecifierPath);
const importedFilename = getExistedFileName();
(0, assert_1.default)(importedFilename, `${filename}」中import路径${fileSpecifierPath}找不到对应的声明`);
const sourceFile = program.getSourceFile(importedFilename);
(0, assert_1.default)(sourceFile, `${filename}」中import路径${fileSpecifierPath}找不到对应的声明`);
return [sourceFile, importedFilename];
}
// 创建编译器主机
const compilerHost = ts.createCompilerHost(program.getCompilerOptions());
// 解析模块
const resolvedModule = ts.resolveModuleName(fileSpecifierPath, filename, program.getCompilerOptions(), compilerHost);
(0, assert_1.default)(resolvedModule.resolvedModule, `${filename}」中import路径${fileSpecifierPath}找不到对应的声明`);
const pathName = resolvedModule.resolvedModule.resolvedFileName;
const sourceFile = program.getSourceFile(pathName);
(0, assert_1.default)(sourceFile, `${filename}」中import路径${fileSpecifierPath}找不到对应的声明`);
return [sourceFile, pathName];
}
/**
* 在path下的filename文件中import了fileSpecifierPath要找到其对应的引用路径
* 这里关键是要处理形如file:的依赖声明
* @param path
* @param fileSpecifierPath
* @param filename
* @returns
*/
// function getImportedFilePath(path: string, fileSpecifierPath: string, filename: string) {
// let importedFilepath = '';
// const getExistedFileName = () => {
// if (existsSync(`${importedFilepath}.ts`)) {
// return `${importedFilepath}.ts`;
// }
// else if (existsSync(`${importedFilepath}.d.ts`)) {
// return `${importedFilepath}.d.ts`;
// }
// return '';
// };
// if (fileSpecifierPath.startsWith('.')) {
// importedFilepath = PathLib.join(path, fileSpecifierPath);
// const importedFilename = getExistedFileName();
// assert(importedFilename, `「${filename}」中import路径${fileSpecifierPath}找不到对应的声明`);
// return importedFilename;
// }
// else {
// const cwd = process.cwd();
// const fileSpecifierPaths = fileSpecifierPath.split('/');
// const moduleName = fileSpecifierPaths[0] || fileSpecifierPaths[1];
// assert(moduleName, '「${filename}」中import路径不合法');
// // 从path向外找package.json -> node_modules直至找到fileSpecifier
// const paths = path.split('/');
// for (let iter = paths.length; iter >= 0; iter--) {
// const paths2 = paths.slice(0, iter);
// const pkgJsonPath = PathLib.join(cwd, ...paths2, 'package.json');
// if (existsSync(pkgJsonPath)) {
// const pkgJson = require(pkgJsonPath);
// if (pkgJson.dependencies?.hasOwnProperty(moduleName)) {
// const dependentPath = pkgJson.dependencies[moduleName] as string;
// if (dependentPath.trimStart().startsWith('file:')) {
// const dependentFilePath = dependentPath.trimStart().slice(5);
// importedFilepath = PathLib.join(pkgJsonPath, '..', dependentFilePath, ...(fileSpecifierPaths[0] ? fileSpecifierPaths.slice(1) : (fileSpecifierPaths.slice(2))));
// }
// else {
// importedFilepath = PathLib.join(pkgJsonPath, '..', 'node_modules', fileSpecifierPath);
// }
// const importedFilename = getExistedFileName();
// if (importedFilename) {
// return importedFilename;
// }
// }
// }
// }
// }
// assert(false, `「${filename}」中import路径${fileSpecifierPath}找不到对应的声明`);
// }
function analyzeSchemaDefinition(node, moduleName, filename, path, program, referencedSchemas, schemaAttrs, enumAttributes, importAttrFrom, relativePath) {
let hasEntityAttr = false;
let hasEntityIdAttr = false;
let toModi = false;
let toLog = false;
const extendsFrom = [];
const { members, heritageClauses } = node;
(0, assert_1.default)(heritageClauses, `${filename}」中的Schema定义需要继承EntityShape或者其他Entity`);
const heritagedResult = heritageClauses.map((clause) => {
const { expression } = clause.types[0];
(0, assert_1.default)(ts.isIdentifier(expression), `${expression}不是一个合法的继承类型`);
if (expression.text === 'EntityShape') {
// import { EntityShape } from 'oak-domain/lib/types/Entities; 所有schema的公共祖先类型不用处理
return;
}
// 从其它文件的Schema类继承这里需要将所继承的对象的属性进行访问并展开
(0, assert_1.default)(referencedSchemas.includes(expression.text), `${filename}」中的Schema继承了未定义的实体「${expression.text}`);
const checker = program.getTypeChecker();
const symbol = checker.getSymbolAtLocation(expression);
let declaration = symbol?.getDeclarations()[0];
(0, assert_1.default)(ts.isImportSpecifier(declaration), `${declaration.getText()}应该是导入的类型`);
const importDeclaration = declaration.parent.parent.parent;
(0, assert_1.default)(ts.isImportDeclaration(importDeclaration), `${declaration.getText()}应该是导入的类型`);
const { moduleSpecifier } = importDeclaration;
(0, assert_1.default)(ts.isStringLiteral(moduleSpecifier), `${declaration.getText()}应该是导入的类型`);
const { text: from } = moduleSpecifier;
extendsFrom.push(from);
const [sourceFile, pathName] = dealImportedFile(path, from, filename, program);
const relativeFilename = path_1.default.relative(process.cwd(), pathName);
const result = analyzeReferenceSchemaFile(moduleName, path_1.default.basename(relativeFilename), path_1.default.dirname(relativeFilename), sourceFile, program, referencedSchemas, schemaAttrs, enumAttributes, importAttrFrom, path_1.default.join(from, '..'));
return result;
}).filter(ele => !!ele);
// assert(['EntityShape'].includes((<ts.Identifier>heritageClauses![0].types![0].expression).text), moduleName);
members.forEach((attrNode) => {
const { type, name, questionToken } = attrNode;
const attrName = name.text;
checkNameLegal(filename, attrName, false);
if (ts.isTypeReferenceNode(type)
&& ts.isIdentifier(type.typeName)) {
if ((referencedSchemas.includes(type.typeName.text) || type.typeName.text === 'Schema')) {
addRelationship(moduleName, type.typeName.text, attrName, !!questionToken);
schemaAttrs.push(attrNode);
}
else if (type.typeName.text === 'Array') {
// 这是一对多的反向指针的引用,需要特殊处理
const { typeArguments } = type;
(0, assert_1.default)(typeArguments.length === 1
&& ts.isTypeReferenceNode(typeArguments[0])
&& ts.isIdentifier(typeArguments[0].typeName)
&& referencedSchemas.includes(typeArguments[0].typeName.text), `${filename}」非法的属性定义「${attrName}`);
const reverseEntity = typeArguments[0].typeName.text;
if (ReversePointerRelations[reverseEntity]) {
if (!ReversePointerRelations[reverseEntity].includes(moduleName)) {
ReversePointerRelations[reverseEntity].push(moduleName);
}
}
else {
(0, lodash_1.assign)(ReversePointerRelations, {
[reverseEntity]: [moduleName],
});
}
if (reverseEntity === 'Modi') {
toModi = true;
}
else if (reverseEntity === 'Log') {
toLog = true;
}
}
else {
schemaAttrs.push(attrNode);
const enumStringValues = tryGetStringLiteralValues(moduleName, filename, `attr-${attrName}`, type, program);
if (enumStringValues.length > 0) {
enumAttributes[attrName] = enumStringValues;
}
analyzeExternalAttrImport(type, program, importAttrFrom, relativePath);
}
}
else if (ts.isArrayTypeNode(type) && ts.isTypeReferenceNode(type.elementType) && ts.isIdentifier(type.elementType.typeName)) {
const { typeName } = type.elementType;
if (referencedSchemas.includes(typeName.text)) {
// 这也是一对多的反指定义
const reverseEntity = typeName.text;
if (ReversePointerRelations[reverseEntity]) {
if (!ReversePointerRelations[reverseEntity].includes(moduleName)) {
ReversePointerRelations[reverseEntity].push(moduleName);
}
}
else {
(0, lodash_1.assign)(ReversePointerRelations, {
[reverseEntity]: [moduleName],
});
}
if (reverseEntity === 'Modi') {
toModi = true;
}
else if (reverseEntity === 'Log') {
toLog = true;
}
}
else {
schemaAttrs.push(attrNode);
analyzeExternalAttrImport(type.elementType, program, importAttrFrom, relativePath);
// throw new Error(`对象${moduleName}中定义的属性${attrName}是不可识别的数组类别`);
}
}
else {
schemaAttrs.push(attrNode);
if (ts.isUnionTypeNode(type) && ts.isLiteralTypeNode(type.types[0]) && ts.isStringLiteral(type.types[0].literal)) {
(0, assert_1.default)(ts.isIdentifier(name), `${filename}」中的属性定义不是String类型`);
const { types } = type;
const enumValues = types.map((ele) => checkStringLiteralLegal(filename, '属性', name.text, ele));
enumAttributes[name.text] = enumValues;
}
else if (ts.isLiteralTypeNode(type) && ts.isStringLiteral(type.literal)) {
// 单个字符串的情形,目前应该没有,没测试过,先写着 by Xc 20230221
(0, assert_1.default)(ts.isIdentifier(name));
const enumValues = [
checkStringLiteralLegal(filename, '属性', name.text, type)
];
enumAttributes[name.text] = enumValues;
}
}
if (attrName === 'entity') {
(0, assert_1.default)(ts.isTypeReferenceNode(type) && ts.isIdentifier(type.typeName), `${moduleName}」中entity属性的定义不是String<32>类型entity是系统用于表示反指指针的保留属性请勿他用`);
const { typeArguments } = type;
(0, assert_1.default)(type.typeName.text === 'String'
&& typeArguments
&& typeArguments.length === 1, `${moduleName}」中entity属性的定义不是String<32>类型entity是系统用于表示反指指针的保留属性请勿他用`);
const [node] = typeArguments;
if (ts.isLiteralTypeNode(node) && ts.isNumericLiteral(node.literal)) {
if (parseInt(node.literal.text) > 32) {
(0, assert_1.default)(false, `${moduleName}」中entity属性的定义不是String<32>类型entity是系统用于表示反指指针的保留属性请勿他用`);
}
else {
hasEntityAttr = true;
}
}
}
if (attrName === 'entityId') {
(0, assert_1.default)(ts.isTypeReferenceNode(type) && ts.isIdentifier(type.typeName), `${moduleName}」中entityId属性的定义不是String<64>类型entityId是系统用于表示反指指针的保留属性请勿他用`);
const { typeArguments } = type;
(0, assert_1.default)(type.typeName.text === 'String' && typeArguments && typeArguments.length === 1, `${moduleName}」中entityId属性的定义不是String<64>类型entityId是系统用于表示反指指针的保留属性请勿他用`);
const [node] = typeArguments;
if (ts.isLiteralTypeNode(node) && ts.isNumericLiteral(node.literal)) {
if (parseInt(node.literal.text) !== 64) {
(0, assert_1.default)(false, `${moduleName}」中entityId属性的定义不是String<64>类型entityId是系统用于表示反指指针的保留属性请勿他用`);
}
else {
hasEntityIdAttr = true;
}
}
}
});
// 如果继承的对象属性中有相应的定义,一样起效
heritagedResult.forEach(ele => {
if (ele?.hasEntityAttr) {
(0, assert_1.default)(!hasEntityAttr && !hasEntityIdAttr, `${filename}」继承的对象中已经声明了entity和entityId不可重复声明`);
(0, assert_1.default)(ele.hasEntityIdAttr);
hasEntityAttr = true;
hasEntityIdAttr = true;
}
else if (ele?.hasEntityIdAttr) {
(0, assert_1.default)(false, `${filename}」所继承的对象中的entity和entityId没有成对出现`);
}
if (ele?.toModi) {
(0, assert_1.default)(!hasEntityAttr && !hasEntityIdAttr, `${filename}」继承的对象中已经声明了modi不可重复声明`);
toModi = true;
}
if (ele?.toLog) {
toLog = true;
}
});
return {
hasEntityAttr,
hasEntityIdAttr,
toModi,
toLog,
extendsFrom,
};
}
function analyzeReferenceSchemaFile(moduleName, filename, path, sourceFile, program, referencedSchemas, schemaAttrs, enumAttributes, importAttrFrom, relativePath) {
let result;
ts.forEachChild(sourceFile, (node) => {
if (ts.isImportDeclaration(node)) {
analyzeImportDeclaration(node, referencedSchemas, [], filename, relativePath);
}
if (ts.isInterfaceDeclaration(node)) {
// schema 定义
if (node.name.text === 'Schema') {
result = analyzeSchemaDefinition(node, moduleName, filename, path, program, referencedSchemas, schemaAttrs, enumAttributes, importAttrFrom, relativePath);
}
else if (!node.name.text.endsWith('Relation') && !node.name.text.endsWith('Action') && !node.name.text.endsWith('State')) {
// 本地规定的一些形状定义,直接使用
pushStatementIntoSchemaAst(moduleName, node);
}
}
if (ts.isTypeAliasDeclaration(node)) {
if (!node.name.text.endsWith('Relation') && !node.name.text.endsWith('Action') && !node.name.text.endsWith('State')) {
// 本地规定的一些形状定义,直接使用
pushStatementIntoSchemaAst(moduleName, node);
}
}
});
(0, assert_1.default)(result, `${filename}」中没有找到Schema定义`);
return result;
}
function analyzeEntity(filename, path, program, relativePath) {
const fullPath = `${path}/${filename}`;
const sourceFile = program.getSourceFile(fullPath);
(0, assert_1.default)(sourceFile, `${filename}」文件不存在`);
const moduleName = filename.split('.')[0];
if (Schema.hasOwnProperty(moduleName)) {
delete ActionAsts[moduleName];
delete SchemaAsts[moduleName];
delete StyleAsts[moduleName];
// removeFromRelationShip(moduleName);
console.warn(`出现了同名的Entity定义「${moduleName}」,将使用${fullPath}取代掉默认对象,请检查新的对象结构及相关常量定义与原有的兼容,否则原有对象的相关逻辑会出现不可知异常`);
}
checkNameLegal(filename, moduleName, true);
const referencedSchemas = [];
const schemaAttrs = [];
let hasFulltextIndex = false;
let indexes;
let beforeSchema = true;
let hasActionDef = false;
let relations = false;
let hasActionOrStateDef = false;
let actionType = 'crud';
let _static = false;
const enumAttributes = {};
const importAttrFrom = {};
let localeDef = undefined;
let extendsFrom;
// let relationHierarchy: ts.ObjectLiteralExpression | undefined = undefined;
// let reverseCascadeRelationHierarchy: ts.ObjectLiteralExpression | undefined = undefined;
let toModi = false;
let toLog = false;
ts.forEachChild(sourceFile, (node) => {
if (ts.isImportDeclaration(node)) {
analyzeImportDeclaration(node, referencedSchemas, [], filename, relativePath);
}
if (ts.isInterfaceDeclaration(node)) {
// schema 定义
if (node.name.text === 'Schema') {
beforeSchema = false;
const result = analyzeSchemaDefinition(node, moduleName, filename, path, program, referencedSchemas, schemaAttrs, enumAttributes, importAttrFrom, relativePath);
if (result.hasEntityAttr && result.hasEntityIdAttr) {
(0, lodash_1.assign)(ReversePointerEntities, {
[moduleName]: 1,
});
}
else if (result.hasEntityAttr || result.hasEntityIdAttr) {
throw new Error(`文件「${filename}」:属性 定义中只包含${result.hasEntityAttr ? 'entity' : 'entityId'}不符合定义规范。entity/entityId必须联合出现代表不定对象的反向指针`);
}
beforeSchema = false;
toModi = result.toModi;
toLog = result.toLog;
extendsFrom = result.extendsFrom;
// 对于不是Modi和Oper的对象全部建立和ModiEntity的反指关系
/* if (!['Modi', 'Oper', 'OperEntity', 'ModiEntity'].includes(moduleName) && !toModi) {
if (ReversePointerRelations['ModiEntity']) {
if (!ReversePointerRelations['ModiEntity'].includes(moduleName)) {
ReversePointerRelations['ModiEntity'].push(moduleName);
}
}
else {
assign(ReversePointerRelations, {
['ModiEntity']: [moduleName],
});
}
if (ReversePointerRelations['OperEntity']) {
if (!ReversePointerRelations['OperEntity'].includes(moduleName)) {
ReversePointerRelations['OperEntity'].push(moduleName);
}
}
else {
assign(ReversePointerRelations, {
['OperEntity']: [moduleName],
});
}
} */
}
else if (beforeSchema) {
// 本地规定的一些形状定义,直接使用
pushStatementIntoSchemaAst(moduleName, node, sourceFile);
}
}
if (ts.isTypeAliasDeclaration(node)) {
// action 定义
if (node.name.text === 'Action') {
(0, assert_1.default)(!localeDef, `${filename}】locale定义须在Action之后`);
hasActionDef = true;
const modifiers = [factory.createModifier(ts.SyntaxKind.ExportKeyword)];
pushStatementIntoActionAst(moduleName, factory.updateTypeAliasDeclaration(node, modifiers, factory.createIdentifier('ParticularAction'), node.typeParameters, node.type), sourceFile);
dealWithActionTypeNode(moduleName, filename, node.type, program, sourceFile);
}
else if (node.name.text === 'Relation') {
(0, assert_1.default)(!localeDef, `${filename}】locale定义须在Relation之后`);
const relationValues = [];
if (ts.isLiteralTypeNode(node.type)) {
(0, assert_1.default)(ts.isStringLiteral(node.type.literal), `${filename}中的Relation的定义只能是string类型`);
(0, assert_1.default)(node.type.literal.text.length < env_1.STRING_LITERAL_MAX_LENGTH, `Relation定义的字符串长度不长于${env_1.STRING_LITERAL_MAX_LENGTH}${filename}${node.type.literal.text}`);
relationValues.push(node.type.literal.text);
}
else if (ts.isTypeReferenceNode(node.type)) {
const relationStrings = tryGetStringLiteralValues(moduleName, filename, 'relation', node.type, program);
(0, assert_1.default)(relationStrings.length > 0, `文件${filename}中的relation${node.type.typeName.text}定义未找到字符串类型`);
relationValues.push(...relationStrings);
}
else {
(0, assert_1.default)(ts.isUnionTypeNode(node.type), `Relation的定义只能是string类型或者string union类型或者两者的union${filename}`);
node.type.types.forEach((ele) => {
if (ts.isLiteralTypeNode(ele)) {
(0, assert_1.default)(ts.isStringLiteral(ele.literal), `Relation的定义只能是string类型${filename}`);
(0, assert_1.default)(ele.literal.text.length < env_1.STRING_LITERAL_MAX_LENGTH, `Relation定义的字符串长度不长于${env_1.STRING_LITERAL_MAX_LENGTH}${filename}${ele.literal.text}`);
relationValues.push(ele.literal.text);
}
else {
(0, assert_1.default)(ts.isTypeReferenceNode(ele), `Relation的定义只能是string类型或者string union类型或者两者的union${filename}`);
const relationStrings = tryGetStringLiteralValues(moduleName, filename, 'relation', ele, program);
(0, assert_1.default)(relationStrings.length > 0, `文件${filename}中的relation${ele.typeName.text}定义未找到字符串类型`);
relationValues.push(...relationStrings);
}
});
}
// 对UserEntityGrant对象建立相应的反指关系
// UserEntityGrant结构改变不再建立by Xc 20231101
/* if (ReversePointerRelations['UserEntityGrant']) {
if (!ReversePointerRelations['UserEntityGrant'].includes(moduleName)) {
ReversePointerRelations['UserEntityGrant'].push(moduleName);
}
}
else {
assign(ReversePointerRelations, {
['UserEntityGrant']: [moduleName],
});
} */
// 对Relation对象建立相应的反指关系
if (ReversePointerRelations['Relation']) {
if (!ReversePointerRelations['Relation'].includes(moduleName)) {
ReversePointerRelations['Relation'].push(moduleName);
}
}
else {
(0, lodash_1.assign)(ReversePointerRelations, {
['Relation']: [moduleName],
});
}
// 对UserRelation对象建立相应的反指关系
if (ReversePointerRelations['UserRelation']) {
if (!ReversePointerRelations['UserRelation'].includes(moduleName)) {
ReversePointerRelations['UserRelation'].push(moduleName);
}
}
else {
(0, lodash_1.assign)(ReversePointerRelations, {
['UserRelation']: [moduleName],
});
}
relations = relationValues;
}
else if (node.name.text.endsWith('Action') || node.name.text.endsWith('State')) {
(0, assert_1.default)(!localeDef, `${filename}】locale定义须在Action/State之后`);
hasActionOrStateDef = true;
const { type } = node;
if (ts.isUnionTypeNode(type)) {
pushStatementIntoActionAst(moduleName, factory.updateTypeAliasDeclaration(node, [factory.createModifier(ts.SyntaxKind.ExportKeyword)], node.name, node.typeParameters, process.env.COMPLING_AS_LIB ? factory.createUnionTypeNode([
...type.types,
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
]) : type), sourceFile);
}
else {
(0, assert_1.default)(ts.isLiteralTypeNode(type) || ts.isTypeReferenceNode(type), `文件${filename}中的${type.getText()}应该是字面量或引用类型`);
pushStatementIntoActionAst(moduleName, factory.updateTypeAliasDeclaration(node, [factory.createModifier(ts.SyntaxKind.ExportKeyword)], node.name, node.typeParameters, process.env.COMPLING_AS_LIB ? factory.createUnionTypeNode([
type,
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
]) : type), sourceFile);
}
}
else if (beforeSchema) {
// 本地规定的一些形状定义,直接使用
pushStatementIntoSchemaAst(moduleName, node, sourceFile);
}
}
if (ts.isVariableStatement(node)) {
const { declarationList: { declarations } } = node;
const dealWithActionDef = (declaration) => {
checkActionDefNameConsistent(filename, declaration);
const { typeArguments } = declaration.type;
(0, assert_1.default)(typeArguments.length === 2, `文件${filename}中的action定义不是两个泛型参数`);
const [actionNode, stateNode] = typeArguments;
(0, assert_1.default)(ts.isTypeReferenceNode(actionNode), `文件${filename}中的action定义不是TypeReferenceNode`);
// 这里有可能引用的Action不是本文件的定义要调用这个函数加到importFrom中
tryGetStringLiteralValues(moduleName, filename, 'action', actionNode, program);
(0, assert_1.default)(ts.isTypeReferenceNode(stateNode), `文件${filename}中的action定义不是TypeReferenceNode`);
const enumStateValues = tryGetStringLiteralValues(moduleName, filename, 'state', stateNode, program);
(0, assert_1.default)(enumStateValues.length > 0, `文件${filename}中的state${stateNode.typeName.text}定义不是字符串类型`);
pushStatementIntoActionAst(moduleName, node, sourceFile);
dealWithActionDefInitializer(moduleName, declaration.initializer, program);
(0, assert_1.default)(ts.isIdentifier(declaration.name));
const adName = declaration.name.text.slice(0, declaration.name.text.length - 9);
const attr = adName.concat('State');
schemaAttrs.push(factory.createPropertySignature(undefined, (0, string_1.firstLetterLowerCase)(attr), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(attr)));
enumAttributes[(0, string_1.firstLetterLowerCase)(attr)] = enumStateValues;
};
const dealWithIndexes = (declaration) => {
const indexNameDict = {};
// 检查索引的属性是否合法
const { elements } = declaration;
elements.forEach((ele) => {
let isFulltextIndex = false;
(0, assert_1.default)(ts.isObjectLiteralExpression(ele), `${filename}」中索引定义应该是对象字面量`);
const { properties } = ele;
const attrProperty = properties.find((ele2) => {
(0, assert_1.default)(ts.isPropertyAssignment(ele2), `${filename}」中索引的属性不为PropertyAssignment`);
return ele2.name.getText() === 'attributes';
});
(0, assert_1.default)(ts.isArrayLiteralExpression(attrProperty.initializer), `${filename}」中索引的attributes属性应该是数组字面量`);
const nameProperty = properties.find((ele2) => {
(0, assert_1.default)(ts.isPropertyAssignment(ele2));
return ele2.name.getText() === 'name';
});
(0, assert_1.default)(ts.isStringLiteral(nameProperty.initializer), '「${filename}」中索引的name属性应该是字符串字面量');
const nameText = nameProperty.initializer.text;
if (indexNameDict[nameText]) {
throw new Error(`${filename}」索引定义重名「${nameText}`);
}
(0, lodash_1.assign)(indexNameDict, {
[nameText]: true,
});
const configProperty = properties.find((ele2) => {
(0, assert_1.default)(ts.isPropertyAssignment(ele2), `${filename}」中索引的属性不为PropertyAssignment`);
return ele2.name.getText() === 'config';
});
if (configProperty) {
(0, assert_1.default)(ts.isObjectLiteralExpression(configProperty.initializer), `${filename}」中索引的config属性应该是对象字面量`);
const { properties: properties2 } = configProperty.initializer;
const typeProperty = properties2.find((ele2) => {
(0, assert_1.default)(ts.isPropertyAssignment(ele2), `${filename}」中索引的属性不为PropertyAssignment`);
return ele2.name.getText() === 'type';
});
if (typeProperty && typeProperty.initializer.text === 'fulltext') {
// 定义了全文索引
if (hasFulltextIndex) {
throw new Error(`${filename}」只能定义一个全文索引`);
}
hasFulltextIndex = true;
isFulltextIndex = true;
}
}
const { elements } = attrProperty.initializer;
// 每个属性都应该在schema中有值且对象类型是可索引值
elements.forEach((ele2) => {
(0, assert_1.default)(ts.isObjectLiteralExpression(ele2));
const { properties: properties2 } = ele2;
const nameProperty = properties2.find((ele3) => {
(0, assert_1.default)(ts.isPropertyAssignment(ele3));
return ele3.name.getText() === 'name';
});
const indexAttrName = nameProperty.initializer.text;
if (!Entity_1.initinctiveAttributes.includes(indexAttrName)) {
const schemaNode = schemaAttrs.find((ele3) => {
(0, assert_1.default)(ts.isPropertySignature(ele3));
return ele3.name.text === indexAttrName;
});
if (!schemaNode) {
throw new Error(`${filename}」中索引「${nameText}」的属性「${indexAttrName}」定义非法`);
}
const { type, name } = schemaNode;
const entity = moduleName;
const { [entity]: manyToOneSet } = ManyToOne;
if (ts.isTypeReferenceNode(type)) {
const { typeName } = type;
if (ts.isIdentifier(typeName)) {
const { text } = typeName;
const text2 = text === 'Schema' ? entity : text;
const manyToOneItem = manyToOneSet && manyToOneSet.find(([refEntity, attrName]) => refEntity === text2 && attrName === name.text);
if (!manyToOneItem) {
// 如果不是外键则不能是Text, File
if (isFulltextIndex) {
(0, assert_1.default)(['Text', 'String'].includes(text2), `${filename}」中全文索引「${nameText}」定义的属性「${indexAttrName}」类型非法只能是Text/String`);
}
else {
(0, assert_1.default)(!DataType_1.unIndexedTypes.includes(text2), `${filename}」中索引「${nameText}」的属性「${indexAttrName}」的类型为「${text2}」,不可索引`);
}
}
else {
(0, assert_1.default)(!isFulltextIndex, `${filename}」中全文索引「${nameText}」的属性「${indexAttrName}」类型非法只能为Text/String`);
// 在这里把外键加上Id这样storageSchema才能正常通过
// 这里的写法不太好未来TS版本高了可能会有问题。by Xc 20230131
Object.assign(nameProperty, {
initializer: factory.createStringLiteral(`${indexAttrName}Id`),
});
}
}
else {
(0, assert_1.default)(false); // 这是什么case不确定
}
}
else {
(0, assert_1.default)(!isFulltextIndex, `${filename}」中全文索引「${nameText}」的属性「${indexAttrName}」类型只能为Text/String`);
(0, assert_1.default)(ts.isUnionTypeNode(type) || ts.isLiteralTypeNode(type), `${entity}中索引「${nameText}」的属性${name.text}有定义非法`);
}
}
});
});
indexes = declaration;
};
const dealWithLocales = (declaration) => {
if (hasActionDef) {
// 检查每种locale定义中都应该有'action'域
checkLocaleExpressionPropertyExists(declaration, 'action', true, filename);
}
else {
checkLocaleExpressionPropertyExists(declaration, 'action', false, filename);
}
if (relations) {
// 检查每种locale定义中都应该有'r'域
checkLocaleExpressionPropertyExists(declaration, 'r', true, filename);
}
else {
checkLocaleExpressionPropertyExists(declaration, 'r', false, filename);
}
const allEnumStringAttrs = Object.keys(enumAttributes);
if (allEnumStringAttrs.length > 0) {
// 检查每种locale定义中都应该有'v'域
checkLocaleExpressionPropertyExists(declaration, 'v', true, filename);
}
else {
// 检查每种locale定义中都应该有'v'域
checkLocaleExpressionPropertyExists(declaration, 'v', false, filename);
}
localeDef = declaration;
};
const dealWithConfiguration = (declaration) => {
// assert(!hasActionDef, `${moduleName}中的Configuration定义在Action之后`);
const { properties } = declaration;
const atProperty = properties.find(ele => ts.isPropertyAssignment(ele) && ts.isIdentifier(ele.name) && ele.name.text === 'actionType');
const staticProperty = properties.find(ele => ts.isPropertyAssignment(ele) && ts.isIdentifier(ele.name) && ele.name.text === 'static');
if (atProperty) {
actionType = atProperty.initializer.text;
}
if (staticProperty) {
_static = true; // static如果有值只能为true
}
};
const dealWithStyleDesc = (declaration) => {
StyleAsts[moduleName] = declaration;
};
const dealWithEntityDesc = (declaration) => {
if (ts.isObjectLiteralExpression(declaration)) {
const { properties } = declaration;
const localesProperty = properties.find(ele => ts.isPropertyAssignment(ele) && ts.isIdentifier(ele.name) && ele.name.text === 'locales');
(0, assert_1.default)(ts.isPropertyAssignment(localesProperty), `${filename}」中entityDesc的locales应该是属性声明`);
dealWithLocales(localesProperty.initializer);
const indexesProperty = properties.find(ele => ts.isPropertyAssignment(ele) && ts.isIdentifier(ele.name) && ele.name.text === 'indexes');
if (indexesProperty) {
(0, assert_1.default)(ts.isPropertyAssignment(indexesProperty), `${filename}」中entityDesc的indexes应该是属性声明`);
dealWithIndexes(indexesProperty.initializer);
}
const configurationProperty = properties.find(ele => ts.isPropertyAssignment(ele) && ts.isIdentifier(ele.name) && ele.name.text === 'configuration');
if (configurationProperty) {
(0, assert_1.default)(ts.isPropertyAssignment(configurationProperty), `${filename}」中entityDesc的configuration应该是属性声明`);
dealWithConfiguration(configurationProperty.initializer);
}
const styleDescProperty = properties.find(ele => ts.isPropertyAssignment(ele) && ts.isIdentifier(ele.name) && ele.name.text === 'style');
if (styleDescProperty) {
(0, assert_1.default)(ts.isPropertyAssignment(styleDescProperty), `${filename}」中entityDesc的style应该是属性声明`);
dealWithStyleDesc(styleDescProperty.initializer);
}
}
else if (ts.isIdentifier(declaration)) {
const checker = program.getTypeChecker();
const symbol = checker.getSymbolAtLocation(declaration);
const original = checker.getAliasedSymbol(symbol);
/**
* 目前只研究出来怎么得到originSymbol但只能拿到其类型定义在d.ts中
* 拿不到数据定义(在js中)(original.declaration.initializer是undefined)
*/
(0, assert_1.default)(false, '用变量赋值给entityDesc暂时还解析不了');
}
};
declarations.forEach((declaration) => {
if (declaration.type && ts.isTypeReferenceNode(declaration.type) && ts.isIdentifier(declaration.type.typeName) && declaration.type.typeName.text === 'ActionDef') {
dealWithActionDef(declaration);
}
else if (declaration.type && (ts.isArrayTypeNode(declaration.type)
&& ts.isTypeReferenceNode(declaration.type.elementType)
&& ts.isIdentifier(declaration.type.elementType.typeName)
&& declaration.type.elementType.typeName.text === 'Index'
|| ts.isTypeReferenceNode(declaration.type)
&& ts.isIdentifier(declaration.type.typeName)
&& declaration.type.typeName.text === 'Array'
&& ts.isTypeReferenceNode(declaration.type.typeArguments[0])
&& ts.isIdentifier(declaration.type.typeArguments[0].typeName)
&& declaration.type.typeArguments[0].typeName.text === 'Index')) {
// 对索引Index的定义
console.log(`${filename}」直接定义indexes的写法已经过时请定义在entityDesc中`);
(0, assert_1.default)(ts.isArrayLiteralExpression(declaration.initializer), `${filename}」中索引定义应该是数组字面量`);
dealWithIndexes(declaration.initializer);
}
else if (declaration.type && ts.isTypeReferenceNode(declaration.type) && ts.isIdentifier(declaration.type.typeName) && declaration.type.typeName.text === 'LocaleDef') {
// locale定义
console.log(`${filename}」直接定义locales的写法已经过时请定义在entityDesc中`);
const { type, initializer } = declaration;
(0, assert_1.default)(ts.isObjectLiteralExpression(initializer), `${filename}」中locale定义应该是对象字面量`);
const { properties } = initializer;
(0, assert_1.default)(properties.length > 0, `${filename}至少需要有一种locale定义`);
const allEnumStringAttrs = Object.keys(enumAttributes);
const { typeArguments } = type;
(0, assert_1.default)(typeArguments &&
ts.isTypeReferenceNode(typeArguments[0])
&& ts.isIdentifier(typeArguments[0].typeName) && typeArguments[0].typeName.text === 'Schema', `${filename}中缺少locale定义或者locale类型定义的第一个参数不是Schema`);
if (hasActionDef) {
(0, assert_1.default)(ts.isTypeReferenceNode(typeArguments[1])
&& ts.isIdentifier(typeArguments[1].typeName) && typeArguments[1].typeName.text === 'Action', `${filename}中locale类型定义的第二个参数不是Action`);
}
else {
(0, assert_1.default)(ts.isLiteralTypeNode(typeArguments[1])
&& ts.isStringLiteral(typeArguments[1].literal), `${filename}中locale类型定义的第二个参数不是字符串`);
}
if (relations) {
(0, assert_1.default)(ts.isTypeReferenceNode(typeArguments[2])
&& ts.isIdentifier(typeArguments[2].typeName)
&& typeArguments[2].typeName.text === 'Relation', `${filename}中的locale类型定义的第三个参数不是Relation`);
}
else {
(0, assert_1.default)(ts.isLiteralTypeNode(typeArguments[2])
&& ts.isStringLiteral(typeArguments[2].literal), `${filename}中locale类型定义的第三个参数不是空字符串`);
}
if (allEnumStringAttrs.length > 0) {
(0, assert_1.default)(ts.isTypeLiteralNode(typeArguments[3]), `${filename}中的locale类型定义的第四个参数不是{}`);
checkLocaleEnumAttrs(typeArguments[3], allEnumStringAttrs, filename);
}
else {
(0, assert_1.default)(ts.isTypeLiteralNode(typeArguments[3]), `${filename}中的locale类型定义的第四个参数不是{}`);
(0, assert_1.default)(typeArguments[3].members.length == 0, `${filename}中locale类型定义的第四个参数不应存在相应的v定义`);
}
dealWithLocales(initializer);
}
else if (declaration.type && ts.isTypeReferenceNode(declaration.type) && ts.isIdentifier(declaration.type.typeName) && declaration.type.typeName.text === 'Configuration') {
console.log(`${filename}」直接定义configuration的写法已经过时请定义在entityDesc中`);
(0, assert_1.default)(ts.isObjectLiteralExpression(declaration.initializer), `${filename}」中configuration定义应该是对象字面量`);
dealWithConfiguration(declaration.initializer);
}
else if (declaration.type && ts.isTypeReferenceNode(declaration.type) && ts.isIdentifier(declaration.type.typeName) && declaration.type.typeName.text === 'EntityDesc') {
const { initializer } = declaration;
(0, assert_1.default)(initializer, `${filename}」中entityDesc的定义不应该为空`);
dealWithEntityDesc(initializer);
}
else {
throw new Error(`${moduleName}:不能理解的定义内容${declaration.name.text}`);
}
});
}
});
// 要等configuration确定了actionType后再处理
if (hasActionDef) {
const actionDefNodes = [
factory.createTypeReferenceNode(OriginActionDict[actionType], undefined),
factory.createTypeReferenceNode('ParticularAction', undefined)
];
if (moduleName === 'User') {
actionDefNodes.push(factory.createTypeReferenceNode('RelationAction', undefined));
}
if (process.env.COMPLING_AS_LIB) {
actionDefNodes.push(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword));
}
pushStatementIntoActionAst(moduleName, factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("Action"), undefined, factory.createUnionTypeNode(actionDefNodes)), sourceFile);
}
if (!hasActionDef && hasActionOrStateDef) {
throw new Error(`${filename}中有Action或State定义但没有定义完整的Action类型`);
}
if (hasActionDef && actionType !== 'crud') {
throw new Error(`${filename}中有Action定义但却定义了actionType不是crud`);
}
(0, assert_1.default)(schemaAttrs.length > 0, `对象${moduleName}没有任何属性定义`);
const schema = {
schemaAttrs,
sourceFile,
toModi,
actionType,
static: _static,
relations,
enumAttributes,
importAttrFrom,
extendsFrom,
};
if (hasFulltextIndex) {
(0, lodash_1.assign)(schema, {
fulltextIndex: true,
});
}
if (indexes) {
(0, lodash_1.assign)(schema, {
indexes,
});
}
if (!localeDef) {
throw new Error(`${filename}中缺少了locale定义`);
}
else {
(0, lodash_1.assign)(schema, {
locale: localeDef,
});
}
/* if (hasRelationDef) {
if(!relationHierarchy && !reverseCascadeRelationHierarchy){
console.warn(`${filename}中定义了Relation,但并没有relationHierarchy或reverseCascadeRelationHierarchy的定义请注意自主编写权限分配的checker`);
}
if (relationHierarchy) {
assign(schema, {
relationHierarchy,
});
}
if (reverseCascadeRelationHierarchy) {
assign(schema, {
reverseCascadeRelationHierarchy,
});
}
}
else {
assert(!relationHierarchy, `${filename}中具有relationHierarchy定义但没有Relation定义`);
assert(!reverseCascadeRelationHierarchy, `${filename}中具有reverseCascadeRelationHierarchy定义但没有Relation定义`)
} */
if (toLog) {
(0, lodash_1.assign)(schema, {
toLog,
});
}
(0, lodash_1.assign)(Schema, {
[moduleName]: schema,
});
}
/**
* 生成Schema
* @param statements
* @param schemaAttrs
* @param entity
*/
function constructSchema(statements, entity) {
const { schemaAttrs } = Schema[entity];
const members = [];
const members2 = [];
const { [entity]: manyToOneSet } = ManyToOne;
const { [entity]: oneToManySet } = OneToMany;
const referenceEntities = [];
for (const attr of schemaAttrs) {
const { type, name, questionToken } = attr;
const attrName = name.text;
if (ts.isTypeReferenceNode(type)) {
const { typeName } = type;
if (ts.isIdentifier(typeName)) {
const { text } = typeName;
const text2 = text === 'Schema' ? entity : text;
const manyToOneItem = manyToOneSet && manyToOneSet.find(([refEntity, attrName2]) => refEntity === text2 && attrName2 === attrName);
if (manyToOneItem) {
referenceEntities.push(text2);
members2.push(factory.createPropertySignature(undefined, name, questionToken, questionToken ? factory.createUnionTypeNode([
factory.createTypeReferenceNode(createForeignRef(entity, text2, 'Schema')),
factory.createLiteralTypeNode(factory.createNull())
]) : factory.createTypeReferenceNode(createForeignRef(entity, text2, 'Schema'))));
const foreignKey = `${attrName}Id`;
members.push(factory.createPropertySignature(undefined, factory.createIdentifier(foreignKey), questionToken, questionToken ? factory.createUnionTypeNode([
factory.createTypeReferenceNode(factory.createIdentifier('ForeignKey'), [
factory.createLiteralTypeNode(factory.createStringLiteral((0, string_1.firstLetterLowerCase)(text2)))
]),
factory.createLiteralTypeNode(factory.createNull())
]) : factory.createTypeReferenceNode(factory.createIdentifier('ForeignKey'), [
factory.createLiteralTypeNode(factory.createStringLiteral((0, string_1.firstLetterLowerCase)(text2)))
])));
}
else {
// assert(types.includes(text), `${entity}中的属性${name.toString()}有非法的属性类型定义`);
// 处理entity这种特殊情况
if (ReversePointerRelations[entity] && attrName === 'entity') {
const entityUnionTypeNode = ReversePointerRelations[entity].map(ele => factory.createLiteralTypeNode(factory.createStringLiteral((0, string_1.firstLetterLowerCase)(ele))));
if (process.env.COMPLING_AS_LIB) {
// 如果是建立 base-domain还要容纳可能的其它对象引用
entityUnionTypeNode.push(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword));
}
members.push(factory.createPropertySignature(undefined, name, questionToken, questionToken ? factory.createUnionTypeNode([
factory.createUnionTypeNode(entityUnionTypeNode),
factory.createLiteralTypeNode(factory.createNull())
]) : factory.createUnionTypeNode(entityUnionTypeNode)));
}
else {
members.push(factory.createPropertySignature(undefined, name, questionToken, questionToken ? factory.createUnionTypeNode([
type,
factory.createLiteralTypeNode(factory.createNull())
]) : type));
}
}
}
else {
(0, assert_1.default)(false); // 这是什么case不确定
members.push(attr);
}
}
else {
// assert(ts.isUnionTypeNode(type!) || ts.isLiteralTypeNode(type!), `${entity}有非法的属性类型定义${(<ts.Identifier>name).text}`);
members.push(factory.createPropertySignature(undefined, name, questionToken, questionToken ? factory.createUnionTypeNode([
type,
factory.createLiteralTypeNode(factory.createNull())
]) : type));
}
}
// 处理reverserPointer
const reverseOnes = ReversePointerRelations[entity];
if (reverseOnes) {
reverseOnes.forEach((one) => {
referenceEntities.push(one);
members2.push(factory.createPropertySignature(undefined, (0, string_1.firstLetterLowerCase)(one), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(createForeignRef(entity, one, 'Schema'))));
});
}
const foreignKeySet = {};
if (oneToManySet) {
for (const oneToManyItem of oneToManySet) {
const [entityName, foreignKey] = oneToManyItem;
if (referenceEntities.indexOf(entityName) === -1) {
referenceEntities.push(entityName);
}
if (foreignKeySet.hasOwnProperty(entityName)) {
foreignKeySet[entityName].push(foreignKey);
}
else {
foreignKeySet[entityName] = [foreignKey];
}
}
for (const entityName in foreignKeySet) {
const entityNameLc = (0, string_1.firstLetterLowerCase)(entityName);
foreignKeySet[entityName].forEach((foreignKey) => {
const identifier = `${entityNameLc}$${foreignKey}`;
members2.push(factory.createPropertySignature(undefined, identifier, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(factory.createIdentifier("Array"), [factory.createTypeReferenceNode(createForeignRef(entity, entityName, 'Schema'), undefined)])));
});
}
}
(0, lodash_1.uniq)(referenceEntities).forEach((ele) => {
if (ele !== entity) {
statements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamespaceImport(factory.createIdentifier(ele))), factory.createStringLiteral(`../${ele}/Schema`)));
}
});
// 在这里把需要直接拷贝过来的语句写入
if (SchemaAsts[entity]) {
statements.push(...SchemaAsts[entity].statements);
}
statements.push(factory.createTypeAliasDeclaration([
factory.createModifier(ts.SyntaxKind.ExportKeyword)
], factory.createIdentifier('OpSchema'), undefined, factory.createIntersectionTypeNode([
factory.createTypeReferenceNode('EntityShape'),
factory.createTypeLiteralNode(members)
])), factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("OpAttr"), undefined, factory.createTypeOperatorNode(ts.SyntaxKind.KeyOfKeyword, factory.createTypeReferenceNode(factory.createIdentifier("OpSchema"), undefined))));
const otmAggrMappedNodes = [];
for (const entityName in foreignKeySet) {
const entityNameLc = (0, string_1.firstLetterLowerCase)(entityName);
foreignKeySet[entityName].forEach((foreignKey) => {
const typeAliasIdentifier = `${entityName}$${foreignKey}Aggr`;
const typeStringLiterals = [`${entityNameLc}$${foreignKey}$$aggr`];
let i = 0;
while (i < 10) {
typeStringLiterals.push(`${entityNameLc}$${foreignKey}$$${i}$$aggr`);
i++;
}
statements.push(factory.createTypeAliasDeclaration(undefined, factory.createIdentifier(typeAliasIdentifier), undefined, factory.createUnionTypeNode(typeStringLiterals.map(literal => factory.createLiteralTypeNode(factory.createStringLiteral(literal))))));
otmAggrMappedNodes.push(factory.createMappedTypeNode(undefined, factory.createTypeParameterDeclaration(undefined, factory.createIdentifier("A"), factory.createTypeReferenceNode(factory.createIdentifier(typeAliasIdentifier), undefined), undefined), undefined, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(factory.createIdentifier("AggregationResult"), [factory.createTypeReferenceNode(createForeignRef(entity, entityName, 'Schema'), undefined)]), undefined));
});
}
statements.push(factory.createTypeAliasDeclaration([
factory.createModifier(ts.SyntaxKind.ExportKeyword)
], factory.createIdentifier('Schema'), undefined, factory.createIntersectionTypeNode([
factory.createTypeReferenceNode('OpSchema'),
factory.createTypeLiteralNode(members2),
factory.createMappedTypeNode(undefined, factory.createTypeParameterDeclaration(undefined, factory.createIdentifier("A"), factory.createTypeReferenceNode(factory.createIdentifier("ExpressionKey"), undefined), undefined), undefined, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), undefined),
...otmAggrMappedNodes,
])));
}
function _constructOpSchema(statements, entity) {
const { schemaAttrs } = Schema[entity];
const members = [];
const members2 = [];
const { [entity]: manyToOneSet } = ManyToOne;
const { [entity]: oneToManySet } = OneToMany;
const referenceEntities = [];
for (const attr of schemaAttrs) {
const { type, name, questionToken } = attr;
const attrName = name.text;
if (ts.isTypeReferenceNode(type)) {
const { typeName } = type;
if (ts.isIdentifier(typeName)) {
const { text } = typeName;
const text2 = text === 'Schema' ? entity : text;
const manyToOneItem = manyToOneSet && manyToOneSet.find(([refEntity, attrName2]) => refEntity === text2 && attrName2 === attrName);
if (manyToOneItem) {
referenceEntities.push(text2);
members2.push(factory.createPropertySignature(undefined, name, questionToken, questionToken ? factory.createUnionTypeNode([
factory.createTypeReferenceNode(createForeignRef(entity, text2, 'Schema')),
factory.createLiteralTypeNode(factory.createNull())
]) : factory.createTypeReferenceNode(createForeignRef(entity, text2, 'Schema'))));
const foreignKey = `${attrName}Id`;
members.push(factory.createPropertySignature(undefined, factory.createIdentifier(foreignKey), questionToken, questionToken ? factory.createUnionTypeNode([
factory.createTypeReferenceNode(factory.createIdentifier('ForeignKey'), [
factory.createLiteralTypeNode(factory.createStringLiteral((0, string_1.firstLetterLowerCase)(text2)))
]),
factory.createLiteralTypeNode(factory.createNull())
]) : factory.createTypeReferenceNode(factory.createIdentifier('ForeignKey'), [
factory.createLiteralTypeNode(factory.createStringLiteral((0, string_1.firstLetterLowerCase)(text2)))
])));
}
else {
// assert(types.includes(text), `${entity}中的属性${name.toString()}有非法的属性类型定义`);
// 处理entity这种特殊情况
if (ReversePointerRelations[entity] && attrName === 'entity') {
const entityUnionTypeNode = ReversePointerRelations[entity].map(ele => factory.createLiteralTypeNode(factory.createStringLiteral((0, string_1.firstLetterLowerCase)(ele))));
if (process.env.COMPLING_AS_LIB) {
// 如果是建立 base-domain还要容纳可能的其它对象引用
entityUnionTypeNode.push(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword));
}
members.push(factory.createPropertySignature(undefined, name, questionToken, questionToken ? factory.createUnionTypeNode([
factory.createUnionTypeNode(entityUnionTypeNode),
factory.createLiteralTypeNode(factory.createNull())
]) : factory.createUnionTypeNode(entityUnionTypeNode)));
}
else {
members.push(factory.createPropertySignature(undefined, name, questionToken, questionToken ? factory.createUnionTypeNode([
type,
factory.createLiteralTypeNode(factory.createNull())
]) : type));
}
}
}
else {
(0, assert_1.default)(false); // 这是什么case不确定
members.push(attr);
}
}
else {
// assert(ts.isUnionTypeNode(type!) || ts.isLiteralTypeNode(type!), `${entity}有非法的属性类型定义${(<ts.Identifier>name).text}`);
members.push(factory.createPropertySignature(undefined, name, questionToken, questionToken ? factory.createUnionTypeNode([
type,
factory.createLiteralTypeNode(factory.createNull())
]) : type));
}
}
// 在这里把需要直接拷贝过来的语句写入
if (SchemaAsts[entity]) {
statements.push(...SchemaAsts[entity].statements);
}
statements.push(factory.createTypeAliasDeclaration([
factory.createModifier(ts.SyntaxKind.ExportKeyword)
], factory.createIdentifier('OpSchema'), undefined, factory.createIntersectionTypeNode([
factory.createTypeReferenceNode('EntityShape'),
factory.createTypeLiteralNode(members),
factory.createMappedTypeNode(undefined, factory.createTypeParameterDeclaration(undefined, factory.createIdentifier("A"), factory.createTypeReferenceNode(factory.createIdentifier("ExpressionKey"), undefined), undefined), undefined, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword), undefined),
])), factory.createTypeAliasDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("OpAttr"), undefined, factory.createTypeOperatorNode(ts.SyntaxKind.KeyOfKeyword, factory.createTypeReferenceNode(factory.createIdentifier("OpSchema"), undefined))));
}
/**
* 生成Query
* @param statements
* @param schemaAttrs
* @param entity
*/
function constructFilter(statements, entity) {
const { schemaAttrs, fulltextIndex, enumAttributes } = Schema[entity];
const members = [
// id: Q_StringValue
factory.createPropertySignature(undefined, factory.createIdentifier('id'), undefined, factory.createUnionTypeNode([
factory.createTypeReferenceNode(factory.createIdentifier('Q_StringValue')),
/* factory.createTypeReferenceNode(
factory.createQualifiedName(
factory.createIdentifier("SubQuery"),
factory.createIdentifier(`${entity}IdSubQuery`)
)
) */
])),
// $$createAt$$: Q_DateValue
factory.createPropertySignature(undefined, factory.createIdentifier('$$createAt$$'), undefined, factory.createTypeReferenceNode(factory.createIdentifier('Q_DateValue'))),
// $$seq$$: Q_StringValue
factory.createPropertySignature(undefined, factory.createIdentifier('$$seq$$'), undefined, factory.createTypeReferenceNode(factory.createIdentifier('Q_NumberValue'))),
// $$updateAt$$: Q_DateValue
factory.createPropertySignature(undefined, factory.createIdentifier('$$updateAt$$'), undefined, factory.createTypeReferenceNode(factory.createIdentifier('Q_DateValue')))
];
const { [entity]: manyToOneSet } = ManyToOne;
const entityUnionTypeNodes = ReversePointerRelations[entity] && ReversePointerRelations[entity].map(ele => factory.createLiteralTypeNode(factory.createStringLiteral((0, string_1.firstLetterLowerCase)(ele))));
if (process.env.COMPLING_AS_LIB) {
entityUnionTypeNodes && entityUnionTypeNodes.push(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword));
}
for (const attr of schemaAttrs) {
const { type, name } = attr;
const attrName = name.text;
if (ts.isTypeReferenceNode(type)) {
const { typeName } = type;
if (ts.isIdentifier(typeName)) {
const { text } = typeName;
let type2;
switch (text) {
case 'String':
case 'Text':
case 'Image':
case 'File': {
if (ReversePointerRelations[entity] && attrName === 'entity') {
type2 = factory.createTypeReferenceNode(factory.createIdentifier('Q_EnumValue'), [
factory.createUnionTypeNode(entityUnionTypeNodes)
]);
}
else {
type2 = factory.createTypeReferenceNode(factory.createIdentifier('Q_StringValue'));
}
break;
}
case 'Int':
case 'Uint':
case 'Float':
case 'Double':
case 'Price':
case 'Decimal': {
type2 = factory.createTypeReferenceNode(factory.createIdentifier('Q_NumberValue'));
break;
}
case 'Boolean': {
type2 = factory.createTypeReferenceNode(factory.createIdentifier('Q_BooleanValue'));
break;
}
case 'Datetime': {
type2 = factory.createTypeReferenceNode(factory.createIdentifier('Q_DateValue'));
break;
}
case 'SingleGeo':
case 'Geo': {
// geo类型暂时只支持通过expr查询
break;
}
case 'Object': {
type2 = factory.createTypeReferenceNode(factory.createIdentifier('Object'));
break;
}
default: {
const text2 = text === 'Schema' ? entity : text;
const manyToOneItem = manyToOneSet && manyToOneSet.find(([refEntity]) => refEntity === text2);
if (manyToOneItem) {
// 外键可能落到相应的子查询中
members.push(factory.createPropertySignature(undefined, `${name.text}Id`, undefined, factory.createTypeReferenceNode(factory.createIdentifier('Q_StringValue'))));
type2 = factory.createTypeReferenceNode(createForeignRef(entity, text2, 'Filter'));
}
else if (enumAttributes && enumAttributes[attrName] || ts.isUnionTypeNode(type)) {
// 这里应该都是引用某个UnionType类型的定义了如何判断
// const words = getStringTextFromUnionStringLiterals();
type2 = factory.createTypeReferenceNode(factory.createIdentifier('Q_EnumValue'), [
factory.createTypeReferenceNode(factory.createIdentifier(text), undefined)
]);
}
else {
// 非枚举类型的非结构化属性用JSONFilter来形式化
type2 = factory.createTypeReferenceNode(factory.createIdentifier('JsonFilter'), [
factory.createTypeReferenceNode(factory.createIdentifier(text), undefined)
]);
}
}
}
if (type2) {
members.push(factory.createPropertySignature(undefined, name, undefined, type2));
}
}
}
else if (ts.isUnionTypeNode(type) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type)) {
members.push(factory.createPropertySignature(undefined, name, undefined, factory.createTypeReferenceNode(factory.createIdentifier('Q_EnumValue'), [
type
])));
}
else {
// 此时应当是引用本地定义的shape
(0, assert_1.default)(type, `${entity}中的属性${name.toString()}有非法的属性类型定义`);
members.push(factory.createPropertySignature(undefined, name, undefined, factory.createTypeReferenceNode(factory.createIdentifier('JsonFilter'), [
type
])));
}
}
// type AttrFilter = {};
if (ReversePointerRelations[entity]) {
// 有反向指针将反向指针关联的对象的Filter也注入
ReversePointerRelations[entity].forEach(ele => members.push(factory.createPropertySignature(undefined, (0, string_1.firstLetterLowerCase)(ele), undefined, factory.createTypeReferenceNode(createForeignRef(entity, ele, 'Filter')))));
}
// 一对多的生成子查询
const { [entity]: oneToManySet } = OneToMany;
if (oneToManySet) {
const foreignKeySet = {};
for (const oneToManyItem of oneToManySet) {
const [entityName, foreignKey] = oneToManyItem;
if (foreignKeySet.hasOwnProperty(entityName)) {
foreignKeySet[entityName].push(foreignKey);
}
else {
foreignKeySet[entityName] = [foreignKey];
}
}
for (const entityName in foreignKeySet) {
const entityNameLc = (0, string_1.firstLetterLowerCase)(entityName);
foreignKeySet[entityName].forEach((foreignKey) => {
const identifier = `${entityNameLc}$${foreignKey}`;
members.push(factory.createPropertySignature(undefined, identifier, undefined, factory.createIntersectionTypeNode([
factory.createTypeReferenceNode(createForeignRef(entity, entityName, 'Filter'), undefined),
factory.createTypeReferenceNode('SubQueryPredicateMetadata')
])));
});
}
}
statements.push(factory.createTypeAliasDeclaration(undefined, factory.createIdentifier('AttrFilter'), undefined, factory.createTypeLiteralNode(members)));
/**
*
export type Filter = AttrFilter | Partial<ExprOp<OpSchema> | {
[F in Q_LogicKey]: Filter[];
} | {
[F in Q_FullTextKey]: Q_FullTextValue;
}>;
*/
const types = [
factory.createTypeReferenceNode(factory.createIdentifier("AttrFilter")),
factory.createTypeReferenceNode(factory.createIdentifier("ExprOp"), [
process.env.COMPLING_AS_LIB ?
factory.createUnionTypeNode([
factory.createTypeReferenceNode(factory.createIdentifier('OpAttr')),
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
]) :
factory.createTypeReferenceNode(factory.createIdentifier('OpAttr'))
]),
];
// 如果还有其它类型的查询如全文则加在types数组中
if (fulltextIndex) {
types.push(factory.createTypeReferenceNode('FulltextFilter'));
}
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("Filter"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("MakeFilter"), [factory.createIntersectionTypeNode(types)])));
}
function _constructOpFilter(statements, entity) {
const { schemaAttrs, fulltextIndex, enumAttributes } = Schema[entity];
const members = [
// id: Q_StringValue
factory.createPropertySignature(undefined, factory.createIdentifier('id'), undefined, factory.createUnionTypeNode([
factory.createTypeReferenceNode(factory.createIdentifier('Q_StringValue')),
/* factory.createTypeReferenceNode(
factory.createQualifiedName(
factory.createIdentifier("SubQuery"),
factory.createIdentifier(`${entity}IdSubQuery`)
)
) */
])),
// $$createAt$$: Q_DateValue
factory.createPropertySignature(undefined, factory.createIdentifier('$$createAt$$'), undefined, factory.createTypeReferenceNode(factory.createIdentifier('Q_DateValue'))),
// $$seq$$: Q_StringValue
factory.createPropertySignature(undefined, factory.createIdentifier('$$seq$$'), undefined, factory.createTypeReferenceNode(factory.createIdentifier('Q_NumberValue'))),
// $$updateAt$$: Q_DateValue
factory.createPropertySignature(undefined, factory.createIdentifier('$$updateAt$$'), undefined, factory.createTypeReferenceNode(factory.createIdentifier('Q_DateValue')))
];
const entityUnionTypeNodes = ReversePointerRelations[entity] && ReversePointerRelations[entity].map(ele => factory.createLiteralTypeNode(factory.createStringLiteral((0, string_1.firstLetterLowerCase)(ele))));
if (process.env.COMPLING_AS_LIB) {
entityUnionTypeNodes && entityUnionTypeNodes.push(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword));
}
const { [entity]: manyToOneSet } = ManyToOne;
for (const attr of schemaAttrs) {
const { type, name } = attr;
const attrName = name.text;
if (ts.isTypeReferenceNode(type)) {
const { typeName } = type;
if (ts.isIdentifier(typeName)) {
const { text } = typeName;
let type2;
switch (text) {
case 'String':
case 'Text':
case 'Image':
case 'File': {
if (ReversePointerRelations[entity] && attrName === 'entity') {
type2 = factory.createTypeReferenceNode(factory.createIdentifier('Q_EnumValue'), [
factory.createUnionTypeNode(entityUnionTypeNodes)
]);
}
else {
type2 = factory.createTypeReferenceNode(factory.createIdentifier('Q_StringValue'));
}
break;
}
case 'Int':
case 'Uint':
case 'Float':
case 'Double':
case 'Price':
case 'Decimal': {
type2 = factory.createTypeReferenceNode(factory.createIdentifier('Q_NumberValue'));
break;
}
case 'Boolean': {
type2 = factory.createTypeReferenceNode(factory.createIdentifier('Q_BooleanValue'));
break;
}
case 'Datetime': {
type2 = factory.createTypeReferenceNode(factory.createIdentifier('Q_DateValue'));
break;
}
case 'SingleGeo':
case 'Geo': {
// geo类型暂时只支持通过expr查询
break;
}
case 'Object': {
type2 = factory.createTypeReferenceNode(factory.createIdentifier('Object'));
break;
}
default: {
const text2 = text === 'Schema' ? entity : text;
const manyToOneItem = manyToOneSet && manyToOneSet.find(([refEntity]) => refEntity === text2);
if (manyToOneItem) {
// 外键可能落到相应的子查询中
members.push(factory.createPropertySignature(undefined, `${name.text}Id`, undefined, factory.createTypeReferenceNode(factory.createIdentifier('Q_StringValue'))));
}
else if (enumAttributes && enumAttributes[attrName] || ts.isUnionTypeNode(type)) {
// 这里应该都是引用某个UnionType类型的定义了如何判断
// const words = getStringTextFromUnionStringLiterals();
type2 = factory.createTypeReferenceNode(factory.createIdentifier('Q_EnumValue'), [
factory.createTypeReferenceNode(factory.createIdentifier(text), undefined)
]);
}
else {
// 非枚举类型的非结构化属性用JSONFilter来形式化
type2 = factory.createTypeReferenceNode(factory.createIdentifier('JsonFilter'), [
factory.createTypeReferenceNode(factory.createIdentifier(text), undefined)
]);
}
}
}
if (type2) {
members.push(factory.createPropertySignature(undefined, name, undefined, type2));
}
}
}
else if (ts.isUnionTypeNode(type) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type)) {
members.push(factory.createPropertySignature(undefined, name, undefined, factory.createTypeReferenceNode(factory.createIdentifier('Q_EnumValue'), [
type
])));
}
else {
// 此时应当是引用本地定义的shape
(0, assert_1.default)(type, `${entity}中的属性${name.toString()}有非法的属性类型定义`);
members.push(factory.createPropertySignature(undefined, name, undefined, factory.createTypeReferenceNode(factory.createIdentifier('JsonFilter'), [
type
])));
}
}
const types = [
factory.createTypeLiteralNode(members),
factory.createTypeReferenceNode(factory.createIdentifier("ExprOp"), [
process.env.COMPLING_AS_LIB ?
factory.createUnionTypeNode([
factory.createTypeReferenceNode(factory.createIdentifier('OpAttr')),
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
]) :
factory.createTypeReferenceNode(factory.createIdentifier('OpAttr'))
]),
];
// 如果还有其它类型的查询如全文则加在types数组中
if (fulltextIndex) {
types.push(factory.createTypeReferenceNode('FulltextFilter'));
}
statements.push(factory.createTypeAliasDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("OpFilter"), undefined, factory.createIntersectionTypeNode(types)));
}
/**
* 构造Projection和OneAttrProjection
* @param statements
* @param entity
*/
function constructProjection(statements, entity) {
const { schemaAttrs, enumAttributes } = Schema[entity];
const properties = [
['id', false],
['$$createAt$$', false],
['$$updateAt$$', false],
['$$seq$$', false],
];
const foreignKeyProperties = {
[entity]: [''],
};
const { [entity]: manyToOneSet } = ManyToOne;
for (const attr of schemaAttrs) {
const { type, name } = attr;
const attrName = name.text;
if (ts.isTypeReferenceNode(type)) {
const { typeName } = type;
if (ts.isIdentifier(typeName)) {
const { text } = typeName;
switch (text) {
case 'String':
case 'Text':
case 'Int':
case 'Uint':
case 'Float':
case 'Double':
case 'Boolean':
case 'Datetime':
case 'Image':
case 'File':
case 'SingleGeo':
case 'Geo':
case 'Price':
case 'Decimal': {
properties.push([name, false]);
break;
}
case 'Object': {
properties.push([name, false, factory.createUnionTypeNode([
factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
factory.createTypeReferenceNode(factory.createIdentifier("Object"), undefined)
])]);
break;
}
default: {
const text2 = text === 'Schema' ? entity : text;
const manyToOneItem = manyToOneSet && manyToOneSet.find(([refEntity]) => refEntity === text2);
if (manyToOneItem) {
// 外键投影
properties.push([`${attrName}Id`, false, undefined], [name, false, factory.createTypeReferenceNode(createForeignRef(entity, text2, 'Projection')) /* , factory.createTypeReferenceNode(
createForeignRef(entity, text2, 'ExportProjection')
) */
]);
if (foreignKeyProperties.hasOwnProperty(text2)) {
foreignKeyProperties[text2].push(attrName);
}
else {
(0, lodash_1.assign)(foreignKeyProperties, {
[text2]: [attrName],
});
}
}
else {
if (!enumAttributes || !enumAttributes[attrName]) {
// 引用的非enum类型shape
properties.push([name, false, factory.createUnionTypeNode([
factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
factory.createTypeReferenceNode(factory.createIdentifier("JsonProjection"), [type])
])]);
}
else {
// 引用的enum类型shape
properties.push([name, false, undefined]);
}
}
}
}
}
else {
(0, assert_1.default)(false);
}
}
else {
// 增加了本身object的shape定义
// assert(ts.isUnionTypeNode(type!) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type!));
if (enumAttributes && enumAttributes[attrName] || ts.isUnionTypeNode(type) && ts.isLiteralTypeNode(type.types[0])) {
properties.push([name, false, undefined]);
}
else {
// 如果是非枚举类型的其它对象的union定义加上JsonProjection
properties.push([name, false, factory.createUnionTypeNode([
factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
factory.createTypeReferenceNode(factory.createIdentifier("JsonProjection"), [type])
])]);
}
}
}
if (ReversePointerRelations[entity]) {
ReversePointerRelations[entity].forEach((one) => {
const text2 = one === 'Schema' ? entity : one;
properties.push([(0, string_1.firstLetterLowerCase)(one), false, factory.createTypeReferenceNode(createForeignRef(entity, one, 'Projection')) /* , factory.createTypeReferenceNode(
createForeignRef(entity, one, 'ExportProjection')
) */
]);
if (foreignKeyProperties.hasOwnProperty(one)) {
foreignKeyProperties[text2].push('entity');
}
else {
(0, lodash_1.assign)(foreignKeyProperties, {
[text2]: ['entity'],
});
}
});
}
// 一对多的projection
const otmAggrMappedNodes = [];
const { [entity]: oneToManySet } = OneToMany;
if (oneToManySet) {
const foreignKeySet = {};
for (const oneToManyItem of oneToManySet) {
const [entityName, foreignKey] = oneToManyItem;
if (foreignKeySet.hasOwnProperty(entityName)) {
foreignKeySet[entityName].push(foreignKey);
}
else {
foreignKeySet[entityName] = [foreignKey];
}
}
for (const entityName in foreignKeySet) {
const entityNameLc = (0, string_1.firstLetterLowerCase)(entityName);
foreignKeySet[entityName].forEach((foreignKey) => {
const identifier = `${entityNameLc}$${foreignKey}`;
const typeAliasIdentifier = `${entityName}$${foreignKey}Aggr`;
properties.push([identifier, false,
factory.createIntersectionTypeNode([
factory.createTypeReferenceNode(createForeignRef(entity, entityName, 'Selection'), undefined),
factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier("$entity"), undefined, factory.createLiteralTypeNode(factory.createStringLiteral((0, string_1.firstLetterLowerCase)(entityName))))
])
]) /* ,
factory.createIntersectionTypeNode([
factory.createTypeReferenceNode(
createForeignRef(entity, entityName, 'Exportation'),
undefined
),
factory.createTypeLiteralNode([
factory.createPropertySignature(
undefined,
factory.createIdentifier("$entity"),
undefined,
factory.createLiteralTypeNode(factory.createStringLiteral(firstLetterLowerCase(entityName)))
)
])
]) */
]);
otmAggrMappedNodes.push(factory.createMappedTypeNode(undefined, factory.createTypeParameterDeclaration(undefined, factory.createIdentifier("A"), factory.createTypeReferenceNode(factory.createIdentifier(typeAliasIdentifier), undefined), undefined), undefined, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createIntersectionTypeNode([
factory.createTypeReferenceNode(createForeignRef(entity, entityName, 'Aggregation'), undefined),
factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier("$entity"), undefined, factory.createLiteralTypeNode(factory.createStringLiteral((0, string_1.firstLetterLowerCase)(entityName))))
])
]), undefined));
});
}
}
const exprNode = factory.createTypeReferenceNode(factory.createIdentifier("Partial"), [
factory.createTypeReferenceNode(factory.createIdentifier("ExprOp"), [
process.env.COMPLING_AS_LIB ?
factory.createUnionTypeNode([
factory.createTypeReferenceNode(factory.createIdentifier('OpAttr')),
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
]) :
factory.createTypeReferenceNode(factory.createIdentifier('OpAttr'))
])
]);
const MetaPropertySignatures = [
factory.createPropertySignature(undefined, factory.createStringLiteral("#id"), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode('NodeId'))
];
if (process.env.COMPLING_AS_LIB) {
MetaPropertySignatures.push(factory.createIndexSignature(undefined, [factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier("k"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), undefined)], factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)));
}
// Projection正常查询的投影
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("Projection"), undefined, factory.createIntersectionTypeNode([
factory.createTypeLiteralNode(MetaPropertySignatures.concat(properties.map(([n, q, v]) => {
return factory.createPropertySignature(undefined, n, q ? undefined : factory.createToken(ts.SyntaxKind.QuestionToken), v || factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword));
}))),
exprNode,
...otmAggrMappedNodes,
])));
// ExportProjection下载查询的投影
// 已经废弃。By Xc 2023.01.08
/* statements.push(
factory.createTypeAliasDeclaration(
undefined,
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
factory.createIdentifier("ExportProjection"),
undefined,
factory.createIntersectionTypeNode([
factory.createTypeLiteralNode(
MetaPropertySignaturs.concat(
properties.map(
([n, q, v, v2]) => {
return factory.createPropertySignature(
undefined,
n,
factory.createToken(ts.SyntaxKind.QuestionToken),
v2 || factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
)
}
)
)
),
exprNode,
])
)
); */
// ${Entity}Projection外键查询的专用投影
for (const foreignKey in foreignKeyProperties) {
const identifier = `${foreignKey}IdProjection`;
statements.push(factory.createTypeAliasDeclaration(undefined, factory.createIdentifier(identifier), undefined, factory.createTypeReferenceNode(factory.createIdentifier("OneOf"), [
factory.createTypeLiteralNode(foreignKeyProperties[foreignKey].map((attr) => factory.createPropertySignature(undefined, attr ? factory.createIdentifier(`${attr}Id`) : 'id', undefined, factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword))))
])));
}
}
function _constructOpProjection(statements, entity) {
const { schemaAttrs, enumAttributes } = Schema[entity];
const properties = [
['id', false],
['$$createAt$$', false],
['$$updateAt$$', false],
['$$seq$$', false],
];
const { [entity]: manyToOneSet } = ManyToOne;
for (const attr of schemaAttrs) {
const { type, name } = attr;
const attrName = name.text;
if (ts.isTypeReferenceNode(type)) {
const { typeName } = type;
if (ts.isIdentifier(typeName)) {
const { text } = typeName;
switch (text) {
case 'String':
case 'Text':
case 'Int':
case 'Uint':
case 'Float':
case 'Double':
case 'Boolean':
case 'Datetime':
case 'Image':
case 'File':
case 'SingleGeo':
case 'Geo':
case 'Price':
case 'Decimal': {
properties.push([name, false]);
break;
}
case 'Object': {
properties.push([name, false, factory.createUnionTypeNode([
factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
factory.createTypeReferenceNode(factory.createIdentifier("Object"), undefined)
])]);
break;
}
default: {
const text2 = text === 'Schema' ? entity : text;
const manyToOneItem = manyToOneSet && manyToOneSet.find(([refEntity]) => refEntity === text2);
if (manyToOneItem) {
// 外键投影
properties.push([`${attrName}Id`, false, undefined]);
}
else {
if (!enumAttributes || !enumAttributes[attrName]) {
// 引用的非enum类型shape
properties.push([name, false, factory.createUnionTypeNode([
factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
factory.createTypeReferenceNode(factory.createIdentifier("JsonProjection"), [type])
])]);
}
else {
// 引用的enum类型shape
properties.push([name, false, undefined]);
}
}
}
}
}
else {
(0, assert_1.default)(false);
}
}
else {
// 增加了本身object的shape定义
// assert(ts.isUnionTypeNode(type!) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type!));
if (enumAttributes && enumAttributes[attrName] || ts.isUnionTypeNode(type) && ts.isLiteralTypeNode(type.types[0])) {
properties.push([name, false, undefined]);
}
else {
// 如果是非枚举类型的其它对象的union定义加上JsonProjection
properties.push([name, false, factory.createUnionTypeNode([
factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
factory.createTypeReferenceNode(factory.createIdentifier("JsonProjection"), [type])
])]);
}
}
}
const exprNode = factory.createTypeReferenceNode(factory.createIdentifier("Partial"), [
factory.createTypeReferenceNode(factory.createIdentifier("ExprOp"), [
process.env.COMPLING_AS_LIB ?
factory.createUnionTypeNode([
factory.createTypeReferenceNode(factory.createIdentifier('OpAttr')),
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
]) :
factory.createTypeReferenceNode(factory.createIdentifier('OpAttr'))
])
]);
const MetaPropertySignatures = [
factory.createPropertySignature(undefined, factory.createStringLiteral("#id"), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode('NodeId'))
];
if (process.env.COMPLING_AS_LIB) {
MetaPropertySignatures.push(factory.createIndexSignature(undefined, [factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier("k"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), undefined)], factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)));
}
// OpProjection原始属性投影
statements.push(factory.createTypeAliasDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("OpProjection"), undefined, factory.createIntersectionTypeNode([
factory.createTypeLiteralNode(MetaPropertySignatures.concat(properties.map(([n, q, v]) => {
return factory.createPropertySignature(undefined, n, q ? undefined : factory.createToken(ts.SyntaxKind.QuestionToken), v || factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword));
}))),
exprNode,
])));
}
function getOpProjectionKeys(entity) {
const { schemaAttrs, enumAttributes } = Schema[entity];
const { [entity]: manyToOneSet } = ManyToOne;
const result = [
'id',
'$$createAt$$',
'$$updateAt$$',
'$$seq$$',
];
for (const attr of schemaAttrs) {
const { type, name } = attr;
const attrName = name.text;
if (ts.isTypeReferenceNode(type)) {
const { typeName } = type;
if (ts.isIdentifier(typeName)) {
const typeStr = typeName.text;
switch (typeStr) {
case 'String':
case 'Text':
case 'Int':
case 'Uint':
case 'Float':
case 'Double':
case 'Boolean':
case 'Datetime':
case 'Image':
case 'File':
case 'SingleGeo':
case 'Geo':
case 'Price':
case 'Decimal':
result.push(attrName);
break;
case 'Object':
result.push(attrName);
break;
default: {
const refEntity = typeStr === 'Schema' ? entity : typeStr;
const isManyToOne = manyToOneSet?.some(([e]) => e === refEntity);
if (isManyToOne) {
result.push(`${attrName}Id`);
}
else if (!enumAttributes?.[attrName]) {
result.push(attrName);
}
else {
result.push(attrName);
}
}
}
}
}
else {
result.push(attrName);
}
}
return result;
}
/**
* 构造Query
* @param statements
* @param entity
*/
function constructQuery(statements, entity) {
const entityLc = (0, string_1.firstLetterLowerCase)(entity);
/* statements.push(
factory.createTypeAliasDeclaration(
undefined,
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
factory.createIdentifier("Query"),
undefined,
factory.createIntersectionTypeNode([
factory.createTypeLiteralNode([
// 这里可以不写entity了
factory.createPropertySignature(
undefined,
factory.createIdentifier("projection"),
undefined,
factory.createTypeReferenceNode(
factory.createIdentifier("Projection"),
undefined
)
),
factory.createPropertySignature(
undefined,
factory.createIdentifier("sort"),
factory.createToken(ts.SyntaxKind.QuestionToken),
factory.createTypeReferenceNode(
factory.createIdentifier("Sorter"),
undefined
)
)
]),
factory.createTypeReferenceNode(
factory.createIdentifier("OakFilter"),
[
factory.createLiteralTypeNode(factory.createStringLiteral("select")),
factory.createTypeReferenceNode(
factory.createIdentifier("Filter"),
undefined
)
]
),
factory.createTypeReferenceNode(
factory.createIdentifier("OakOperation"),
[
factory.createTypeReferenceNode(
factory.createIdentifier("Operation"),
undefined
)
]
)
])
)
); */
/**
* export type ExportQuery = {
entity: 'user';
projection: ExportProjection;
filter?: Filter;
sort?: Sorter;
indexFrom?: number;
count?: number;
};
*/
/* statements.push(
factory.createTypeAliasDeclaration(
undefined,
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
factory.createIdentifier("ExportQuery"),
undefined,
factory.createIntersectionTypeNode([
factory.createTypeLiteralNode([
factory.createPropertySignature(
undefined,
factory.createIdentifier("projection"),
undefined,
factory.createTypeReferenceNode(
factory.createIdentifier("ExportProjection"),
undefined
)
),
factory.createPropertySignature(
undefined,
factory.createIdentifier("sort"),
factory.createToken(ts.SyntaxKind.QuestionToken),
factory.createTypeReferenceNode(
factory.createIdentifier("Sorter"),
undefined
)
)
]),
factory.createTypeReferenceNode(
factory.createIdentifier("OakFilter"),
[
factory.createLiteralTypeNode(factory.createStringLiteral("select")),
factory.createTypeReferenceNode(
factory.createIdentifier("Filter"),
undefined
)
]
)
])
)
); */
// 对每个可能的外键的子查询,建立相应的${Entity}IdSubQuery
const { [entity]: manyToOneSet } = ManyToOne;
let manyToSelf = false;
if (manyToOneSet) {
(0, lodash_1.uniqBy)(manyToOneSet, ([a]) => a).forEach(([oneEntity, foreignKey]) => {
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier(`${oneEntity}IdSubQuery`), undefined, factory.createTypeReferenceNode(factory.createIdentifier("Selection"), [factory.createTypeReferenceNode(factory.createIdentifier(`${oneEntity}IdProjection`), undefined)])));
if (oneEntity === entity) {
manyToSelf = true;
}
});
}
// 主键可能产生的子查询
if (!manyToSelf) {
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier(`${entity}IdSubQuery`), undefined, factory.createTypeReferenceNode(factory.createIdentifier("Selection"), [factory.createTypeReferenceNode(factory.createIdentifier(`${entity}IdProjection`), undefined)])));
}
}
/**
* 构造Sort
* @param statements
* @param entity
*/
function constructSorter(statements, entity) {
const { schemaAttrs } = Schema[entity];
const members = [
// id: 1
factory.createTypeLiteralNode([factory.createPropertySignature(undefined, factory.createIdentifier("id"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword))]),
// $$createAt$$: 1
factory.createTypeLiteralNode([factory.createPropertySignature(undefined, factory.createIdentifier("$$createAt$$"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword))]),
// $$seq$$: 1
factory.createTypeLiteralNode([factory.createPropertySignature(undefined, factory.createIdentifier("$$seq$$"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword))]),
// $$updateAt$$: 1
factory.createTypeLiteralNode([factory.createPropertySignature(undefined, factory.createIdentifier("$$updateAt$$"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword))]),
];
const { [entity]: manyToOneSet } = ManyToOne;
for (const attr of schemaAttrs) {
const { type, name, questionToken } = attr;
if (ts.isTypeReferenceNode(type)) {
const { typeName } = type;
if (ts.isIdentifier(typeName)) {
const { text } = typeName;
let type2;
switch (text) {
case 'String':
case 'Text':
case 'Int':
case 'Float':
case 'Double':
case 'Boolean':
case 'Datetime':
case 'Image':
case 'File':
case 'Price': {
type2 = factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
break;
}
default: {
const text2 = text === 'Schema' ? entity : text;
const manyToOneItem = manyToOneSet && manyToOneSet.find(([refEntity]) => refEntity === text2);
if (manyToOneItem) {
type2 = factory.createTypeReferenceNode(createForeignRef(entity, text2, 'SortAttr'));
members.push(factory.createTypeLiteralNode([factory.createPropertySignature(undefined, factory.createIdentifier(`${name.text}Id`), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword))]));
}
else if (!['Object'].includes(text)) {
// todo 对State的专门处理
type2 = factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
}
}
}
if (type2) {
members.push(factory.createTypeLiteralNode([factory.createPropertySignature(undefined, name, undefined, type2)]));
}
}
}
else if (ts.isUnionTypeNode(type) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type)) {
members.push(factory.createTypeLiteralNode([factory.createPropertySignature(undefined, name, undefined, factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword))]));
}
else {
// 本地规定的shape非结构化属性不参与排序
}
}
if (ReversePointerRelations[entity]) {
ReversePointerRelations[entity].forEach((one) => {
members.push(factory.createTypeLiteralNode([factory.createPropertySignature(undefined, (0, string_1.firstLetterLowerCase)(one), undefined, factory.createTypeReferenceNode(createForeignRef(entity, one, 'SortAttr')))]));
});
}
if (process.env.COMPLING_AS_LIB) {
members.push(factory.createTypeLiteralNode([factory.createIndexSignature(undefined, [factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier("k"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), undefined)], factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword))]));
}
members.push(factory.createTypeReferenceNode(factory.createIdentifier("OneOf"), [factory.createTypeReferenceNode(factory.createIdentifier("ExprOp"), [
process.env.COMPLING_AS_LIB ?
factory.createUnionTypeNode([
factory.createTypeReferenceNode(factory.createIdentifier('OpAttr')),
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
]) :
factory.createTypeReferenceNode(factory.createIdentifier('OpAttr'))
])]));
/**
*
export type SortAttr = {
id: 1;
} | {
$$createAt$$: 1;
} | {
$$updateAt$$: 1;
} | {
modiId: 1;
} | {
modi: Modi.SortAttr;
} | {
[k: string]: any;
} | OneOf<ExprOp<OpAttr>>
*/
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("SortAttr"), undefined, factory.createUnionTypeNode(members)));
/**
* export type SortNode = {
$attr: SortAttr;
$direction?: 'asc' | 'desc';
};
*/
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("SortNode"), undefined, factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier("$attr"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("SortAttr"), undefined)),
factory.createPropertySignature(undefined, factory.createIdentifier("$direction"), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([
factory.createLiteralTypeNode(factory.createStringLiteral("asc")),
factory.createLiteralTypeNode(factory.createStringLiteral("desc"))
]))
])));
/**
* export type Sorter = SortNode[];
*/
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("Sorter"), undefined, factory.createArrayTypeNode(factory.createTypeReferenceNode(factory.createIdentifier("SortNode"), undefined))));
}
function _constructOpSortAttr(statements, entity) {
const { schemaAttrs } = Schema[entity];
const members = [
// id: 1
factory.createPropertySignature(undefined, factory.createIdentifier("id"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)),
// $$createAt$$: 1
factory.createPropertySignature(undefined, factory.createIdentifier("$$createAt$$"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)),
// $$seq$$: 1
factory.createPropertySignature(undefined, factory.createIdentifier("$$seq$$"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)),
// $$updateAt$$: 1
factory.createPropertySignature(undefined, factory.createIdentifier("$$updateAt$$"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)),
];
const { [entity]: manyToOneSet } = ManyToOne;
for (const attr of schemaAttrs) {
const { type, name, questionToken } = attr;
if (ts.isTypeReferenceNode(type)) {
const { typeName } = type;
if (ts.isIdentifier(typeName)) {
const { text } = typeName;
let type2;
switch (text) {
case 'String':
case 'Text':
case 'Int':
case 'Float':
case 'Double':
case 'Boolean':
case 'Datetime':
case 'Image':
case 'File':
case 'Price': {
type2 = factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
break;
}
default: {
const text2 = text === 'Schema' ? entity : text;
const manyToOneItem = manyToOneSet && manyToOneSet.find(([refEntity]) => refEntity === text2);
if (manyToOneItem) {
members.push(factory.createPropertySignature(undefined, factory.createIdentifier(`${name.text}Id`), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)));
}
else if (!['Object'].includes(text)) {
// todo 对State的专门处理
type2 = factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
}
}
}
if (type2) {
members.push(factory.createPropertySignature(undefined, name, undefined, type2));
}
}
}
else if (ts.isUnionTypeNode(type) && ts.isLiteralTypeNode(type.types[0]) || ts.isLiteralTypeNode(type)) {
members.push(factory.createPropertySignature(undefined, name, undefined, factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)));
}
else {
// 本地规定的shape非结构化属性不参与排序
}
}
if (process.env.COMPLING_AS_LIB) {
members.push(factory.createIndexSignature(undefined, [factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier("k"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), undefined)], factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)));
}
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("OpSortAttr"), undefined, factory.createTypeReferenceNode('Partial', [
factory.createUnionTypeNode([
factory.createTypeLiteralNode(members),
factory.createTypeReferenceNode(factory.createIdentifier("ExprOp"), [
process.env.COMPLING_AS_LIB ?
factory.createUnionTypeNode([
factory.createTypeReferenceNode(factory.createIdentifier('OpAttr')),
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
]) :
factory.createTypeReferenceNode(factory.createIdentifier('OpAttr'))
])
])
])));
}
function constructOperations(statements, entity) {
// Selection
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("SelectOperation"), [
factory.createTypeParameterDeclaration(undefined, factory.createIdentifier("P"), factory.createTypeReferenceNode(factory.createIdentifier("Object"), undefined), factory.createTypeReferenceNode(factory.createIdentifier("Projection"), undefined))
], factory.createTypeReferenceNode(factory.createIdentifier("OakSelection"), [
factory.createLiteralTypeNode(factory.createStringLiteral("select")),
factory.createTypeReferenceNode(factory.createIdentifier("P"), undefined),
factory.createTypeReferenceNode(factory.createIdentifier("Filter"), undefined),
factory.createTypeReferenceNode(factory.createIdentifier("Sorter"), undefined)
])), factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("Selection"), [
factory.createTypeParameterDeclaration(undefined, factory.createIdentifier("P"), factory.createTypeReferenceNode(factory.createIdentifier("Object"), undefined), factory.createTypeReferenceNode(factory.createIdentifier("Projection"), undefined))
], factory.createTypeReferenceNode(factory.createIdentifier("SelectOperation"), [
factory.createTypeReferenceNode(factory.createIdentifier("P"), undefined)
])), factory.createTypeAliasDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("Aggregation"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("DeduceAggregation"), [
factory.createTypeReferenceNode(factory.createIdentifier("Projection"), undefined),
factory.createTypeReferenceNode(factory.createIdentifier("Filter"), undefined),
factory.createTypeReferenceNode(factory.createIdentifier("Sorter"), undefined)
])));
// Exportation
// 已经废弃by Xc 2023.01.08
/* statements.push(
factory.createTypeAliasDeclaration(
undefined,
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
factory.createIdentifier("Exportation"),
undefined,
factory.createTypeReferenceNode(
factory.createIdentifier("OakOperation"),
[
factory.createLiteralTypeNode(factory.createStringLiteral("export")),
factory.createTypeReferenceNode(
factory.createIdentifier("ExportProjection"),
undefined
),
factory.createTypeReferenceNode(
factory.createIdentifier("Filter"),
undefined
),
factory.createTypeReferenceNode(
factory.createIdentifier("Sorter"),
undefined
)
]
)
)
); */
const { [entity]: manyToOneSet } = ManyToOne;
const { [entity]: oneToManySet } = OneToMany;
const foreignKeySet = {};
if (oneToManySet) {
for (const oneToManyItem of oneToManySet) {
const [entityName, foreignKey] = oneToManyItem;
if (foreignKeySet.hasOwnProperty(entityName)) {
foreignKeySet[entityName].push(foreignKey);
}
else {
foreignKeySet[entityName] = [foreignKey];
}
}
}
// CreateOperationData
let foreignKeyAttr = [];
if (ReversePointerEntities[entity]) {
foreignKeyAttr.push('entity', 'entityId');
}
if (manyToOneSet) {
for (const one of manyToOneSet) {
if (one[1] !== 'entity') {
foreignKeyAttr.push(`${one[1]}Id`);
}
}
}
let adNodes = [
factory.createTypeReferenceNode(factory.createIdentifier("FormCreateData"), [
foreignKeyAttr.length > 0
? factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
factory.createTypeReferenceNode(factory.createIdentifier("OpSchema"), undefined),
factory.createUnionTypeNode((0, lodash_1.uniq)(foreignKeyAttr).map(ele => factory.createLiteralTypeNode(factory.createStringLiteral(ele))))
])
: factory.createTypeReferenceNode(factory.createIdentifier("OpSchema"), undefined)
])
];
if (manyToOneSet) {
/**
* create的多对一有两种case
* 如果关联对象是create则对象的外键由关联对象的id决定
* 如果关联对象是update则关联对象的filter由对象决定其主键
* 见cascadeStore
*/
const upsertOneNodes = [];
for (const one of manyToOneSet) {
if (one[1] !== 'entity') {
const oneEntity = one[0];
const cascadeCreateNode = factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier(`${one[1]}Id`), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)),
factory.createPropertySignature(undefined, factory.createIdentifier(one[1]), one[2] ? factory.createToken(ts.SyntaxKind.QuestionToken) : undefined, factory.createTypeReferenceNode(createForeignRef(entity, one[0], 'CreateSingleOperation')))
]);
const cascadeUpdateNode = factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier(`${one[1]}Id`), undefined, factory.createTypeReferenceNode(factory.createIdentifier("ForeignKey"), [factory.createLiteralTypeNode(factory.createStringLiteral(one[1]))])),
factory.createPropertySignature(undefined, factory.createIdentifier(one[1]), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(createForeignRef(entity, one[0], 'UpdateOperation')))
]);
const noCascadeNode = factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier(one[1]), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)),
factory.createPropertySignature(undefined, factory.createIdentifier(`${one[1]}Id`), one[2] ? factory.createToken(ts.SyntaxKind.QuestionToken) : undefined, factory.createTypeReferenceNode(factory.createIdentifier("ForeignKey"), [factory.createLiteralTypeNode(factory.createStringLiteral(one[1]))]))
]);
if (Schema[oneEntity].static) {
upsertOneNodes.push(noCascadeNode);
}
else {
switch (Schema[oneEntity].actionType) {
case 'crud':
case 'excludeRemove': {
upsertOneNodes.push(factory.createUnionTypeNode([cascadeCreateNode, cascadeUpdateNode, noCascadeNode]));
break;
}
case 'excludeUpdate':
case 'appendOnly': {
upsertOneNodes.push(factory.createUnionTypeNode([cascadeCreateNode, noCascadeNode]));
break;
}
case 'readOnly': {
upsertOneNodes.push(noCascadeNode);
break;
}
default: {
(0, assert_1.default)(false);
}
}
}
}
}
if (upsertOneNodes.length > 0) {
adNodes.push(factory.createIntersectionTypeNode(upsertOneNodes));
}
}
const reverseOneNodes = [];
if (ReversePointerEntities[entity]) {
if (ReversePointerRelations[entity]) {
const { schemaAttrs } = Schema[entity];
const { questionToken: entityQuestionToken } = schemaAttrs.find(ele => {
const { name } = ele;
return name.text === 'entity';
});
const { questionToken: entityIdQuestionToken } = schemaAttrs.find(ele => {
const { name } = ele;
return name.text === 'entityId';
});
for (const one of ReversePointerRelations[entity]) {
const cascadeCreateNode = factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier('entity'), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)),
factory.createPropertySignature(undefined, factory.createIdentifier('entityId'), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)),
factory.createPropertySignature(undefined, factory.createIdentifier((0, string_1.firstLetterLowerCase)(one)), entityQuestionToken || entityIdQuestionToken, factory.createTypeReferenceNode(createForeignRef(entity, one, 'CreateSingleOperation')))
]);
const cascadeUpdateNode = factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier('entity'), entityQuestionToken, factory.createLiteralTypeNode(factory.createStringLiteral(`${(0, string_1.firstLetterLowerCase)(one)}`))),
factory.createPropertySignature(undefined, factory.createIdentifier('entityId'), entityIdQuestionToken, factory.createTypeReferenceNode(factory.createIdentifier("ForeignKey"), [factory.createLiteralTypeNode(factory.createStringLiteral(one))])),
factory.createPropertySignature(undefined, factory.createIdentifier((0, string_1.firstLetterLowerCase)(one)), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(createForeignRef(entity, one, 'UpdateOperation')))
]);
const noCascadeNode = factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier('entity'), entityQuestionToken, factory.createLiteralTypeNode(factory.createStringLiteral(`${(0, string_1.firstLetterLowerCase)(one)}`))),
factory.createPropertySignature(undefined, factory.createIdentifier('entityId'), entityIdQuestionToken, factory.createTypeReferenceNode(factory.createIdentifier("ForeignKey"), [factory.createLiteralTypeNode(factory.createStringLiteral(one))])),
factory.createPropertySignature(undefined, factory.createIdentifier((0, string_1.firstLetterLowerCase)(one)), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword))
]);
if (Schema[one].static) {
reverseOneNodes.push(noCascadeNode);
}
else {
switch (Schema[one].actionType) {
case 'crud':
case 'excludeRemove': {
reverseOneNodes.push(cascadeCreateNode, cascadeUpdateNode, noCascadeNode);
break;
}
case 'appendOnly':
case 'excludeUpdate': {
reverseOneNodes.push(cascadeCreateNode, noCascadeNode);
break;
}
case 'readOnly': {
reverseOneNodes.push(noCascadeNode);
break;
}
default: {
(0, assert_1.default)(false);
}
}
}
}
}
if (process.env.COMPLING_AS_LIB) {
// 如果是base要包容更多可能的反指
reverseOneNodes.push(factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier('entity'), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)),
factory.createPropertySignature(undefined, factory.createIdentifier('entityId'), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)),
factory.createIndexSignature(undefined, [factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier("K"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), undefined)], factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword))
]));
}
if (reverseOneNodes.length > 0) {
adNodes.push(factory.createUnionTypeNode(reverseOneNodes));
}
}
// 一对多
const propertySignatures = [];
if (oneToManySet) {
for (const entityName in foreignKeySet) {
const entityNameLc = (0, string_1.firstLetterLowerCase)(entityName);
foreignKeySet[entityName].forEach((foreignKey) => {
const identifier = `${entityNameLc}$${foreignKey}`;
const otmCreateOperationDataNode = factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
factory.createTypeReferenceNode(createForeignRef(entity, entityName, 'CreateOperationData'), undefined),
factory.createUnionTypeNode(foreignKey === 'entity' ? [
factory.createLiteralTypeNode(factory.createStringLiteral("entity")),
factory.createLiteralTypeNode(factory.createStringLiteral("entityId"))
] : [
factory.createLiteralTypeNode(factory.createStringLiteral(foreignKey)),
factory.createLiteralTypeNode(factory.createStringLiteral(`${foreignKey}Id`))
])
]);
const otmCreateSingleOperationNode = factory.createTypeReferenceNode(factory.createIdentifier("OakOperation"), [
factory.createLiteralTypeNode(factory.createStringLiteral("create")),
otmCreateOperationDataNode
]);
const otmCreateMultipleOperationNode = factory.createTypeReferenceNode(factory.createIdentifier("OakOperation"), [
factory.createLiteralTypeNode(factory.createStringLiteral("create")),
factory.createArrayTypeNode(otmCreateOperationDataNode)
]);
const otmUpdateOperationNode = factory.createTypeReferenceNode(factory.createIdentifier("OakOperation"), [
factory.createIndexedAccessTypeNode(factory.createTypeReferenceNode(createForeignRef(entity, entityName, 'UpdateOperation'), undefined), factory.createLiteralTypeNode(factory.createStringLiteral("action"))),
factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
factory.createTypeReferenceNode(createForeignRef(entity, entityName, 'UpdateOperationData'), undefined),
factory.createUnionTypeNode(foreignKey === 'entity' ? [
factory.createLiteralTypeNode(factory.createStringLiteral("entity")),
factory.createLiteralTypeNode(factory.createStringLiteral("entityId"))
] : [
factory.createLiteralTypeNode(factory.createStringLiteral(foreignKey)),
factory.createLiteralTypeNode(factory.createStringLiteral(`${foreignKey}Id`))
])
]),
factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
factory.createTypeReferenceNode(createForeignRef(entity, entityName, 'Filter'), undefined),
factory.createUnionTypeNode(foreignKey === 'entity' ? [
factory.createLiteralTypeNode(factory.createStringLiteral("entity")),
factory.createLiteralTypeNode(factory.createStringLiteral("entityId"))
] : [
factory.createLiteralTypeNode(factory.createStringLiteral(foreignKey)),
factory.createLiteralTypeNode(factory.createStringLiteral(`${foreignKey}Id`))
])
])
]);
if (!Schema[entityName].static) {
switch (Schema[entityName].actionType) {
case 'crud': {
propertySignatures.push(factory.createPropertySignature(undefined, factory.createIdentifier(identifier), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([
otmUpdateOperationNode,
otmCreateMultipleOperationNode,
factory.createTypeReferenceNode(factory.createIdentifier("Array"), [factory.createUnionTypeNode([
otmCreateSingleOperationNode,
otmUpdateOperationNode
])])
])));
break;
}
case 'appendOnly':
case 'excludeUpdate': {
propertySignatures.push(factory.createPropertySignature(undefined, factory.createIdentifier(identifier), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([
otmCreateMultipleOperationNode,
factory.createTypeReferenceNode(factory.createIdentifier("Array"), [otmCreateSingleOperationNode])
])));
break;
}
case 'readOnly': {
break;
}
default: {
(0, assert_1.default)(false);
}
}
}
});
}
}
if (propertySignatures.length > 0) {
adNodes.push(factory.createTypeLiteralNode(propertySignatures));
}
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("CreateOperationData"), undefined, factory.createIntersectionTypeNode(adNodes)));
// CreateOperation
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("CreateSingleOperation"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("OakOperation"), [
factory.createLiteralTypeNode(factory.createStringLiteral("create")),
factory.createTypeReferenceNode(factory.createIdentifier("CreateOperationData"))
])), factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("CreateMultipleOperation"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("OakOperation"), [
factory.createLiteralTypeNode(factory.createStringLiteral("create")),
factory.createTypeReferenceNode(factory.createIdentifier("Array"), [factory.createTypeReferenceNode(factory.createIdentifier("CreateOperationData"))])
])), factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("CreateOperation"), undefined, factory.createUnionTypeNode([
factory.createTypeReferenceNode(factory.createIdentifier("CreateSingleOperation")),
factory.createTypeReferenceNode(factory.createIdentifier("CreateMultipleOperation"))
])));
// UpdateOperationData
foreignKeyAttr = [];
if (ReversePointerRelations[entity]) {
foreignKeyAttr.push('entity', 'entityId');
}
if (manyToOneSet) {
for (const one of manyToOneSet) {
if (one[1] !== 'entity') {
foreignKeyAttr.push(`${one[1]}Id`);
}
}
}
adNodes = [
factory.createTypeReferenceNode(factory.createIdentifier("FormUpdateData"), [
foreignKeyAttr.length > 0 ? factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
factory.createTypeReferenceNode(factory.createIdentifier("OpSchema"), undefined),
factory.createUnionTypeNode((0, lodash_1.uniq)(foreignKeyAttr).map(ele => factory.createLiteralTypeNode(factory.createStringLiteral(ele))))
]) : factory.createTypeReferenceNode(factory.createIdentifier("OpSchema"), undefined)
])
];
if (manyToOneSet) {
/**
* update的多对一有三种case
* 如果关联对象是create则对象的外键由关联对象的id决定
* 如果关联对象是update或者remove则关联对象的filter由对象(的原行!注意这里的外键是不能变的!)决定其主键
* 见cascadeStore
*/
const upsertOneNodes = [];
for (const one of manyToOneSet) {
if (one[1] !== 'entity') {
const cascadeCreateNode = factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier(one[1]), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(createForeignRef(entity, one[0], 'CreateSingleOperation'))),
factory.createPropertySignature(undefined, factory.createIdentifier(`${one[1]}Id`), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)),
]);
const cascadeUpdateNode = factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier(one[1]), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(createForeignRef(entity, one[0], 'UpdateOperation'))),
factory.createPropertySignature(undefined, factory.createIdentifier(`${one[1]}Id`), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)),
]);
const cascadeRemoveNode = factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier(one[1]), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(createForeignRef(entity, one[0], 'RemoveOperation'))),
factory.createPropertySignature(undefined, factory.createIdentifier(`${one[1]}Id`), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)),
]);
const noCascadeNode = factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier(one[1]), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)),
factory.createPropertySignature(undefined, factory.createIdentifier(`${one[1]}Id`), factory.createToken(ts.SyntaxKind.QuestionToken), one[2] ? factory.createUnionTypeNode([
factory.createTypeReferenceNode(factory.createIdentifier("ForeignKey"), [factory.createLiteralTypeNode(factory.createStringLiteral(one[1]))]),
factory.createLiteralTypeNode(factory.createNull())
]) : factory.createTypeReferenceNode(factory.createIdentifier("ForeignKey"), [factory.createLiteralTypeNode(factory.createStringLiteral(one[1]))])),
]);
if (Schema[one[0]].static) {
upsertOneNodes.push(noCascadeNode);
}
else {
switch (Schema[one[0]].actionType) {
case 'crud': {
upsertOneNodes.push(factory.createUnionTypeNode([cascadeCreateNode, cascadeUpdateNode, cascadeRemoveNode, noCascadeNode]));
break;
}
case 'excludeUpdate': {
upsertOneNodes.push(factory.createUnionTypeNode([cascadeCreateNode, cascadeRemoveNode, noCascadeNode]));
break;
}
case 'appendOnly': {
upsertOneNodes.push(factory.createUnionTypeNode([cascadeCreateNode, noCascadeNode]));
break;
}
case 'readOnly': {
upsertOneNodes.push(noCascadeNode);
break;
}
case 'excludeRemove': {
upsertOneNodes.push(factory.createUnionTypeNode([cascadeCreateNode, cascadeUpdateNode, noCascadeNode]));
break;
}
default: {
(0, assert_1.default)(false);
}
}
}
}
}
if (upsertOneNodes.length > 0) {
adNodes.push(factory.createIntersectionTypeNode(upsertOneNodes));
}
const reverseOneNodes = [];
if (ReversePointerRelations[entity]) {
const refEntityLitrals = [];
for (const one of ReversePointerRelations[entity]) {
refEntityLitrals.push(factory.createLiteralTypeNode(factory.createStringLiteral(`${(0, string_1.firstLetterLowerCase)(one)}`)));
const actionNodes = [];
if (!Schema[one].static) {
switch (Schema[one].actionType) {
case 'crud': {
actionNodes.push(factory.createTypeReferenceNode(createForeignRef(entity, one, 'CreateSingleOperation')), factory.createTypeReferenceNode(createForeignRef(entity, one, 'UpdateOperation')), factory.createTypeReferenceNode(createForeignRef(entity, one, 'RemoveOperation')));
break;
}
case 'excludeUpdate': {
actionNodes.push(factory.createTypeReferenceNode(createForeignRef(entity, one, 'CreateSingleOperation')), factory.createTypeReferenceNode(createForeignRef(entity, one, 'RemoveOperation')));
break;
}
case 'excludeRemove': {
actionNodes.push(factory.createTypeReferenceNode(createForeignRef(entity, one, 'CreateSingleOperation')), factory.createTypeReferenceNode(createForeignRef(entity, one, 'UpdateOperation')));
break;
}
case 'appendOnly': {
actionNodes.push(factory.createTypeReferenceNode(createForeignRef(entity, one, 'CreateSingleOperation')));
break;
}
case 'readOnly': {
break;
}
default: {
(0, assert_1.default)(false);
}
}
}
if (actionNodes.length > 0) {
reverseOneNodes.push(factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier((0, string_1.firstLetterLowerCase)(one)), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode(actionNodes)),
factory.createPropertySignature(undefined, factory.createIdentifier('entityId'), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword)),
factory.createPropertySignature(undefined, factory.createIdentifier('entity'), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword))
]));
}
}
const { schemaAttrs } = Schema[entity];
const { questionToken: entityQuestionToken } = schemaAttrs.find(ele => {
const { name } = ele;
return name.text === 'entity';
});
const { questionToken: entityIdQuestionToken } = schemaAttrs.find(ele => {
const { name } = ele;
return name.text === 'entityId';
});
reverseOneNodes.push(factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier('entity'), factory.createToken(ts.SyntaxKind.QuestionToken), !entityQuestionToken ? factory.createUnionTypeNode([
// 如果是作为lib要包容更多可能的反指
factory.createUnionTypeNode(process.env.COMPLING_AS_LIB ? refEntityLitrals.concat(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)) : refEntityLitrals),
factory.createLiteralTypeNode(factory.createNull())
]) : factory.createUnionTypeNode(process.env.COMPLING_AS_LIB ? refEntityLitrals.concat(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)) : refEntityLitrals)),
factory.createPropertySignature(undefined, factory.createIdentifier('entityId'), factory.createToken(ts.SyntaxKind.QuestionToken), !entityIdQuestionToken ? factory.createUnionTypeNode([
factory.createTypeReferenceNode(factory.createIdentifier("ForeignKey"), [factory.createUnionTypeNode(ReversePointerRelations[entity].map(ele => factory.createLiteralTypeNode(factory.createStringLiteral(ele))))]),
factory.createLiteralTypeNode(factory.createNull())
]) : factory.createTypeReferenceNode(factory.createIdentifier("ForeignKey"), [factory.createUnionTypeNode(ReversePointerRelations[entity].map(ele => factory.createLiteralTypeNode(factory.createStringLiteral(ele))))]))
].concat(ReversePointerRelations[entity].map((one) => factory.createPropertySignature(undefined, factory.createIdentifier((0, string_1.firstLetterLowerCase)(one)), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createKeywordTypeNode(ts.SyntaxKind.NeverKeyword))))));
}
if (reverseOneNodes.length > 0) {
adNodes.push(factory.createUnionTypeNode(reverseOneNodes));
}
}
const propertySignatures2 = [];
if (process.env.COMPLING_AS_LIB) {
propertySignatures2.push(factory.createIndexSignature(undefined, [factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier("k"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), undefined)], factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)));
}
if (oneToManySet) {
for (const entityName in foreignKeySet) {
const entityNameLc = (0, string_1.firstLetterLowerCase)(entityName);
foreignKeySet[entityName].forEach((foreignKey) => {
const identifier = `${entityNameLc}$${foreignKey}`;
const otmCreateOperationDataNode = factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
factory.createTypeReferenceNode(createForeignRef(entity, entityName, 'CreateOperationData'), undefined),
factory.createUnionTypeNode(foreignKey === 'entity' ? [
factory.createLiteralTypeNode(factory.createStringLiteral("entity")),
factory.createLiteralTypeNode(factory.createStringLiteral("entityId"))
] : [
factory.createLiteralTypeNode(factory.createStringLiteral(foreignKey)),
factory.createLiteralTypeNode(factory.createStringLiteral(`${foreignKey}Id`))
])
]);
const otmCreateSingleOperationNode = factory.createTypeReferenceNode(factory.createIdentifier("OakOperation"), [
factory.createLiteralTypeNode(factory.createStringLiteral("create")),
otmCreateOperationDataNode
]);
const otmCreateMultipleOperationNode = factory.createTypeReferenceNode(factory.createIdentifier("OakOperation"), [
factory.createLiteralTypeNode(factory.createStringLiteral("create")),
factory.createArrayTypeNode(otmCreateOperationDataNode)
]);
const otmUpdateOperationNode = factory.createTypeReferenceNode(factory.createIdentifier("OakOperation"), [
factory.createIndexedAccessTypeNode(factory.createTypeReferenceNode(createForeignRef(entity, entityName, 'UpdateOperation'), undefined), factory.createLiteralTypeNode(factory.createStringLiteral("action"))),
factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
factory.createTypeReferenceNode(createForeignRef(entity, entityName, 'UpdateOperationData'), undefined),
factory.createUnionTypeNode(foreignKey === 'entity' ? [
factory.createLiteralTypeNode(factory.createStringLiteral("entity")),
factory.createLiteralTypeNode(factory.createStringLiteral("entityId"))
] : [
factory.createLiteralTypeNode(factory.createStringLiteral(foreignKey)),
factory.createLiteralTypeNode(factory.createStringLiteral(`${foreignKey}Id`))
])
]),
factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
factory.createTypeReferenceNode(createForeignRef(entity, entityName, 'Filter'), undefined),
factory.createUnionTypeNode(foreignKey === 'entity' ? [
factory.createLiteralTypeNode(factory.createStringLiteral("entity")),
factory.createLiteralTypeNode(factory.createStringLiteral("entityId"))
] : [
factory.createLiteralTypeNode(factory.createStringLiteral(foreignKey)),
factory.createLiteralTypeNode(factory.createStringLiteral(`${foreignKey}Id`))
])
])
]);
const otmRemoveOperationNode = factory.createTypeReferenceNode(factory.createIdentifier("OakOperation"), [
factory.createIndexedAccessTypeNode(factory.createTypeReferenceNode(createForeignRef(entity, entityName, 'RemoveOperation'), undefined), factory.createLiteralTypeNode(factory.createStringLiteral("action"))),
factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
factory.createTypeReferenceNode(createForeignRef(entity, entityName, 'RemoveOperationData'), undefined),
factory.createUnionTypeNode(foreignKey === 'entity' ? [
factory.createLiteralTypeNode(factory.createStringLiteral("entity")),
factory.createLiteralTypeNode(factory.createStringLiteral("entityId"))
] : [
factory.createLiteralTypeNode(factory.createStringLiteral(foreignKey)),
factory.createLiteralTypeNode(factory.createStringLiteral(`${foreignKey}Id`))
])
]),
factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
factory.createTypeReferenceNode(createForeignRef(entity, entityName, 'Filter'), undefined),
factory.createUnionTypeNode(foreignKey === 'entity' ? [
factory.createLiteralTypeNode(factory.createStringLiteral("entity")),
factory.createLiteralTypeNode(factory.createStringLiteral("entityId"))
] : [
factory.createLiteralTypeNode(factory.createStringLiteral(foreignKey)),
factory.createLiteralTypeNode(factory.createStringLiteral(`${foreignKey}Id`))
])
])
]);
if (!Schema[entityName].static) {
switch (Schema[entityName].actionType) {
case 'crud': {
propertySignatures2.push(factory.createPropertySignature(undefined, factory.createIdentifier(identifier), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([
otmUpdateOperationNode,
otmRemoveOperationNode,
otmCreateMultipleOperationNode,
factory.createTypeReferenceNode(factory.createIdentifier("Array"), [factory.createUnionTypeNode([
otmCreateSingleOperationNode,
otmUpdateOperationNode,
otmRemoveOperationNode
])])
])));
break;
}
case 'excludeUpdate': {
propertySignatures2.push(factory.createPropertySignature(undefined, factory.createIdentifier(identifier), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([
otmRemoveOperationNode,
otmCreateMultipleOperationNode,
factory.createTypeReferenceNode(factory.createIdentifier("Array"), [factory.createUnionTypeNode([
otmCreateSingleOperationNode,
otmRemoveOperationNode
])])
])));
break;
}
case 'excludeRemove': {
propertySignatures2.push(factory.createPropertySignature(undefined, factory.createIdentifier(identifier), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([
otmUpdateOperationNode,
otmCreateMultipleOperationNode,
factory.createTypeReferenceNode(factory.createIdentifier("Array"), [factory.createUnionTypeNode([
otmCreateSingleOperationNode,
otmUpdateOperationNode
])])
])));
break;
}
case 'appendOnly': {
propertySignatures2.push(factory.createPropertySignature(undefined, factory.createIdentifier(identifier), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([
otmCreateMultipleOperationNode,
factory.createTypeReferenceNode(factory.createIdentifier("Array"), [factory.createUnionTypeNode([
otmCreateSingleOperationNode
])])
])));
break;
}
case 'readOnly': {
break;
}
default: {
(0, assert_1.default)(false);
}
}
}
});
}
}
if (propertySignatures2.length > 0) {
adNodes.push(factory.createTypeLiteralNode(propertySignatures2));
}
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("UpdateOperationData"), undefined, factory.createIntersectionTypeNode(adNodes)));
// UpdateOperation
const actionTypeNodes = [factory.createLiteralTypeNode(factory.createStringLiteral("update"))];
if (ActionAsts[entity]) {
actionTypeNodes.push(factory.createTypeReferenceNode('ParticularAction'));
}
if (Schema[entity].relations || entity === 'User') {
actionTypeNodes.push(factory.createTypeReferenceNode('RelationAction'));
}
if (process.env.COMPLING_AS_LIB) {
actionTypeNodes.push(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword));
}
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("UpdateOperation"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("OakOperation"), [
factory.createUnionTypeNode(actionTypeNodes),
factory.createTypeReferenceNode(factory.createIdentifier("UpdateOperationData")),
factory.createTypeReferenceNode(factory.createIdentifier("Filter"), undefined),
factory.createTypeReferenceNode(factory.createIdentifier("Sorter"), undefined)
])));
// RemoveOperationData
adNodes = [
factory.createTypeLiteralNode([])
];
if (manyToOneSet) {
/**
* remove的多对一有两种case
* 如果关联对象动作是update或者remove则关联对象的filter由对象(的原行!注意这里的外键是不能变的!)决定其主键
* 见cascadeStore
*/
const upsertOneNodes = [];
for (const one of manyToOneSet) {
if (one[1] !== 'entity') {
if (!Schema[one[0]].static) {
switch (Schema[one[0]].actionType) {
case 'crud': {
upsertOneNodes.push(factory.createUnionTypeNode([
factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier(one[1]), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([
factory.createTypeReferenceNode(createForeignRef(entity, one[0], 'UpdateOperation')),
factory.createTypeReferenceNode(createForeignRef(entity, one[0], 'RemoveOperation'))
]))
])
]));
break;
}
case 'excludeUpdate': {
upsertOneNodes.push(factory.createUnionTypeNode([
factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier(one[1]), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(createForeignRef(entity, one[0], 'RemoveOperation')))
])
]));
break;
}
case 'excludeRemove': {
upsertOneNodes.push(factory.createUnionTypeNode([
factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier(one[1]), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(createForeignRef(entity, one[0], 'UpdateOperation')))
])
]));
break;
}
case 'appendOnly':
case 'readOnly': {
break;
}
default: {
(0, assert_1.default)(false);
}
}
}
}
}
const reverseOneNodes = [];
if (ReversePointerRelations[entity]) {
const refEntityLitrals = [];
for (const one of ReversePointerRelations[entity]) {
refEntityLitrals.push(factory.createLiteralTypeNode(factory.createStringLiteral(`${(0, string_1.firstLetterLowerCase)(one)}`)));
if (!Schema[one].static) {
switch (Schema[one].actionType) {
case 'crud': {
reverseOneNodes.push(factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier((0, string_1.firstLetterLowerCase)(one)), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([
factory.createTypeReferenceNode(createForeignRef(entity, one, 'UpdateOperation')),
factory.createTypeReferenceNode(createForeignRef(entity, one, 'RemoveOperation'))
]))
]));
break;
}
case 'excludeUpdate': {
reverseOneNodes.push(factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier((0, string_1.firstLetterLowerCase)(one)), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(createForeignRef(entity, one, 'RemoveOperation')))
]));
break;
}
case 'excludeRemove': {
reverseOneNodes.push(factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier((0, string_1.firstLetterLowerCase)(one)), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(createForeignRef(entity, one, 'UpdateOperation')))
]));
break;
}
case 'appendOnly':
case 'readOnly': {
break;
}
default: {
(0, assert_1.default)(false);
}
}
}
}
if (process.env.COMPLING_AS_LIB) {
reverseOneNodes.push(factory.createTypeLiteralNode([
factory.createIndexSignature(undefined, [factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier("k"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), undefined)], factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword))
]));
}
}
if (upsertOneNodes.length > 0) {
adNodes.push(factory.createIntersectionTypeNode(upsertOneNodes));
}
if (reverseOneNodes.length > 0) {
adNodes.push(factory.createUnionTypeNode(reverseOneNodes));
}
}
/**
* remove的同时进行cascade update或者cascade remove感觉用触发器会更自然因为在用户界面上似乎不会有对应的操作。
* 这部分代码暂时封闭 by Xc 20220501
**/
/* const propertySignatures3: ts.TypeElement[] = [];
if (process.env.COMPLING_AS_LIB) {
propertySignatures3.push(
factory.createIndexSignature(
undefined,
undefined,
[factory.createParameterDeclaration(
undefined,
undefined,
undefined,
factory.createIdentifier("k"),
undefined,
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
undefined
)],
factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
)
);
}
if (oneToManySet) {
for (const entityName in foreignKeySet) {
const entityNameLc = firstLetterLowerCase(entityName);
foreignKeySet[entityName].forEach(
(foreignKey) => {
const identifier = `${entityNameLc}s$${foreignKey}`;
propertySignatures3.push(
factory.createPropertySignature(
undefined,
factory.createIdentifier(identifier),
factory.createToken(ts.SyntaxKind.QuestionToken),
factory.createUnionTypeNode([
factory.createTypeReferenceNode(
createForeignRef(entity, entityName, 'UpdateOperation'),
undefined
),
factory.createTypeReferenceNode(
createForeignRef(entity, entityName, 'RemoveOperation'),
undefined
),
factory.createTypeReferenceNode(
factory.createIdentifier("Array"),
[factory.createUnionTypeNode([
factory.createTypeReferenceNode(
createForeignRef(entity, entityName, 'UpdateOperation'),
undefined
),
factory.createTypeReferenceNode(
createForeignRef(entity, entityName, 'RemoveOperation'),
undefined
)
])]
)
])
)
);
}
);
}
}
if (propertySignatures3.length > 0) {
adNodes.push(
factory.createTypeLiteralNode(
propertySignatures3
)
);
} */
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("RemoveOperationData"), undefined, factory.createIntersectionTypeNode(adNodes)));
// RemoveOperation
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("RemoveOperation"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("OakOperation"), [
factory.createLiteralTypeNode(factory.createStringLiteral("remove")),
factory.createTypeReferenceNode(factory.createIdentifier("RemoveOperationData"), undefined),
factory.createTypeReferenceNode(factory.createIdentifier("Filter"), undefined),
factory.createTypeReferenceNode(factory.createIdentifier("Sorter"), undefined)
])));
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("Operation"), undefined, factory.createUnionTypeNode([
factory.createTypeReferenceNode(factory.createIdentifier("CreateOperation"), undefined),
factory.createTypeReferenceNode(factory.createIdentifier("UpdateOperation"), undefined),
factory.createTypeReferenceNode(factory.createIdentifier("RemoveOperation"), undefined)
])));
}
const initialStatements = (level) => [
// import { String, Text, Int, SpecificKey } from 'oak-domain/types/DataType';
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier('PrimaryKey')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('ForeignKey')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('JsonProjection'))
])), factory.createStringLiteral(`${(0, env_1.TYPE_PATH_IN_OAK_DOMAIN)(level)}DataType`)),
/* import {
Q_DateValue, Q_LogicKey, Q_NumberValue, FnCallKey, FnCallValue,
Q_StringValue, Q_FullTextKey, Q_FullTextValue, FnCallValueAs,
Q_BooleanValue,
} from 'oak-domain/types/Demand'; */
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Q_DateValue')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Q_BooleanValue')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Q_NumberValue')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Q_StringValue')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Q_EnumValue')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('NodeId')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('MakeFilter')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('FulltextFilter')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('ExprOp')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('ExpressionKey')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('JsonFilter')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('SubQueryPredicateMetadata')),
])), factory.createStringLiteral(`${(0, env_1.TYPE_PATH_IN_OAK_DOMAIN)(level)}Demand`)),
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier("OneOf")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("ValueOf"))
])), factory.createStringLiteral(`${(0, env_1.TYPE_PATH_IN_OAK_DOMAIN)(level)}Polyfill`)),
// import * as SubQuery from '../_SubQuery';
/* factory.createImportDeclaration(
undefined,
undefined,
factory.createImportClause(
false,
undefined,
factory.createNamespaceImport(factory.createIdentifier("SubQuery"))
),
factory.createStringLiteral("../_SubQuery")
), */
// import { Filter as OakFilter } from 'oak-domain/src/types/Entity';
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier("FormCreateData")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("FormUpdateData")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("DeduceAggregation")),
factory.createImportSpecifier(false, factory.createIdentifier("Operation"), factory.createIdentifier("OakOperation")),
factory.createImportSpecifier(false, factory.createIdentifier("Selection"), factory.createIdentifier("OakSelection")),
factory.createImportSpecifier(false, factory.createIdentifier("MakeAction"), factory.createIdentifier("OakMakeAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("AggregationResult")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("EntityShape")),
])), factory.createStringLiteral(`${(0, env_1.TYPE_PATH_IN_OAK_DOMAIN)(level)}Entity`), undefined)
];
const initialStatements2 = () => [
// import { String, Text, Int, SpecificKey } from 'oak-domain/types/DataType';
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier('PrimaryKey')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('ForeignKey')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('JsonProjection'))
])), factory.createStringLiteral(`${(0, env_1.TYPE_PATH_IN_OAK_DOMAIN)()}DataType`)),
/* import {
Q_DateValue, Q_LogicKey, Q_NumberValue, FnCallKey, FnCallValue,
Q_StringValue, Q_FullTextKey, Q_FullTextValue, FnCallValueAs,
Q_BooleanValue,
} from 'oak-domain/types/Demand'; */
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Q_DateValue')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Q_BooleanValue')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Q_NumberValue')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Q_StringValue')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('Q_EnumValue')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('NodeId')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('MakeFilter')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('FulltextFilter')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('ExprOp')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('ExpressionKey')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('JsonFilter')),
])), factory.createStringLiteral(`${(0, env_1.TYPE_PATH_IN_OAK_DOMAIN)()}Demand`)),
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, factory.createIdentifier("MakeAction"), factory.createIdentifier("OakMakeAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("EntityShape")),
])), factory.createStringLiteral(`${(0, env_1.TYPE_PATH_IN_OAK_DOMAIN)()}Entity`), undefined)
];
const initialStatements3 = (level) => [
// import { String, Text, Int, SpecificKey } from 'oak-domain/types/DataType';
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier('PrimaryKey')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('ForeignKey')),
])), factory.createStringLiteral(`${(0, env_1.TYPE_PATH_IN_OAK_DOMAIN)(level)}DataType`)),
/* import {
Q_DateValue, Q_LogicKey, Q_NumberValue, FnCallKey, FnCallValue,
Q_StringValue, Q_FullTextKey, Q_FullTextValue, FnCallValueAs,
Q_BooleanValue,
} from 'oak-domain/types/Demand'; */
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier('NodeId')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('MakeFilter')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('FulltextFilter')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('ExprOp')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('ExpressionKey')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('JsonFilter')),
factory.createImportSpecifier(false, undefined, factory.createIdentifier('SubQueryPredicateMetadata')),
])), factory.createStringLiteral(`${(0, env_1.TYPE_PATH_IN_OAK_DOMAIN)(level)}Demand`)),
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier("FormCreateData")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("FormUpdateData")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("DeduceAggregation")),
factory.createImportSpecifier(false, factory.createIdentifier("Operation"), factory.createIdentifier("OakOperation")),
factory.createImportSpecifier(false, factory.createIdentifier("Selection"), factory.createIdentifier("OakSelection")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("AggregationResult")),
])), factory.createStringLiteral(`${(0, env_1.TYPE_PATH_IN_OAK_DOMAIN)(level)}Entity`), undefined)
];
function outputSubQuery(outputDir, printer) {
const statements = [];
if (process.env.COMPLING_AS_LIB) {
}
for (const entity in Schema) {
// import * as User from '../User/Schema';
statements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamespaceImport(factory.createIdentifier(entity))), factory.createStringLiteral(`./${entity}/Schema`)));
}
const entities = (0, lodash_1.keys)(Schema);
// 每个有manyToOne的Entity都会输出${One}IdSubQuery
for (const one in Schema) {
const identifier = `${one}IdSubQuery`;
const fromEntites = OneToMany[one] ? (0, lodash_1.uniq)(OneToMany[one]
/* .filter(
([e, f]) => f !== 'entity'
) */ .map(([e]) => e)) : [];
fromEntites.push(one);
const inUnionTypeNode = fromEntites.map(ele => factory.createIntersectionTypeNode([
factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(ele), factory.createIdentifier(identifier)), undefined),
factory.createTypeLiteralNode([factory.createPropertySignature(undefined, factory.createIdentifier("entity"), undefined, factory.createLiteralTypeNode(factory.createStringLiteral((0, string_1.firstLetterLowerCase)(ele))))])
]));
if (process.env.COMPLING_AS_LIB) {
// 如果是建立 base这里要加上额外可能的对象信息
inUnionTypeNode.push(factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword));
}
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier(identifier), undefined, factory.createMappedTypeNode(undefined, factory.createTypeParameterDeclaration(undefined, factory.createIdentifier("K"), factory.createUnionTypeNode([
factory.createLiteralTypeNode(factory.createStringLiteral("$in")),
factory.createLiteralTypeNode(factory.createStringLiteral("$nin"))
]), undefined), undefined, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode(inUnionTypeNode), undefined)));
}
const resultFile = ts.createSourceFile("someFileName.ts", "", ts.ScriptTarget.Latest, /*setParentNodes*/ false, ts.ScriptKind.TS);
const result = printer.printNode(ts.EmitHint.Unspecified, factory.createSourceFile(statements, factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None), resultFile);
const fileName = path_1.default.join(outputDir, '_SubQuery.ts');
(0, fs_1.writeFileSync)(fileName, result, { flag: 'w' });
}
function outputEntityDict(outputDir, printer) {
const statements = [];
const propertySignatures = [];
for (const entity in Schema) {
// import * as User from '../User/Schema';
statements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, factory.createIdentifier("EntityDef"), factory.createIdentifier(entity))])), factory.createStringLiteral(`./${entity}/Schema`)));
const entityLc = (0, string_1.firstLetterLowerCase)(entity);
propertySignatures.push(factory.createPropertySignature(undefined, factory.createIdentifier(entityLc), undefined, factory.createTypeReferenceNode(entity)));
}
if ( /* process.env.COMPLING_AS_LIB */false) {
statements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, undefined, factory.createIdentifier("EntityDef"))])), factory.createStringLiteral("../types/Entity"), undefined), factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("EntityDict"), undefined, factory.createIntersectionTypeNode([
factory.createTypeLiteralNode(propertySignatures),
factory.createTypeLiteralNode([
factory.createIndexSignature(undefined, [factory.createParameterDeclaration(undefined, undefined, factory.createIdentifier("E"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), undefined)], factory.createTypeReferenceNode(factory.createIdentifier("EntityDef"), undefined))
])
])));
}
else {
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("EntityDict"), undefined, factory.createTypeLiteralNode(propertySignatures)));
}
const resultFile = ts.createSourceFile("someFileName.ts", "", ts.ScriptTarget.Latest, /*setParentNodes*/ false, ts.ScriptKind.TS);
const result = printer.printNode(ts.EmitHint.Unspecified, factory.createSourceFile(statements, factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None), resultFile);
const fileName = path_1.default.join(outputDir, 'EntityDict.ts');
(0, fs_1.writeFileSync)(fileName, result, { flag: 'w' });
}
function outputSchema(outputDir, printer) {
for (const entity in Schema) {
const { importAttrFrom } = Schema[entity];
const statements = initialStatements();
if (ActionAsts[entity]) {
const { importStateFrom } = ActionAsts[entity];
const fromLocalActionSpecifiers = ['Action', 'ParticularAction'];
const fromExtenalStates = {};
for (const state in importStateFrom) {
(0, assert_1.default)(state.endsWith('State'), `${state} should end with State`);
if (importStateFrom[state][0] === './') {
// 本地定义的State从 ./Action 中获取
fromLocalActionSpecifiers.push(state);
}
else {
// 否则从原来的import specifiers当中获取
// todo 在additionalImports中如果有则去重
const [from, propertyName] = importStateFrom[state];
if (fromExtenalStates[from]) {
fromExtenalStates[from].push([state, propertyName]);
}
else {
fromExtenalStates[from] = [[state, propertyName]];
}
}
}
statements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports(fromLocalActionSpecifiers.map(ele => factory.createImportSpecifier(false, undefined, factory.createIdentifier(ele))))), factory.createStringLiteral('./Action'), undefined), factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier("RelationAction")),
])), factory.createStringLiteral((0, env_1.ACTION_CONSTANT_IN_OAK_DOMAIN)()), undefined));
for (const external in fromExtenalStates) {
statements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports(fromExtenalStates[external].map(ele => factory.createImportSpecifier(false, ele[1] === undefined ? undefined : factory.createIdentifier(ele[1]), factory.createIdentifier(ele[0]))))), factory.createStringLiteral(external), undefined));
}
}
else {
statements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier("GenericAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("AppendOnlyAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("ReadOnlyAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("ExcludeUpdateAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("ExcludeRemoveAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("RelationAction")),
])), factory.createStringLiteral((0, env_1.ACTION_CONSTANT_IN_OAK_DOMAIN)()), undefined));
}
// 从外部引入的属性
const fromExternalImportAttrs = {};
for (const attr in importAttrFrom) {
const [from, propertyName] = importAttrFrom[attr];
if (fromExternalImportAttrs[from]) {
fromExternalImportAttrs[from].push([attr, propertyName]);
}
else {
fromExternalImportAttrs[from] = [[attr, propertyName]];
}
}
for (const external in fromExternalImportAttrs) {
statements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports(fromExternalImportAttrs[external].map(ele => factory.createImportSpecifier(false, ele[1] === undefined ? undefined : factory.createIdentifier(ele[1]), factory.createIdentifier(ele[0]))))), factory.createStringLiteral(external), undefined));
}
// Relation定义加入
/* if (typeof Schema[entity].hasRelationDef === 'object' && ts.isTypeAliasDeclaration(Schema[entity].hasRelationDef as ts.Node)) {
const node = Schema[entity].hasRelationDef as ts.TypeAliasDeclaration;
statements.push(
factory.updateTypeAliasDeclaration(
node,
undefined,
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
node.name,
node.typeParameters,
node.type
)
);
} */
constructSchema(statements, entity);
constructFilter(statements, entity);
constructProjection(statements, entity);
constructSorter(statements, entity);
constructOperations(statements, entity);
constructQuery(statements, entity);
// 现在FullAttrs和NativeAttrs似乎没什么用还会引起递归
// constructFullAttrs(statements, entity);
const makeActionArguments = [];
if (ActionAsts[entity]) {
makeActionArguments.push(factory.createTypeReferenceNode('Action'));
}
else {
makeActionArguments.push(factory.createTypeReferenceNode(OriginActionDict[Schema[entity].actionType]));
}
if (Schema[entity].relations || entity === 'User') {
makeActionArguments.push(factory.createTypeReferenceNode('RelationAction'));
}
const actionTypeNode = factory.createTypeReferenceNode(factory.createIdentifier('OakMakeAction'), makeActionArguments.length === 1 ? makeActionArguments : [factory.createUnionTypeNode(makeActionArguments)]);
const EntityDefAttrs = [
factory.createPropertySignature(undefined, factory.createIdentifier("Schema"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("Schema"), undefined)),
factory.createPropertySignature(undefined, factory.createIdentifier("OpSchema"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("OpSchema"), undefined)),
factory.createPropertySignature(undefined, factory.createIdentifier("Action"), undefined, process.env.COMPLING_AS_LIB ?
factory.createUnionTypeNode([
actionTypeNode,
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
]) : actionTypeNode),
factory.createPropertySignature(undefined, factory.createIdentifier("Selection"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("Selection"), undefined)),
factory.createPropertySignature(undefined, factory.createIdentifier("Aggregation"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("Aggregation"), undefined)),
factory.createPropertySignature(undefined, factory.createIdentifier("Operation"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("Operation"), undefined)),
factory.createPropertySignature(undefined, factory.createIdentifier("Create"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("CreateOperation"), undefined)),
factory.createPropertySignature(undefined, factory.createIdentifier("Update"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("UpdateOperation"), undefined)),
factory.createPropertySignature(undefined, factory.createIdentifier("Remove"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("RemoveOperation"), undefined)),
factory.createPropertySignature(undefined, factory.createIdentifier("CreateSingle"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("CreateSingleOperation"), undefined)),
factory.createPropertySignature(undefined, factory.createIdentifier("CreateMulti"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("CreateMultipleOperation"), undefined)),
];
if (ActionAsts[entity]) {
EntityDefAttrs.push(factory.createPropertySignature(undefined, factory.createIdentifier("ParticularAction"), undefined, factory.createTypeReferenceNode(factory.createIdentifier('ParticularAction'), undefined)));
}
/* if (typeof Schema[entity].hasRelationDef === 'object' && ts.isTypeAliasDeclaration(Schema[entity].hasRelationDef as ts.Node)) {
EntityDefAttrs.push(
factory.createPropertySignature(
undefined,
factory.createIdentifier("Relation"),
undefined,
factory.createTypeReferenceNode(
factory.createIdentifier('Relation'),
undefined
)
)
);
} */
statements.push(factory.createTypeAliasDeclaration([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("EntityDef"), undefined, factory.createTypeLiteralNode(EntityDefAttrs)));
// 现在支持Schema extends其继承的对象解析来自另一个文件故不能再用原sourceFile来生成否则printer会用sourceFile中的originText去取stringLiteral
const result = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray(statements), undefined);
const fileName = path_1.default.join(outputDir, entity, 'Schema.ts');
(0, fs_1.writeFileSync)(fileName, result, { flag: 'w' });
}
}
function _outputBaseSchema(outputDir, printer) {
for (const entity in Schema) {
const { importAttrFrom } = Schema[entity];
const statements = initialStatements2();
if (ActionAsts[entity]) {
const { importStateFrom } = ActionAsts[entity];
const fromLocalActionSpecifiers = ['Action', 'ParticularAction'];
const fromExtenalStates = {};
for (const state in importStateFrom) {
(0, assert_1.default)(state.endsWith('State'), `${state} should end with State`);
if (importStateFrom[state][0] === './') {
// 本地定义的State从 ./Action 中获取
fromLocalActionSpecifiers.push(state);
}
else {
// 否则从原来的import specifiers当中获取
// todo 在additionalImports中如果有则去重
const [from, propertyName] = importStateFrom[state];
if (fromExtenalStates[from]) {
fromExtenalStates[from].push([state, propertyName]);
}
else {
fromExtenalStates[from] = [[state, propertyName]];
}
}
}
statements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports(fromLocalActionSpecifiers.map(ele => factory.createImportSpecifier(false, undefined, factory.createIdentifier(ele))))), factory.createStringLiteral('./Action'), undefined), factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier("RelationAction")),
])), factory.createStringLiteral((0, env_1.ACTION_CONSTANT_IN_OAK_DOMAIN)()), undefined));
for (const external in fromExtenalStates) {
statements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports(fromExtenalStates[external].map(ele => factory.createImportSpecifier(false, ele[1] === undefined ? undefined : factory.createIdentifier(ele[1]), factory.createIdentifier(ele[0]))))), factory.createStringLiteral(external), undefined));
}
}
else {
statements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier("GenericAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("AppendOnlyAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("ReadOnlyAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("ExcludeUpdateAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("ExcludeRemoveAction")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("RelationAction")),
])), factory.createStringLiteral((0, env_1.ACTION_CONSTANT_IN_OAK_DOMAIN)()), undefined));
}
// 从外部引入的属性
const fromExternalImportAttrs = {};
for (const attr in importAttrFrom) {
// const [from, propertyName] = importAttrFrom[attr];
// if (fromExternalImportAttrs[from]) {
// fromExternalImportAttrs[from].push([attr, propertyName]);
// }
// else {
// fromExternalImportAttrs[from] = [[attr, propertyName]];
// }
const [from, propertyName, sourceFilePath, relative] = importAttrFrom[attr];
// ===== 在这里进行路径转换 =====
const outputFilePath = path_1.default.join(outputDir, entity, '_baseSchema.ts'); // 输出文件路径
// 使用路径解析算法计算新的导入路径
const newImportPath = resolveCompiledImportPath(path_1.default.relative(process.cwd(), sourceFilePath), path_1.default.relative(process.cwd(), outputFilePath), from, // 原始导入路径
".", relative);
// console.log('resolve import path:', {
// sourceFilePath: PathLib.relative(process.cwd(), sourceFilePath),
// outputFilePath: PathLib.relative(process.cwd(), outputFilePath),
// from,
// newImportPath,
// });
if (fromExternalImportAttrs[newImportPath]) {
fromExternalImportAttrs[newImportPath].push([attr, propertyName]);
}
else {
fromExternalImportAttrs[newImportPath] = [[attr, propertyName]];
}
}
for (const external in fromExternalImportAttrs) {
statements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports(fromExternalImportAttrs[external].map(ele => factory.createImportSpecifier(false, ele[1] === undefined ? undefined : factory.createIdentifier(ele[1]), factory.createIdentifier(ele[0]))))), factory.createStringLiteral(external), undefined));
}
_constructOpSchema(statements, entity);
_constructOpFilter(statements, entity);
_constructOpProjection(statements, entity);
_constructOpSortAttr(statements, entity);
const makeActionArguments = [];
const makeUpdateActionArguments = [factory.createLiteralTypeNode(factory.createStringLiteral('update'))];
if (ActionAsts[entity]) {
makeActionArguments.push(factory.createTypeReferenceNode('Action'));
makeUpdateActionArguments.push(factory.createTypeReferenceNode('ParticularAction'));
}
else {
makeActionArguments.push(factory.createTypeReferenceNode(OriginActionDict[Schema[entity].actionType]));
}
if (Schema[entity].relations || entity === 'User') {
makeActionArguments.push(factory.createTypeReferenceNode('RelationAction'));
}
if (process.env.COMPLING_AS_LIB) {
makeActionArguments.push(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword));
makeUpdateActionArguments.push(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword));
}
statements.push(factory.createTypeAliasDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("OpAction"), undefined, factory.createTypeReferenceNode(factory.createIdentifier('OakMakeAction'), [factory.createUnionTypeNode(makeActionArguments)])), factory.createTypeAliasDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("OpUpdateAction"), undefined, factory.createUnionTypeNode(makeUpdateActionArguments)));
// 现在支持Schema extends其继承的对象解析来自另一个文件故不能再用原sourceFile来生成否则printer会用sourceFile中的originText去取stringLiteral
const result = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray(statements), undefined);
const fileName = path_1.default.join(outputDir, entity, '_baseSchema.ts');
(0, fs_1.writeFileSync)(fileName, result, { flag: 'w' });
}
}
function outputAction(outputDir, printer) {
const actionDictStatements = [];
const propertyAssignments = [];
for (const entity in ActionAsts) {
const { sourceFile, statements, importActionFrom, importStateFrom, importActionDefFrom, actionDefNames } = ActionAsts[entity];
const importStatements = [];
const fromExternalImports = {};
for (const state in importStateFrom) {
(0, assert_1.default)(state.endsWith('State'), `${state} should end with State`);
const [from, propertyName] = importStateFrom[state];
if (from !== './') {
if (fromExternalImports[from]) {
fromExternalImports[from].push([state, propertyName]);
}
else {
fromExternalImports[from] = [[state, propertyName]];
}
}
}
for (const action in importActionFrom) {
(0, assert_1.default)(action.endsWith('Action'), `${action} should end with Action`);
const [from, propertyName] = importActionFrom[action];
if (from !== './') {
if (fromExternalImports[from]) {
fromExternalImports[from].push([action, propertyName]);
}
else {
fromExternalImports[from] = [[action, propertyName]];
}
}
}
for (const def in importActionDefFrom) {
(0, assert_1.default)(def.endsWith('ActionDef'), `${def} should end with ActionDef`);
const [from, propertyName] = importActionDefFrom[def];
if (from !== './') {
if (fromExternalImports[from]) {
fromExternalImports[from].push([def, propertyName]);
}
else {
fromExternalImports[from] = [[def, propertyName]];
}
}
}
for (const external in fromExternalImports) {
statements.splice(0, 0, factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports(fromExternalImports[external].map(ele => factory.createImportSpecifier(false, ele[1] === undefined ? undefined : factory.createIdentifier(ele[1]), factory.createIdentifier(ele[0]))))), factory.createStringLiteral(external), undefined));
}
statements.push(factory.createVariableStatement([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([factory.createVariableDeclaration(factory.createIdentifier("actionDefDict"), undefined, undefined, factory.createObjectLiteralExpression(actionDefNames.map(ele => factory.createPropertyAssignment(factory.createIdentifier(`${ele}State`), factory.createIdentifier(`${(0, string_1.firstLetterUpperCase)(ele)}ActionDef`))), true))], ts.NodeFlags.Const)));
/* const result = printer.printNode(
ts.EmitHint.Unspecified,
factory.createSourceFile(statements,
factory.createToken(ts.SyntaxKind.EndOfFileToken),
ts.NodeFlags.None),
sourceFile
); */
// 这里如果用printNodestringLiteral的输出始终有个bug不知道如何处理
const result = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray(importStatements.concat(statements)), sourceFile);
const filename = path_1.default.join(outputDir, entity, 'Action.ts');
(0, fs_1.writeFileSync)(filename, result, { flag: 'w' });
actionDictStatements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, factory.createIdentifier("actionDefDict"), factory.createIdentifier((0, string_1.firstLetterLowerCase)(entity)))])), factory.createStringLiteral(`./${entity}/Action`)));
propertyAssignments.push(factory.createShorthandPropertyAssignment(factory.createIdentifier((0, string_1.firstLetterLowerCase)(entity))));
}
actionDictStatements.push(factory.createVariableStatement([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([factory.createVariableDeclaration(factory.createIdentifier("actionDefDict"), undefined, undefined, factory.createObjectLiteralExpression(propertyAssignments, true))], ts.NodeFlags.Const)));
const resultFile = ts.createSourceFile("someFileName.ts", "", ts.ScriptTarget.Latest, /*setParentNodes*/ false, ts.ScriptKind.TS);
const result = printer.printNode(ts.EmitHint.Unspecified, factory.createSourceFile(actionDictStatements, factory.createToken(ts.SyntaxKind.EndOfFileToken), ts.NodeFlags.None), resultFile);
const fileName = path_1.default.join(outputDir, 'ActionDefDict.ts');
(0, fs_1.writeFileSync)(fileName, result, { flag: 'w' });
}
function constructAttributes(entity) {
const { schemaAttrs, enumAttributes } = Schema[entity];
const { [entity]: manyToOneSet } = ManyToOne;
const result = [];
schemaAttrs.forEach((attr) => {
const attrAssignments = [];
const { name, type, questionToken: allowNull } = attr;
if (!allowNull) {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("notNull"), factory.createTrue()));
}
let name2 = name;
if (ts.isTypeReferenceNode(type)) {
const { typeName, typeArguments } = type;
if (ts.isIdentifier(typeName)) {
const { text } = typeName;
switch (text) {
case 'String': {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("varchar")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([
factory.createPropertyAssignment(factory.createIdentifier("length"), factory.createNumericLiteral(typeArguments[0].literal.text)),
], true)));
// 如果是entity在这里处理一下ref
if (ts.isIdentifier(name) && name.text === 'entity') {
const mtoRelations = ReversePointerRelations[entity];
if (mtoRelations) {
const mtoEntities = mtoRelations.map(ele => (0, string_1.firstLetterLowerCase)(ele));
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("ref"), factory.createArrayLiteralExpression(mtoEntities.map(ele => factory.createStringLiteral(ele)), false)));
}
}
break;
}
case 'Text':
case 'Image':
case 'File': {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("text")));
break;
}
case 'Int':
case 'Uint': {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("int")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([
factory.createPropertyAssignment(factory.createIdentifier("width"), factory.createNumericLiteral(typeArguments[0].literal.text)),
factory.createPropertyAssignment(factory.createIdentifier("signed"), text === 'Uint' ? factory.createFalse() : factory.createTrue())
], true)));
break;
}
case 'Double':
case 'Float':
case 'Decimal': {
if (['Double', 'Float'].includes(text)) {
console.warn(`${entity}对象中还有${text}类型定义现在统一用Decimal进行存储`);
}
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("decimal")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([
factory.createPropertyAssignment(factory.createIdentifier("precision"), factory.createNumericLiteral(typeArguments[0].literal.text)),
factory.createPropertyAssignment(factory.createIdentifier("scale"), factory.createNumericLiteral(typeArguments[1].literal.text))
], true)));
break;
}
case 'Boolean': {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("boolean")));
break;
}
case 'Price': {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("money")));
break;
}
case 'Datetime': {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("datetime")));
break;
}
case 'SingleGeo':
case 'Geo': {
// object类型暂不支持查询
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("geometry")));
break;
}
case 'Object': {
// object类型暂不支持查询
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("object")));
break;
}
default: {
const text2 = text === 'Schema' ? entity : text;
const manyToOneItem = manyToOneSet && manyToOneSet.find(([refEntity, attrName]) => refEntity === text2 && attrName === attrName);
if (manyToOneItem) {
// 外键
name2 = factory.createIdentifier(`${name.text}Id`);
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("ref")), factory.createPropertyAssignment(factory.createIdentifier("ref"), factory.createStringLiteral((0, string_1.firstLetterLowerCase)(text2))));
}
else {
if (enumAttributes && enumAttributes[name.text]) {
attrAssignments.push(factory.createPropertyAssignment('type', factory.createStringLiteral("enum")), factory.createPropertyAssignment('enumeration', factory.createArrayLiteralExpression(enumAttributes[name.text].map(ele => factory.createStringLiteral(ele)))));
}
else {
// todo 引用的非string定义目前没有处理int类型的引用等遇到了再处理
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("object")));
}
}
}
}
}
else {
(0, assert_1.default)(false);
}
}
else {
if (ts.isUnionTypeNode(type)) {
if (ts.isLiteralTypeNode(type.types[0])) {
if (ts.isStringLiteral(type.types[0].literal)) {
(0, assert_1.default)(enumAttributes && enumAttributes[name.text], `${entity}对象中的${name.text}属性没有定义enumAttributes`);
attrAssignments.push(factory.createPropertyAssignment('type', factory.createStringLiteral("enum")), factory.createPropertyAssignment('enumeration', factory.createArrayLiteralExpression(enumAttributes[name.text].map(ele => factory.createStringLiteral(ele)))));
}
else {
(0, assert_1.default)(ts.isNumericLiteral(type.types[0].literal), `${entity}对象中的${type.types[0].literal.getText()}属性不是数字`);
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("int")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([
factory.createPropertyAssignment(factory.createIdentifier("width"), factory.createNumericLiteral(env_1.INT_LITERL_DEFAULT_WIDTH))
], true)));
}
}
else {
// 否则是本地规定的shape直接用object
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("object")));
}
}
else {
if (ts.isLiteralTypeNode(type)) {
if (ts.isStringLiteral(type.literal)) {
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("varchar")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([factory.createPropertyAssignment(factory.createIdentifier("length"), factory.createNumericLiteral(env_1.STRING_LITERAL_MAX_LENGTH))], true)));
}
else {
(0, assert_1.default)(ts.isNumericLiteral(type.literal), `${entity}对象中的${name.text}属性不是数字`);
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("precision")), factory.createPropertyAssignment(factory.createIdentifier("params"), factory.createObjectLiteralExpression([
factory.createPropertyAssignment(factory.createIdentifier("precision"), factory.createNumericLiteral(env_1.NUMERICAL_LITERL_DEFAULT_PRECISION)),
factory.createPropertyAssignment(factory.createIdentifier("scale"), factory.createNumericLiteral(env_1.NUMERICAL_LITERL_DEFAULT_SCALE))
], true)));
}
}
else {
// 否则是本地规定的shape直接用object
attrAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("type"), factory.createStringLiteral("object")));
}
}
}
result.push(factory.createPropertyAssignment(name2, factory.createObjectLiteralExpression(attrAssignments, true)));
});
return result;
}
exports.constructAttributes = constructAttributes;
function translateLocaleObject(locale) {
const result = {};
locale.properties.forEach((ele) => {
(0, assert_1.default)(ts.isPropertyAssignment(ele) && (ts.isIdentifier(ele.name) || ts.isStringLiteral(ele.name)), `locale对象中的属性定义不正确`);
const name = ele.name.text;
if (ts.isStringLiteral(ele.initializer)) {
result[name] = ele.initializer.text;
}
else if (ts.isObjectLiteralExpression(ele.initializer)) {
const subObj = translateLocaleObject(ele.initializer);
result[name] = subObj;
}
else {
throw new Error(`locale对象中的属性${name}的定义不正确`);
}
});
return result;
}
exports.translateLocaleObject = translateLocaleObject;
function outputLocale(outputDir, printer) {
const locales = {};
const entities = [];
for (const entity in Schema) {
const { locale, sourceFile } = Schema[entity];
if (locale) {
const { properties } = locale;
properties.forEach((ele) => {
(0, assert_1.default)(ts.isPropertyAssignment(ele) && (ts.isIdentifier(ele.name) || ts.isStringLiteral(ele.name)) && ts.isObjectLiteralExpression(ele.initializer), `${entity}对象中的locale属性定义不正确`);
const lng = ele.name.text;
const result = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray([
factory.createReturnStatement(ele.initializer)
]), sourceFile);
const data = Function(result)();
const filename = path_1.default.join(outputDir, entity, 'locales', `${lng}.json`);
(0, fs_1.writeFileSync)(filename, JSON.stringify(data, null, 2), { flag: 'w' });
if (locales[lng]) {
locales[lng].push(entity);
}
else {
locales[lng] = [entity];
}
});
entities.push(entity);
}
}
for (const lng in locales) {
if (locales[lng].length < entities.length) {
const lack = (0, lodash_1.difference)(entities, locales[lng]);
throw new Error(`${lng}语言定义中缺少了对象${lack.join(',')}的定义,请检查相应的定义文件`);
}
/* const statements: ts.Statement[] = locales[lng].map(
(entity) => factory.createImportDeclaration(
undefined,
undefined,
factory.createImportClause(
false,
factory.createIdentifier(firstLetterLowerCase(entity)),
undefined
),
factory.createStringLiteral(`../${entity}/locales/${lng}`),
undefined
)
);
statements.push(
factory.createExportAssignment(
undefined,
undefined,
undefined,
factory.createObjectLiteralExpression(
locales[lng].map(
ele => factory.createShorthandPropertyAssignment(
factory.createIdentifier(firstLetterLowerCase(ele)),
undefined
)
),
true
)
)
);
const result = printer.printList(
ts.ListFormat.SourceFileStatements,
factory.createNodeArray(statements),
ts.createSourceFile("someFileName.ts", "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS));
const filename = path.join(outputDir, '_locales', `${lng}.ts`);
writeFileSync(filename, result, { flag: 'w' }); */
}
}
function outputStorage(outputDir, printer) {
const importStatements = [
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, undefined, factory.createIdentifier("StorageSchema"))])), factory.createStringLiteral(`${(0, env_1.TYPE_PATH_IN_OAK_DOMAIN)(1)}Storage`), undefined),
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, undefined, factory.createIdentifier("EntityDict"))])), factory.createStringLiteral("./EntityDict"), undefined)
];
const entityAssignments = [];
for (const entity in Schema) {
const indexExpressions = [];
const { sourceFile, inModi, indexes, toModi, toLog, actionType, static: _static, relations } = Schema[entity];
const fromSchemaSpecifiers = [
factory.createImportSpecifier(false, undefined, factory.createIdentifier("OpSchema"))
];
/* if (relationHierarchy || reverseCascadeRelationHierarchy) {
fromSchemaSpecifiers.push(
factory.createImportSpecifier(
false,
undefined,
factory.createIdentifier("Relation")
)
);
} */
const statements = [
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, undefined, factory.createIdentifier("StorageDesc"))])), factory.createStringLiteral(`${(0, env_1.TYPE_PATH_IN_OAK_DOMAIN)()}Storage`), undefined),
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports(fromSchemaSpecifiers)), factory.createStringLiteral("./Schema"), undefined)
];
const needImportActions = [];
switch (actionType) {
case 'readOnly': {
needImportActions.push(factory.createImportSpecifier(false, factory.createIdentifier("readOnlyActions"), factory.createIdentifier("actions")));
break;
}
case 'appendOnly': {
needImportActions.push(factory.createImportSpecifier(false, factory.createIdentifier("appendOnlyActions"), factory.createIdentifier("actions")));
break;
}
case 'excludeUpdate': {
needImportActions.push(factory.createImportSpecifier(false, factory.createIdentifier("excludeUpdateActions"), factory.createIdentifier("actions")));
break;
}
default: {
if (ActionAsts[entity]) {
statements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, undefined, factory.createIdentifier("actions"))])), factory.createStringLiteral("./Action"), undefined));
}
else {
needImportActions.push(factory.createImportSpecifier(false, factory.createIdentifier("genericActions"), factory.createIdentifier("actions")));
}
}
}
if (Schema[entity].relations || entity === 'User') {
needImportActions.push(factory.createImportSpecifier(false, undefined, factory.createIdentifier("relationActions")));
}
if (needImportActions.length > 0) {
statements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports(needImportActions)), factory.createStringLiteral((0, env_1.ACTION_CONSTANT_IN_OAK_DOMAIN)()), undefined));
}
const propertyAssignments = [];
const attributes = constructAttributes(entity);
propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("attributes"), factory.createObjectLiteralExpression(attributes, true)));
if (indexes) {
indexExpressions.push(...indexes.elements);
}
if (toModi) {
propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("toModi"), factory.createTrue()));
}
if (toLog) {
propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("toLog"), factory.createTrue()));
}
if (inModi) {
propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("inModi"), factory.createTrue()));
}
if (_static || actionType === 'readOnly') {
propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("static"), factory.createTrue()));
}
propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("actionType"), factory.createStringLiteral(actionType)));
propertyAssignments.push(factory.createShorthandPropertyAssignment(factory.createIdentifier("actions"), undefined));
if (indexExpressions.length > 0) {
propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("indexes"), factory.createArrayLiteralExpression(indexExpressions, true)));
}
/* if (relationHierarchy) {
propertyAssignments.push(
factory.createPropertyAssignment(
factory.createIdentifier("relationHierarchy"),
relationHierarchy,
)
);
}
if (reverseCascadeRelationHierarchy) {
propertyAssignments.push(
factory.createPropertyAssignment(
factory.createIdentifier("reverseCascadeRelationHierarchy"),
reverseCascadeRelationHierarchy,
)
);
} */
if (relations) {
propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("relation"), factory.createArrayLiteralExpression(relations.map(ele => factory.createStringLiteral(ele)))));
}
const sdTypeArguments = [
factory.createTypeReferenceNode(factory.createIdentifier("OpSchema"), undefined)
];
statements.push(factory.createVariableStatement([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([factory.createVariableDeclaration(factory.createIdentifier("desc"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("StorageDesc"), sdTypeArguments), factory.createObjectLiteralExpression(propertyAssignments, true))], ts.NodeFlags.Const)));
const result = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray(statements), sourceFile);
const filename = path_1.default.join(outputDir, entity, 'Storage.ts');
(0, fs_1.writeFileSync)(filename, result, { flag: 'w' });
importStatements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, factory.createIdentifier("desc"), factory.createIdentifier(`${(0, string_1.firstLetterLowerCase)(entity)}Desc`))
])), factory.createStringLiteral(`./${entity}/Storage`), undefined));
entityAssignments.push(factory.createPropertyAssignment((0, string_1.firstLetterLowerCase)(entity), factory.createIdentifier(`${(0, string_1.firstLetterLowerCase)(entity)}Desc`)));
}
importStatements.push(factory.createVariableStatement([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([factory.createVariableDeclaration(factory.createIdentifier("storageSchema"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("StorageSchema"), [
factory.createTypeReferenceNode('EntityDict')
]), factory.createObjectLiteralExpression(entityAssignments, true))], ts.NodeFlags.Const)));
const result = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray(importStatements), ts.createSourceFile("someFileName.ts", "", ts.ScriptTarget.Latest, /*setParentNodes*/ false, ts.ScriptKind.TS));
const filename = path_1.default.join(outputDir, 'Storage.ts');
(0, fs_1.writeFileSync)(filename, result, { flag: 'w' });
}
function resetOutputDir(outputDir) {
(0, fs_extra_1.emptydirSync)(outputDir);
for (const moduleName in Schema) {
(0, fs_1.mkdirSync)(path_1.default.join(outputDir, moduleName));
(0, fs_1.mkdirSync)(path_1.default.join(outputDir, moduleName, 'locales'));
}
(0, fs_1.mkdirSync)(path_1.default.join(outputDir, '_locales'));
}
function addReverseRelationship() {
for (const reverseEntity in ReversePointerRelations) {
if (!ReversePointerEntities.hasOwnProperty(reverseEntity)) {
throw new Error(`${reverseEntity}」被引用为一个反指对象但其定义中的entity和entityId不符合要求`);
}
for (const one of ReversePointerRelations[reverseEntity]) {
addRelationship(reverseEntity, one, 'entity', false);
}
}
}
function outputIndexTs(outputDir) {
const indexTs = `export * from './EntityDict';
export * from './Storage';
export * from './ActionDefDict';
export * from './Relation';
export * from './StyleDict';
`;
const filename = path_1.default.join(outputDir, 'index.ts');
(0, fs_1.writeFileSync)(filename, indexTs, { flag: 'w' });
}
function outputPackageJson(outputDir) {
const pj = {
"name": process.env.COMPLING_AS_LIB ? "general-app-domain" : "oak-app-domain",
"main": "index.ts"
};
const filename = path_1.default.join(outputDir, 'package.json');
(0, fs_1.writeFileSync)(filename, JSON.stringify(pj), { flag: 'w' });
}
/**
* 从toModi的对象开始分析可能被modi指向的对象
*/
function analyzeInModi() {
const getRelateEntities = (entity) => {
let result = [];
if (ManyToOne[entity]) {
// 用反指指针指向的对象可以忽略,因为前端不可能设计出这样的更新页面
result = ManyToOne[entity].filter(ele => ele[1] !== 'entity').map(ele => ele[0]);
}
if (OneToMany[entity]) {
result.push(...OneToMany[entity].map(ele => ele[0]));
}
return (0, lodash_1.uniq)(result);
};
const setInModi = (entity) => {
if (['Modi', 'ModiEntity', 'Oper', 'OperEntity', 'User'].includes(entity)) {
return;
}
const schema = Schema[entity];
if (schema.toModi || schema.inModi || schema.actionType === 'readOnly' || schema.static) {
return;
}
schema.inModi = true;
const related = getRelateEntities(entity);
related.forEach(ele => setInModi(ele));
};
for (const entity in Schema) {
if (Schema[entity].toModi) {
const related = getRelateEntities(entity);
related.forEach(ele => setInModi(ele));
}
}
}
/**
* 此部分功能不再使用
* @param map
*/
let IGNORED_FOREIGN_KEY_MAP = {};
let IGNORED_RELATION_PATH_MAP = {};
let DEDUCED_RELATION_MAP = {};
let SELECT_FREE_ENTITIES = [];
let CREATE_FREE_ENTITIES = [];
let UPDATE_FREE_ENTITIES = [];
let FIXED_DESTINATION_PATH_MAP = {};
let FIXED_FOR_ALL_DESTINATION_PATH_ENTITIES = [];
/**
* 此函数不再使用
* @param map
*/
function registerIgnoredForeignKeyMap(map) {
IGNORED_FOREIGN_KEY_MAP = map;
}
exports.registerIgnoredForeignKeyMap = registerIgnoredForeignKeyMap;
/**
* 此函数不再使用
* @param map
*/
function registerFreeEntities(selectFreeEntities = [], createFreeEntities = [], updateFreeEntities = []) {
SELECT_FREE_ENTITIES = selectFreeEntities;
CREATE_FREE_ENTITIES = createFreeEntities;
UPDATE_FREE_ENTITIES = updateFreeEntities;
}
exports.registerFreeEntities = registerFreeEntities;
/**
* 此函数不再使用
* @param map
*/
function registerIgnoredRelationPathMap(map) {
for (const k in map) {
IGNORED_RELATION_PATH_MAP[(0, string_1.firstLetterUpperCase)(k)] = map[k];
}
}
exports.registerIgnoredRelationPathMap = registerIgnoredRelationPathMap;
/**
* 很多路径虽然最后指向同一对象但不能封掉封了会导致查询的时候找不到对应的路径path
* @param map
*/
function registerFixedDestinationPathMap(map) {
for (const k in map) {
if (k === '.') {
FIXED_FOR_ALL_DESTINATION_PATH_ENTITIES.push(...map[k]);
}
else if (FIXED_DESTINATION_PATH_MAP[k]) {
FIXED_DESTINATION_PATH_MAP[k].push(...map[k]);
}
else {
FIXED_DESTINATION_PATH_MAP[k] = map[k];
}
}
}
exports.registerFixedDestinationPathMap = registerFixedDestinationPathMap;
/**
* 此函数不再使用
* @param map
*/
function registerDeducedRelationMap(map) {
for (const k in map) {
const entity = (0, string_1.firstLetterUpperCase)(k);
(0, assert_1.default)(Schema.hasOwnProperty(entity), `config/relation.ts中配置的DeducedRelationMap包含不合法的对象名称「${k}`);
// 定义的deduce的属性一定是多对一的外键此时ReversePointerEntities还未处理
if (ReversePointerEntities[entity] && map[k] === 'entity') {
}
else {
const mto = ManyToOne[entity].find(ele => ele[1] === map[k]);
(0, assert_1.default)(mto, `config/relation.ts中配置的DeducedRelationMap所定义的「${k}」的deduce属性「${map[k]}」不是一个有效的外键指针`);
}
DEDUCED_RELATION_MAP[entity] = map[k];
}
}
exports.registerDeducedRelationMap = registerDeducedRelationMap;
/**
* 输出所有和User相关的对象的后继
* 此函数不再使用
*/
// function outputRelation(outputDir: string, printer: ts.Printer) {
// const ExcludedEntities = ['Oper', 'User', 'OperEntity', 'Modi', 'ModiEntity', 'UserRelation', 'Relation', 'RelationAuth', 'ActionAuth'];
// const actionPath: [string, string, string, boolean, string[]][] = [];
// const relationPath: [string, string, string, boolean][] = [];
// const outputRecursively = (root: string, entity: string, path: string, paths: string[], isRelation: boolean) => {
// if (ExcludedEntities.includes(entity)) {
// return;
// }
// if (IGNORED_RELATION_PATH_MAP[entity]?.find(
// (ele) => path.includes(ele)
// )) {
// return;
// }
// if (paths.length > 12) {
// throw new Error('对象之间的关系深度过长,请优化设计加以避免');
// }
// actionPath.push([firstLetterLowerCase(entity), path, root, isRelation, paths]);
// if (Schema[entity].hasRelationDef) {
// // assert(!DEDUCED_RELATION_MAP[entity], `${entity}对象定义了deducedRelationMap但它有relation`);
// relationPath.push([firstLetterLowerCase(entity), path, root, isRelation]);
// }
// const { [entity]: parent } = OneToMany;
// if (parent) {
// parent.forEach(
// ([child, foreignKey]) => {
// const child2 = firstLetterLowerCase(child);
// if (child === entity) {
// // 如果有层级关系对象最多找3层。同时这里只找本身存在relation关系的对象因为如果对象上没有relation则其上的公共路径应当可以维护住层级关系
// // 例如在jichuang项目中house上没有relation通过其park外键所维护的路径不需要遍历其父亲。而parkCluster因为有relation所以必须构造以之为根的所有的可能路径
// // 如果不是以之为根的同样可以根据其上的公共路径去查找parkCluster.system和parkCluster.parent.system必然是一样的
// if (!Schema[entity].hasRelationDef) {
// return;
// }
// if (paths.find(ele => ele !== child2) || paths.length > 2) {
// return;
// }
// }
// else if (paths.indexOf(child2) >= 0) {
// // 除了层级之外的递归直接忽略
// return;
// }
// if (IGNORED_FOREIGN_KEY_MAP[child2]?.includes(foreignKey)) {
// // 忽略的路径放弃
// return;
// }
// if (DEDUCED_RELATION_MAP[child] === foreignKey) {
// // 如果子对象本身由父对象推定,也放弃
// return;
// }
// const fk = foreignKey === 'entity' ? firstLetterLowerCase(entity) : foreignKey;
// const path2 = path ? `${fk}.${path}` : fk;
// outputRecursively(root, child, path2, paths.concat([firstLetterLowerCase(entity)]), isRelation);
// }
// );
// }
// };
// // 所有属性中有指向user的对象
// const { User } = OneToMany;
// User.forEach(
// ([entity3, foreignKey]) => {
// const fk = foreignKey === 'entity' ? 'user' : foreignKey;
// if (!IGNORED_FOREIGN_KEY_MAP[firstLetterLowerCase(entity3)]?.includes(foreignKey)) {
// outputRecursively(firstLetterLowerCase(entity3), entity3, fk, [fk], false);
// }
// }
// );
// // 所有带relation的对象
// const hasRelationEntities = Object.keys(Schema).filter(
// (entity) => Schema[entity].hasRelationDef
// );
// hasRelationEntities.forEach(
// (entity3) => {
// outputRecursively(firstLetterLowerCase(entity3), entity3, '', [], true);
// }
// );
// actionPath.sort(
// (ele1, ele2) => {
// // 先按sourceEntity来排序
// if (ele1[0] > ele2[0]) {
// return 1;
// }
// else if (ele1[0] < ele2[0]) {
// return -1;
// }
// else {
// // 再按destEntity
// if (ele1[2] > ele2[2]) {
// return 1;
// }
// else if (ele1[2] < ele2[2]) {
// return -1;
// }
// else {
// // 最后按paths的长度倒排
// return ele1[4].length - ele2[4].length;
// }
// }
// }
// );
// const entityRelations: [string, string[]][] = [];
// for (const entity in Schema) {
// const { hasRelationDef } = Schema[entity];
// if (hasRelationDef) {
// const { type } = hasRelationDef;
// if (ts.isUnionTypeNode(type)) {
// const { types } = type;
// const relations = types.map(
// ele => {
// assert(ts.isLiteralTypeNode(ele) && ts.isStringLiteral(ele.literal));
// return ele.literal.text;
// }
// );
// entityRelations.push([firstLetterLowerCase(entity), relations]);
// }
// else {
// assert(ts.isLiteralTypeNode(type));
// assert(ts.isStringLiteral(type.literal));
// const relations = [type.literal.text];
// entityRelations.push([firstLetterLowerCase(entity), relations]);
// }
// }
// }
// const stmts: ts.Statement[] = [
// factory.createImportDeclaration(
// undefined,
// factory.createImportClause(
// false,
// undefined,
// factory.createNamedImports([
// factory.createImportSpecifier(
// false,
// undefined,
// factory.createIdentifier("AuthCascadePath")
// ),
// factory.createImportSpecifier(
// false,
// undefined,
// factory.createIdentifier("AuthDeduceRelationMap")
// )
// ])
// ),
// factory.createStringLiteral(`${TYPE_PATH_IN_OAK_DOMAIN(1)}Entity`),
// undefined
// ),
// factory.createImportDeclaration(
// undefined,
// factory.createImportClause(
// false,
// undefined,
// factory.createNamedImports([factory.createImportSpecifier(
// false,
// undefined,
// factory.createIdentifier("EntityDict")
// )])
// ),
// factory.createStringLiteral("./EntityDict"),
// undefined
// ),
// factory.createImportDeclaration(
// undefined,
// factory.createImportClause(
// false,
// undefined,
// factory.createNamedImports([factory.createImportSpecifier(
// false,
// factory.createIdentifier("CreateOperationData"),
// factory.createIdentifier("Relation")
// )])
// ),
// factory.createStringLiteral("./Relation/Schema"),
// undefined
// ),
// factory.createVariableStatement(
// [factory.createToken(ts.SyntaxKind.ExportKeyword)],
// factory.createVariableDeclarationList(
// [factory.createVariableDeclaration(
// factory.createIdentifier("ActionCascadePathGraph"),
// undefined,
// factory.createArrayTypeNode(factory.createTypeReferenceNode(
// factory.createIdentifier("AuthCascadePath"),
// [factory.createTypeReferenceNode(
// factory.createIdentifier("EntityDict"),
// undefined
// )]
// )),
// factory.createArrayLiteralExpression(
// actionPath.map(
// ([entity, path, root, isRelation]) => factory.createArrayLiteralExpression(
// [
// factory.createStringLiteral(entity),
// factory.createStringLiteral(path),
// factory.createStringLiteral(root),
// isRelation ? factory.createTrue() : factory.createFalse()
// ],
// false
// )
// ),
// true
// )
// )],
// ts.NodeFlags.Const
// )
// ),
// factory.createVariableStatement(
// [factory.createToken(ts.SyntaxKind.ExportKeyword)],
// factory.createVariableDeclarationList(
// [factory.createVariableDeclaration(
// factory.createIdentifier("RelationCascadePathGraph"),
// undefined,
// factory.createArrayTypeNode(factory.createTypeReferenceNode(
// factory.createIdentifier("AuthCascadePath"),
// [factory.createTypeReferenceNode(
// factory.createIdentifier("EntityDict"),
// undefined
// )]
// )),
// factory.createArrayLiteralExpression(
// relationPath.map(
// ([entity, path, root, isRelation]) => factory.createArrayLiteralExpression(
// [
// factory.createStringLiteral(entity),
// factory.createStringLiteral(path),
// factory.createStringLiteral(root),
// isRelation ? factory.createTrue() : factory.createFalse()
// ],
// false
// )
// ),
// true
// )
// )],
// ts.NodeFlags.Const
// )
// ),
// factory.createVariableStatement(
// [factory.createToken(ts.SyntaxKind.ExportKeyword)],
// factory.createVariableDeclarationList(
// [factory.createVariableDeclaration(
// factory.createIdentifier("relations"),
// undefined,
// factory.createArrayTypeNode(factory.createTypeReferenceNode(
// factory.createIdentifier("Relation"),
// undefined
// )),
// factory.createArrayLiteralExpression(
// flatten(entityRelations.map(
// ([entity, relations]) => relations.map(
// (relation) => factory.createObjectLiteralExpression(
// [
// factory.createPropertyAssignment(
// factory.createIdentifier("id"),
// factory.createStringLiteral(formUuid(entity, relation))
// ),
// factory.createPropertyAssignment(
// factory.createIdentifier("entity"),
// factory.createStringLiteral(entity)
// ),
// factory.createPropertyAssignment(
// factory.createIdentifier("name"),
// factory.createStringLiteral(relation)
// )
// ],
// true
// )
// )
// )),
// true
// )
// )],
// ts.NodeFlags.Const
// )
// )
// ];
// stmts.push(
// factory.createVariableStatement(
// [
// factory.createToken(ts.SyntaxKind.ExportKeyword)
// ],
// factory.createVariableDeclarationList(
// [
// factory.createVariableDeclaration(
// factory.createIdentifier("deducedRelationMap"),
// undefined,
// factory.createTypeReferenceNode(
// factory.createIdentifier("AuthDeduceRelationMap"),
// [factory.createTypeReferenceNode(
// factory.createIdentifier("EntityDict"),
// undefined
// )]
// ),
// factory.createObjectLiteralExpression(
// Object.keys(DEDUCED_RELATION_MAP).map(
// ele => factory.createPropertyAssignment(
// factory.createIdentifier(firstLetterLowerCase(ele)),
// factory.createStringLiteral(DEDUCED_RELATION_MAP[ele])
// )
// ),
// true
// )
// )
// ],
// ts.NodeFlags.Const
// )
// )
// );
// stmts.push(
// factory.createVariableStatement(
// [
// factory.createToken(ts.SyntaxKind.ExportKeyword)
// ],
// factory.createVariableDeclarationList(
// [factory.createVariableDeclaration(
// factory.createIdentifier("selectFreeEntities"),
// undefined,
// factory.createArrayTypeNode(
// factory.createParenthesizedType(
// factory.createTypeOperatorNode(
// ts.SyntaxKind.KeyOfKeyword,
// factory.createTypeReferenceNode(
// factory.createIdentifier("EntityDict"),
// undefined
// )
// )
// )
// ),
// factory.createArrayLiteralExpression(
// SELECT_FREE_ENTITIES.map(
// ele => factory.createStringLiteral(ele)
// ),
// false
// )
// )],
// ts.NodeFlags.Const
// )
// ),
// factory.createVariableStatement(
// [
// factory.createToken(ts.SyntaxKind.ExportKeyword)
// ],
// factory.createVariableDeclarationList(
// [factory.createVariableDeclaration(
// factory.createIdentifier("updateFreeEntities"),
// undefined,
// factory.createArrayTypeNode(
// factory.createParenthesizedType(
// factory.createTypeOperatorNode(
// ts.SyntaxKind.KeyOfKeyword,
// factory.createTypeReferenceNode(
// factory.createIdentifier("EntityDict"),
// undefined
// )
// )
// )
// ),
// factory.createArrayLiteralExpression(
// UPDATE_FREE_ENTITIES.map(
// ele => factory.createStringLiteral(ele)
// ),
// false
// )
// )],
// ts.NodeFlags.Const
// )
// ),
// factory.createVariableStatement(
// [
// factory.createToken(ts.SyntaxKind.ExportKeyword)
// ],
// factory.createVariableDeclarationList(
// [factory.createVariableDeclaration(
// factory.createIdentifier("createFreeEntities"),
// undefined,
// factory.createArrayTypeNode(
// factory.createParenthesizedType(
// factory.createTypeOperatorNode(
// ts.SyntaxKind.KeyOfKeyword,
// factory.createTypeReferenceNode(
// factory.createIdentifier("EntityDict"),
// undefined
// )
// )
// )
// ),
// factory.createArrayLiteralExpression(
// CREATE_FREE_ENTITIES.map(
// ele => factory.createStringLiteral(ele)
// ),
// false
// )
// )],
// ts.NodeFlags.Const
// )
// )
// );
// const result = printer.printList(
// ts.ListFormat.SourceFileStatements,
// factory.createNodeArray(stmts),
// ts.createSourceFile("someFileName.ts", "", ts.ScriptTarget.Latest, /*setParentNodes*/ false, ts.ScriptKind.TS));
// const filename = PathLib.join(outputDir, 'Relation.ts');
// writeFileSync(filename, result, { flag: 'w' });
// }
/**
* 输出oak-app-domain中的Relation.ts文件
* 不再输出actionAuthGraph和relationAuthGraph两个复杂的对象
* @param outputDir
* @param printer
*/
function outputRelation2(outputDir, printer) {
const entityRelations = [];
const stmts = [
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, undefined, factory.createIdentifier("EntityDict"))])), factory.createStringLiteral("./EntityDict"), undefined),
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, factory.createIdentifier("CreateOperationData"), factory.createIdentifier("Relation"))])), factory.createStringLiteral("./Relation/Schema"), undefined),
];
const enumDelarations = [];
for (const entity in Schema) {
const { relations } = Schema[entity];
if (relations) {
const entity2 = (0, string_1.firstLetterLowerCase)(entity);
const enumMembers = [];
relations.forEach((relation) => {
const id = (0, uuid_1.formUuid)(entity2, relation);
entityRelations.push([entity2, relation, id]);
enumMembers.push(factory.createEnumMember((0, string_1.firstLetterUpperCase)(relation), factory.createStringLiteral(id)));
});
enumDelarations.push(factory.createEnumDeclaration([
factory.createToken(ts.SyntaxKind.ExportKeyword),
factory.createToken(ts.SyntaxKind.ConstKeyword)
], factory.createIdentifier(entity), enumMembers));
}
}
stmts.push(factory.createVariableStatement([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([factory.createVariableDeclaration(factory.createIdentifier("relations"), undefined, factory.createArrayTypeNode(factory.createTypeReferenceNode(factory.createIdentifier("Relation"), undefined)), factory.createArrayLiteralExpression(entityRelations.map(([entity, relation, id]) => factory.createObjectLiteralExpression([
factory.createPropertyAssignment(factory.createIdentifier("id"), factory.createStringLiteral(id)),
factory.createPropertyAssignment(factory.createIdentifier("entity"), factory.createStringLiteral(entity)),
factory.createPropertyAssignment(factory.createIdentifier("name"), factory.createStringLiteral(relation))
], true)), true))], ts.NodeFlags.Const)));
const result = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray(stmts), ts.createSourceFile("someFileName.ts", "", ts.ScriptTarget.Latest, /*setParentNodes*/ false, ts.ScriptKind.TS));
const filename = path_1.default.join(outputDir, 'Relation.ts');
(0, fs_1.writeFileSync)(filename, result, { flag: 'w' });
// 输出RelationIds.ts
const stmts2 = [
factory.createModuleDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("RelationId"), factory.createModuleBlock(enumDelarations), ts.NodeFlags.Namespace),
];
const result2 = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray(stmts2), ts.createSourceFile("someFileName.ts", "", ts.ScriptTarget.Latest, /*setParentNodes*/ false, ts.ScriptKind.TS));
const filename2 = path_1.default.join(outputDir, 'RelationId.ts');
(0, fs_1.writeFileSync)(filename2, result2, { flag: 'w' });
}
/**
* 输出oak-app-domain中的StyleDict.ts文件
* @param outputDir
* @param printer
*/
function outputStyleDict(outputDir, printer) {
for (const entity in StyleAsts) {
const stmts = [
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier("Action")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("OpSchema"))
])), factory.createStringLiteral("./Schema"), undefined),
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, undefined, factory.createIdentifier("StyleDef"))])), factory.createStringLiteral(`${(0, env_1.TYPE_PATH_IN_OAK_DOMAIN)()}Style`), undefined),
factory.createVariableStatement([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([factory.createVariableDeclaration(factory.createIdentifier("style"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("StyleDef"), [
factory.createTypeReferenceNode('OpSchema'),
factory.createTypeReferenceNode('Action')
]), StyleAsts[entity])], ts.NodeFlags.Const))
];
const { sourceFile } = Schema[entity];
const result = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray(stmts), sourceFile);
const filename = path_1.default.join(outputDir, entity, 'Style.ts');
(0, fs_1.writeFileSync)(filename, result, { flag: 'w' });
}
const stmts = [
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier("EntityDict"))
])), factory.createStringLiteral("./EntityDict"), undefined),
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, undefined, factory.createIdentifier("StyleDict"))])), factory.createStringLiteral(`${(0, env_1.TYPE_PATH_IN_OAK_DOMAIN)(1)}Style`), undefined),
...Object.keys(StyleAsts).map((entity) => factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, factory.createIdentifier("style"), factory.createIdentifier((0, string_1.firstLetterLowerCase)(entity)))])), factory.createStringLiteral(`./${entity}/Style`), undefined)),
factory.createVariableStatement([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([factory.createVariableDeclaration(factory.createIdentifier("styleDict"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("StyleDict"), [factory.createTypeReferenceNode(factory.createIdentifier("EntityDict"), undefined)]), factory.createObjectLiteralExpression(Object.keys(StyleAsts).map((entity) => factory.createShorthandPropertyAssignment(factory.createIdentifier((0, string_1.firstLetterLowerCase)(entity)), undefined)), true))], ts.NodeFlags.Const))
];
const result = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray(stmts), ts.createSourceFile("someFileName.ts", "", ts.ScriptTarget.Latest, /*setParentNodes*/ false, ts.ScriptKind.TS));
const filename = path_1.default.join(outputDir, 'StyleDict.ts');
(0, fs_1.writeFileSync)(filename, result, { flag: 'w' });
}
const getAnalizedSchema = () => {
return Schema;
};
exports.getAnalizedSchema = getAnalizedSchema;
function analyzeEntities(inputDir, relativePath) {
const files = (0, fs_1.readdirSync)(inputDir);
const fullFilenames = files.map(ele => {
const entity = ele.slice(0, ele.indexOf('.'));
if (env_1.RESERVED_ENTITY_NAMES.includes(entity) || env_1.RESERVED_ENTITY_NAMES.find(ele2 => entity.startsWith(ele2))) {
throw new Error(`${ele}是系统保留字,请勿使用其当对象名或对象名前缀`);
}
return `${inputDir}/${ele}`;
});
const program = ts.createProgram(fullFilenames, { allowJs: true });
files.forEach((filename) => {
analyzeEntity(filename, inputDir, program, relativePath);
});
analyzeInModi();
uniqRelationships();
}
exports.analyzeEntities = analyzeEntities;
function buildSchemaBackup(outputDir) {
addReverseRelationship();
// setRelationEntities();
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
resetOutputDir(outputDir);
outputSchema(outputDir, printer);
outputLocale(outputDir, printer);
outputSubQuery(outputDir, printer);
outputAction(outputDir, printer);
outputEntityDict(outputDir, printer);
outputStorage(outputDir, printer);
outputRelation2(outputDir, printer);
outputStyleDict(outputDir, printer);
outputIndexTs(outputDir);
if (!process.env.COMPLING_AS_LIB) {
outputPackageJson(outputDir);
}
}
exports.buildSchemaBackup = buildSchemaBackup;
function _getAggrKey(entity, foreignKey) {
const aggrKey = `${entity}$${foreignKey}`;
if (process.env.COMPLING_AS_LIB) {
return `${aggrKey}$$aggr`;
}
return factory.createUnionTypeNode([
factory.createLiteralTypeNode(factory.createStringLiteral(`${aggrKey}$$aggr`)),
factory.createTemplateLiteralType(factory.createTemplateHead(`${aggrKey}$$`, `${aggrKey}$$`), [factory.createTemplateLiteralTypeSpan(factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), factory.createTemplateTail("$$aggr", "$$aggr"))])
]);
}
function _outputEntityDict(outputDir, printer) {
const statements = initialStatements3(1);
for (const entity in Schema) {
statements.push(factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamespaceImport(factory.createIdentifier(`Base${entity}`))), factory.createStringLiteral(`./${entity}/_baseSchema`), undefined));
}
for (const entity in Schema) {
const entityLc = (0, string_1.firstLetterLowerCase)(entity);
const getSchema = () => {
const { schemaAttrs } = Schema[entity];
const { [entity]: manyToOneSet } = ManyToOne;
const { [entity]: oneToManySet } = OneToMany;
const members = [];
for (const attr of schemaAttrs) {
const { type, name, questionToken } = attr;
const attrName = name.text;
if (ts.isTypeReferenceNode(type)) {
const { typeName } = type;
if (ts.isIdentifier(typeName)) {
const { text } = typeName;
const text2 = text === 'Schema' ? entity : text;
const manyToOneItem = manyToOneSet && manyToOneSet.find(([refEntity, attrName2]) => refEntity === text2 && attrName2 === attrName);
if (manyToOneItem) {
const foreignKeyNode = createIndexedForeignRef(text2, 'Schema');
members.push(factory.createPropertySignature(undefined, name, questionToken, foreignKeyNode));
}
}
else {
(0, assert_1.default)(false); // 这是什么case不确定
}
}
}
// 处理reverserPointer
const reverseOnes = ReversePointerRelations[entity];
if (reverseOnes) {
reverseOnes.forEach((one) => {
members.push(factory.createPropertySignature(undefined, (0, string_1.firstLetterLowerCase)(one), factory.createToken(ts.SyntaxKind.QuestionToken), createIndexedForeignRef(one, 'Schema')));
});
}
const foreignKeySet = {};
if (oneToManySet) {
for (const oneToManyItem of oneToManySet) {
const [entityName, foreignKey] = oneToManyItem;
if (foreignKeySet.hasOwnProperty(entityName)) {
foreignKeySet[entityName].push(foreignKey);
}
else {
foreignKeySet[entityName] = [foreignKey];
}
}
for (const entityName in foreignKeySet) {
const entityNameLc = (0, string_1.firstLetterLowerCase)(entityName);
foreignKeySet[entityName].forEach((foreignKey) => {
const identifier = `${entityNameLc}$${foreignKey}`;
members.push(factory.createPropertySignature(undefined, identifier, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(factory.createIdentifier("Array"), [
factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
createIndexedForeignRef(entityName, 'Schema'),
factory.createLiteralTypeNode(factory.createStringLiteral(foreignKey))
])
])));
});
}
}
const otmAggrMappedNodes = [];
for (const entityName in foreignKeySet) {
const entityNameLc = (0, string_1.firstLetterLowerCase)(entityName);
foreignKeySet[entityName].forEach((foreignKey) => {
const aggrKeyNode = _getAggrKey(entityNameLc, foreignKey);
const aggrNode = factory.createTypeReferenceNode(factory.createIdentifier("AggregationResult"), [factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
createIndexedForeignRef(entityName, 'Schema'),
factory.createLiteralTypeNode(factory.createStringLiteral(foreignKey))
])]);
if (typeof aggrKeyNode === 'string') {
members.push(factory.createPropertySignature(undefined, aggrKeyNode, factory.createToken(ts.SyntaxKind.QuestionToken), aggrNode));
}
else {
otmAggrMappedNodes.push(factory.createMappedTypeNode(undefined, factory.createTypeParameterDeclaration(undefined, factory.createIdentifier("A"), aggrKeyNode, undefined), undefined, factory.createToken(ts.SyntaxKind.QuestionToken), aggrNode, undefined));
}
});
}
return factory.createIntersectionTypeNode([
factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(`Base${entity}`), factory.createIdentifier("OpSchema"))),
factory.createTypeLiteralNode(members),
...otmAggrMappedNodes,
]);
};
const getProjection = () => {
const { schemaAttrs, enumAttributes } = Schema[entity];
const properties = [];
const { [entity]: manyToOneSet } = ManyToOne;
for (const attr of schemaAttrs) {
const { type, name } = attr;
const attrName = name.text;
if (ts.isTypeReferenceNode(type)) {
const { typeName } = type;
if (ts.isIdentifier(typeName)) {
const { text } = typeName;
switch (text) {
case 'String':
case 'Text':
case 'Int':
case 'Uint':
case 'Float':
case 'Double':
case 'Boolean':
case 'Datetime':
case 'Image':
case 'File':
case 'SingleGeo':
case 'Geo':
case 'Price':
case 'Decimal':
case 'Object': {
break;
}
default: {
const text2 = text === 'Schema' ? entity : text;
const manyToOneItem = manyToOneSet && manyToOneSet.find(([refEntity]) => refEntity === text2);
if (manyToOneItem) {
// 外键投影
properties.push([name, false, createIndexedForeignRef(text2, 'Projection')]);
}
}
}
}
else {
(0, assert_1.default)(false);
}
}
}
if (ReversePointerRelations[entity]) {
ReversePointerRelations[entity].forEach((one) => {
const text2 = one === 'Schema' ? entity : one;
properties.push([(0, string_1.firstLetterLowerCase)(one), false, createIndexedForeignRef(text2, 'Projection')]);
});
}
// 一对多的projection
const otmAggrMappedNodes = [];
const { [entity]: oneToManySet } = OneToMany;
if (oneToManySet) {
const foreignKeySet = {};
for (const oneToManyItem of oneToManySet) {
const [entityName, foreignKey] = oneToManyItem;
if (foreignKeySet.hasOwnProperty(entityName)) {
foreignKeySet[entityName].push(foreignKey);
}
else {
foreignKeySet[entityName] = [foreignKey];
}
}
for (const entityName in foreignKeySet) {
const entityNameLc = (0, string_1.firstLetterLowerCase)(entityName);
foreignKeySet[entityName].forEach((foreignKey) => {
const identifier = `${entityNameLc}$${foreignKey}`;
const aggrKey = _getAggrKey(entityNameLc, foreignKey);
properties.push([identifier, false,
factory.createIntersectionTypeNode([
factory.createTypeReferenceNode(factory.createIdentifier("OakSelection"), [
factory.createLiteralTypeNode(factory.createStringLiteral("select")),
factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
createIndexedForeignRef(entityName, 'Projection'),
factory.createLiteralTypeNode(factory.createStringLiteral(entityLc))
]),
factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
createIndexedForeignRef(entityName, 'Filter'),
factory.createLiteralTypeNode(factory.createStringLiteral(entityLc))
]),
createIndexedForeignRef(entityName, 'Sorter')
]),
factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier("$entity"), undefined, factory.createLiteralTypeNode(factory.createStringLiteral((0, string_1.firstLetterLowerCase)(entityName))))
])
])
]);
const otmAggrNode = factory.createIntersectionTypeNode([
factory.createTypeReferenceNode(factory.createIdentifier("DeduceAggregation"), [
factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
createIndexedForeignRef(entityName, 'Projection'),
factory.createLiteralTypeNode(factory.createStringLiteral(entityLc))
]),
factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
createIndexedForeignRef(entityName, 'Filter'),
factory.createLiteralTypeNode(factory.createStringLiteral(entityLc))
]),
createIndexedForeignRef(entityName, 'Sorter')
]),
factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier("$entity"), undefined, factory.createLiteralTypeNode(factory.createStringLiteral((0, string_1.firstLetterLowerCase)(entityName))))
])
]);
if (typeof aggrKey === 'string') {
properties.push([
aggrKey,
false,
otmAggrNode
]);
}
else {
otmAggrMappedNodes.push(factory.createMappedTypeNode(undefined, factory.createTypeParameterDeclaration(undefined, factory.createIdentifier("A"), aggrKey, undefined), undefined, factory.createToken(ts.SyntaxKind.QuestionToken), otmAggrNode, undefined));
}
});
}
}
return factory.createIntersectionTypeNode([
factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(`Base${entity}`), factory.createIdentifier("OpProjection"))),
factory.createTypeLiteralNode(properties.map(([n, q, v]) => {
return factory.createPropertySignature(undefined, n, q ? undefined : factory.createToken(ts.SyntaxKind.QuestionToken), v || factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword));
})),
...otmAggrMappedNodes,
]);
};
const getFilterUnit = () => {
const { schemaAttrs, fulltextIndex } = Schema[entity];
const members = [];
const { [entity]: manyToOneSet } = ManyToOne;
const entityUnionTypeNodes = ReversePointerRelations[entity] && ReversePointerRelations[entity].map(ele => factory.createLiteralTypeNode(factory.createStringLiteral((0, string_1.firstLetterLowerCase)(ele))));
if (process.env.COMPLING_AS_LIB) {
entityUnionTypeNodes && entityUnionTypeNodes.push(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword));
}
for (const attr of schemaAttrs) {
const { type, name } = attr;
const attrName = name.text;
if (ts.isTypeReferenceNode(type)) {
const { typeName } = type;
if (ts.isIdentifier(typeName)) {
const { text } = typeName;
let type2;
switch (text) {
case 'String':
case 'Text':
case 'Image':
case 'File':
case 'Int':
case 'Uint':
case 'Float':
case 'Double':
case 'Price':
case 'Decimal':
case 'Boolean':
case 'Datetime':
case 'SingleGeo':
case 'Geo':
case 'Object': {
break;
}
default: {
const text2 = text === 'Schema' ? entity : text;
const manyToOneItem = manyToOneSet && manyToOneSet.find(([refEntity]) => refEntity === text2);
if (manyToOneItem) {
type2 = factory.createTypeReferenceNode('MakeFilter', [
createIndexedForeignRef(text2, 'FilterUnit')
]);
}
}
}
if (type2) {
members.push(factory.createPropertySignature(undefined, name, undefined, type2));
}
}
}
}
// type AttrFilter = {};
if (ReversePointerRelations[entity]) {
// 有反向指针将反向指针关联的对象的Filter也注入
ReversePointerRelations[entity].forEach(ele => members.push(factory.createPropertySignature(undefined, (0, string_1.firstLetterLowerCase)(ele), undefined, factory.createTypeReferenceNode('MakeFilter', [
createIndexedForeignRef(ele, 'FilterUnit')
]))));
}
// 一对多的生成子查询
const { [entity]: oneToManySet } = OneToMany;
if (oneToManySet) {
const foreignKeySet = {};
for (const oneToManyItem of oneToManySet) {
const [entityName, foreignKey] = oneToManyItem;
if (foreignKeySet.hasOwnProperty(entityName)) {
foreignKeySet[entityName].push(foreignKey);
}
else {
foreignKeySet[entityName] = [foreignKey];
}
}
for (const entityName in foreignKeySet) {
const entityNameLc = (0, string_1.firstLetterLowerCase)(entityName);
foreignKeySet[entityName].forEach((foreignKey) => {
const identifier = `${entityNameLc}$${foreignKey}`;
members.push(factory.createPropertySignature(undefined, identifier, undefined, factory.createIntersectionTypeNode([
factory.createTypeReferenceNode('MakeFilter', [
factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [
createIndexedForeignRef(entityName, 'FilterUnit'),
factory.createLiteralTypeNode(factory.createStringLiteral(foreignKey))
])
]),
factory.createTypeReferenceNode('SubQueryPredicateMetadata')
])));
});
}
}
const types = [
factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(`Base${entity}`), factory.createIdentifier("OpFilter"))),
factory.createTypeLiteralNode(members)
];
// 如果还有其它类型的查询如全文则加在types数组中
if (fulltextIndex) {
types.push(factory.createTypeReferenceNode('FulltextFilter'));
}
return factory.createIntersectionTypeNode(types);
};
const getSortAttr = () => {
const { schemaAttrs } = Schema[entity];
const members = [];
const { [entity]: manyToOneSet } = ManyToOne;
for (const attr of schemaAttrs) {
const { type, name, questionToken } = attr;
if (ts.isTypeReferenceNode(type)) {
const { typeName } = type;
if (ts.isIdentifier(typeName)) {
const { text } = typeName;
let type2;
switch (text) {
case 'String':
case 'Text':
case 'Int':
case 'Float':
case 'Double':
case 'Boolean':
case 'Datetime':
case 'Image':
case 'File':
case 'Price': {
break;
}
default: {
const text2 = text === 'Schema' ? entity : text;
const manyToOneItem = manyToOneSet && manyToOneSet.find(([refEntity]) => refEntity === text2);
if (manyToOneItem) {
type2 = createIndexedForeignRef(text2, 'SortAttr');
}
}
}
if (type2) {
members.push(factory.createPropertySignature(undefined, name, undefined, type2));
}
}
}
}
if (ReversePointerRelations[entity]) {
ReversePointerRelations[entity].forEach((one) => {
members.push(factory.createPropertySignature(undefined, (0, string_1.firstLetterLowerCase)(one), undefined, createIndexedForeignRef(one, 'SortAttr')));
});
}
return factory.createTypeReferenceNode('Partial', [
factory.createUnionTypeNode([
factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(`Base${entity}`), factory.createIdentifier("OpSortAttr"))),
factory.createTypeLiteralNode(members),
])
]);
};
const getOperations = () => {
const { [entity]: manyToOneSet } = ManyToOne;
const { [entity]: oneToManySet } = OneToMany;
const foreignKeySet = {};
if (oneToManySet) {
for (const oneToManyItem of oneToManySet) {
const [entityName, foreignKey] = oneToManyItem;
if (foreignKeySet.hasOwnProperty(entityName)) {
foreignKeySet[entityName].push(foreignKey);
}
else {
foreignKeySet[entityName] = [foreignKey];
}
}
}
const cascadeCreateElements = [];
const cascadeUpdateElements = [];
{
const addManyToOneCascade = (foreignEntity, foreignKey) => {
// 切断modiEntity和其它对象的关联太多了
if (entity === 'ModiEntity' && foreignEntity !== 'Modi') {
return;
}
if (entity === 'OperEntity' && foreignEntity !== 'Oper') {
return;
}
const propertyName = foreignKey === 'entity' ? (0, string_1.firstLetterLowerCase)(foreignEntity) : foreignKey;
const createCasNode = factory.createTypeReferenceNode('OakOperation', [
factory.createLiteralTypeNode(factory.createStringLiteral('create')),
createIndexedForeignRef(foreignEntity, 'CreateOperationData')
]);
const updateCasNode = factory.createTypeReferenceNode('OakOperation', [
factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(`Base${foreignEntity}`), factory.createIdentifier("OpUpdateAction"))),
createIndexedForeignRef(foreignEntity, 'UpdateOperationData'),
createIndexedForeignRef(foreignEntity, 'Filter'),
]);
const removeCasNode = factory.createTypeReferenceNode('OakOperation', [
factory.createLiteralTypeNode(factory.createStringLiteral('remove')),
createIndexedForeignRef(foreignEntity, 'RemoveOperationData'),
createIndexedForeignRef(foreignEntity, 'Filter')
]);
if (!Schema[foreignEntity].static) {
switch (Schema[foreignEntity].actionType) {
case 'crud': {
cascadeCreateElements.push(factory.createPropertySignature(undefined, propertyName, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([
createCasNode,
updateCasNode
])));
cascadeUpdateElements.push(factory.createPropertySignature(undefined, propertyName, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([
createCasNode,
updateCasNode,
removeCasNode,
])));
break;
}
case 'excludeRemove': {
cascadeCreateElements.push(factory.createPropertySignature(undefined, propertyName, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([
createCasNode,
updateCasNode
])));
cascadeUpdateElements.push(factory.createPropertySignature(undefined, propertyName, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([
createCasNode,
updateCasNode,
])));
break;
}
case 'excludeUpdate': {
cascadeCreateElements.push(factory.createPropertySignature(undefined, propertyName, factory.createToken(ts.SyntaxKind.QuestionToken), createCasNode));
cascadeUpdateElements.push(factory.createPropertySignature(undefined, propertyName, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([
createCasNode,
removeCasNode,
])));
break;
}
case 'appendOnly': {
cascadeCreateElements.push(factory.createPropertySignature(undefined, propertyName, factory.createToken(ts.SyntaxKind.QuestionToken), createCasNode));
cascadeUpdateElements.push(factory.createPropertySignature(undefined, propertyName, factory.createToken(ts.SyntaxKind.QuestionToken), createCasNode));
break;
}
case 'readOnly': {
break;
}
default: {
(0, assert_1.default)(false);
}
}
}
};
// 多对一
if (manyToOneSet) {
for (const one of manyToOneSet) {
addManyToOneCascade(one[0], one[1]);
}
}
// 一对多
const addOneToManyCascade = (foreignEntity, foreignKey) => {
// 切断modiEntity和其它对象的关联太多了
if (foreignEntity === 'ModiEntity' && entity !== 'Modi') {
return;
}
if (foreignEntity === 'OperEntity' && entity !== 'Oper') {
return;
}
const foreignEntityLc = (0, string_1.firstLetterLowerCase)(foreignEntity);
const otmKey = `${foreignEntityLc}$${foreignKey}`;
const mtoKey = foreignKey === 'entity' ? (0, string_1.firstLetterLowerCase)(entity) : foreignKey;
const otmCreateData = factory.createTypeReferenceNode('Omit', [
createIndexedForeignRef(foreignEntity, 'CreateOperationData'),
factory.createLiteralTypeNode(factory.createStringLiteral(mtoKey))
]);
const otmUpdateData = factory.createTypeReferenceNode('Omit', [
createIndexedForeignRef(foreignEntity, 'UpdateOperationData'),
factory.createLiteralTypeNode(factory.createStringLiteral(mtoKey))
]);
const createCasNode = factory.createTypeReferenceNode('OakOperation', [
factory.createLiteralTypeNode(factory.createStringLiteral('create')),
factory.createUnionTypeNode([
otmCreateData,
factory.createArrayTypeNode(otmCreateData)
])
]);
const updateCasNode = factory.createTypeReferenceNode('OakOperation', [
factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(`Base${foreignEntity}`), factory.createIdentifier("OpUpdateAction"))),
otmUpdateData,
createIndexedForeignRef(foreignEntity, 'Filter'),
]);
const removeCasNode = factory.createTypeReferenceNode('OakOperation', [
factory.createLiteralTypeNode(factory.createStringLiteral('remove')),
createIndexedForeignRef(foreignEntity, 'RemoveOperationData'),
createIndexedForeignRef(foreignEntity, 'Filter')
]);
if (!Schema[foreignEntity].static) {
switch (Schema[foreignEntity].actionType) {
case 'crud': {
cascadeCreateElements.push(factory.createPropertySignature(undefined, otmKey, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createArrayTypeNode(factory.createUnionTypeNode([
createCasNode,
updateCasNode
]))));
cascadeUpdateElements.push(factory.createPropertySignature(undefined, otmKey, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createArrayTypeNode(factory.createUnionTypeNode([
createCasNode,
updateCasNode,
removeCasNode,
]))));
break;
}
case 'excludeRemove': {
cascadeCreateElements.push(factory.createPropertySignature(undefined, otmKey, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createArrayTypeNode(factory.createUnionTypeNode([
createCasNode,
updateCasNode
]))));
cascadeUpdateElements.push(factory.createPropertySignature(undefined, otmKey, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createArrayTypeNode(factory.createUnionTypeNode([
createCasNode,
updateCasNode,
]))));
break;
}
case 'excludeUpdate': {
cascadeCreateElements.push(factory.createPropertySignature(undefined, otmKey, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createArrayTypeNode(createCasNode)));
cascadeUpdateElements.push(factory.createPropertySignature(undefined, otmKey, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createArrayTypeNode(factory.createUnionTypeNode([
createCasNode,
removeCasNode,
]))));
break;
}
case 'appendOnly': {
cascadeCreateElements.push(factory.createPropertySignature(undefined, otmKey, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createArrayTypeNode(createCasNode)));
cascadeUpdateElements.push(factory.createPropertySignature(undefined, otmKey, factory.createToken(ts.SyntaxKind.QuestionToken), factory.createArrayTypeNode(createCasNode)));
break;
}
case 'readOnly': {
break;
}
default: {
(0, assert_1.default)(false);
}
}
}
};
if (oneToManySet) {
for (const entityName in foreignKeySet) {
foreignKeySet[entityName].forEach((foreignKey) => {
addOneToManyCascade(entityName, foreignKey);
});
}
}
if (process.env.COMPLING_AS_LIB) {
// 如果是base要包容更多可能的反指
/* cascadeCreateElements.push(
factory.createIndexSignature(
undefined,
[factory.createParameterDeclaration(
undefined,
undefined,
factory.createIdentifier("K"),
undefined,
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
undefined
)],
factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
)
);
cascadeUpdateElements.push(
factory.createIndexSignature(
undefined,
[factory.createParameterDeclaration(
undefined,
undefined,
factory.createIdentifier("K"),
undefined,
factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
undefined
)],
factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)
)
); */
}
}
return {
CreateOperationData: factory.createTypeReferenceNode('FormCreateData', [
cascadeCreateElements.length ? factory.createIntersectionTypeNode([
factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(`Base${entity}`), factory.createIdentifier("OpSchema"))),
factory.createTypeLiteralNode(cascadeCreateElements),
]) : factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(`Base${entity}`), factory.createIdentifier("OpSchema")))
]),
UpdateOperationData: factory.createTypeReferenceNode('FormUpdateData', [
cascadeUpdateElements.length ? factory.createIntersectionTypeNode([
factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(`Base${entity}`), factory.createIdentifier("OpSchema"))),
factory.createTypeLiteralNode(cascadeUpdateElements),
]) : factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(`Base${entity}`), factory.createIdentifier("OpSchema")))
]),
RemoveOperationData: factory.createTypeLiteralNode([]), // RemoveOperate暂时不支持Cascade
};
};
const { CreateOperationData, UpdateOperationData, RemoveOperationData, } = getOperations();
statements.push(factory.createTypeAliasDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier(entity), undefined, factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, 'OpSchema', undefined, factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(`Base${entity}`), factory.createIdentifier("OpSchema")))),
factory.createPropertySignature(undefined, 'Action', undefined, factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(`Base${entity}`), factory.createIdentifier("OpAction")))),
factory.createPropertySignature(undefined, factory.createIdentifier("Schema"), undefined, getSchema()),
factory.createPropertySignature(undefined, factory.createIdentifier("Projection"), undefined, getProjection()),
factory.createPropertySignature(undefined, factory.createIdentifier("FilterUnit"), undefined, getFilterUnit()),
factory.createPropertySignature(undefined, factory.createIdentifier("Filter"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("MakeFilter"), [
createIndexedForeignRef(entity, 'FilterUnit')
])),
factory.createPropertySignature(undefined, factory.createIdentifier("SortAttr"), undefined, getSortAttr()),
factory.createPropertySignature(undefined, factory.createIdentifier("SortNode"), undefined, factory.createTypeLiteralNode([
factory.createPropertySignature(undefined, factory.createIdentifier("$attr"), undefined, createIndexedForeignRef(entity, 'SortAttr')),
factory.createPropertySignature(undefined, factory.createIdentifier("$direction"), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([
factory.createLiteralTypeNode(factory.createStringLiteral("asc")),
factory.createLiteralTypeNode(factory.createStringLiteral("desc"))
]))
])),
factory.createPropertySignature(undefined, factory.createIdentifier("Sorter"), undefined, factory.createArrayTypeNode(createIndexedForeignRef(entity, 'SortNode'))),
factory.createPropertySignature(undefined, factory.createIdentifier("Selection"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("OakSelection"), [
factory.createLiteralTypeNode(factory.createStringLiteral("select")),
createIndexedForeignRef(entity, 'Projection'),
createIndexedForeignRef(entity, 'Filter'),
createIndexedForeignRef(entity, 'Sorter')
])),
factory.createPropertySignature(undefined, factory.createIdentifier("Aggregation"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("DeduceAggregation"), [
createIndexedForeignRef(entity, 'Projection'),
createIndexedForeignRef(entity, 'Filter'),
createIndexedForeignRef(entity, 'Sorter')
])),
factory.createPropertySignature(undefined, factory.createIdentifier("CreateOperationData"), undefined, CreateOperationData),
factory.createPropertySignature(undefined, factory.createIdentifier("CreateSingle"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("OakOperation"), [
factory.createLiteralTypeNode(factory.createStringLiteral('create')),
createIndexedForeignRef(entity, 'CreateOperationData')
])),
factory.createPropertySignature(undefined, factory.createIdentifier("CreateMulti"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("OakOperation"), [
factory.createLiteralTypeNode(factory.createStringLiteral('create')),
factory.createTypeReferenceNode(factory.createIdentifier("Array"), [
createIndexedForeignRef(entity, 'CreateOperationData')
])
])),
factory.createPropertySignature(undefined, factory.createIdentifier("Create"), undefined, factory.createUnionTypeNode([
createIndexedForeignRef(entity, 'CreateSingle'),
createIndexedForeignRef(entity, 'CreateMulti')
])),
factory.createPropertySignature(undefined, factory.createIdentifier("UpdateOperationData"), undefined, UpdateOperationData),
factory.createPropertySignature(undefined, factory.createIdentifier("Update"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("OakOperation"), [
factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(`Base${entity}`), factory.createIdentifier("OpUpdateAction"))),
createIndexedForeignRef(entity, 'UpdateOperationData'),
createIndexedForeignRef(entity, 'Filter'),
createIndexedForeignRef(entity, 'Sorter'),
])),
factory.createPropertySignature(undefined, factory.createIdentifier("RemoveOperationData"), undefined, RemoveOperationData),
factory.createPropertySignature(undefined, factory.createIdentifier("Remove"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("OakOperation"), [
factory.createLiteralTypeNode(factory.createStringLiteral('remove')),
createIndexedForeignRef(entity, 'RemoveOperationData'),
createIndexedForeignRef(entity, 'Filter'),
createIndexedForeignRef(entity, 'Sorter'),
])),
factory.createPropertySignature(undefined, factory.createIdentifier("Operation"), undefined, factory.createUnionTypeNode([
createIndexedForeignRef(entity, 'Create'),
createIndexedForeignRef(entity, 'Update'),
createIndexedForeignRef(entity, 'Remove'),
])),
])));
}
statements.push(factory.createTypeAliasDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("EntityDict"), undefined, factory.createTypeLiteralNode(Object.keys(Schema).map((ele) => factory.createPropertySignature(undefined, (0, string_1.firstLetterLowerCase)(ele), undefined, factory.createTypeReferenceNode(factory.createIdentifier(ele)))))));
const result = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray(statements), undefined);
const fileName = path_1.default.join(outputDir, 'EntityDict.ts');
(0, fs_1.writeFileSync)(fileName, result, { flag: 'w' });
}
function getProjectionKeys(entity) {
const keys = [];
const { schemaAttrs } = Schema[entity];
const { [entity]: manyToOneSet = [] } = ManyToOne;
for (const attr of schemaAttrs) {
const { type, name } = attr;
const attrName = name.text;
if (ts.isTypeReferenceNode(type)) {
const typeName = type.typeName;
if (ts.isIdentifier(typeName)) {
const text = typeName.text;
switch (text) {
case 'String':
case 'Text':
case 'Int':
case 'Uint':
case 'Float':
case 'Double':
case 'Boolean':
case 'Datetime':
case 'Image':
case 'File':
case 'SingleGeo':
case 'Geo':
case 'Price':
case 'Decimal':
case 'Object':
break;
default:
const text2 = text === 'Schema' ? entity : text;
const manyToOneItem = manyToOneSet.find(([refEntity]) => refEntity === text2);
if (manyToOneItem) {
keys.push(attrName); // 外键属性
}
}
}
}
}
if (ReversePointerRelations[entity]) {
for (const one of ReversePointerRelations[entity]) {
const text2 = one === 'Schema' ? entity : one;
keys.push((0, string_1.firstLetterLowerCase)(one));
}
}
const { [entity]: oneToManySet = [] } = OneToMany;
const foreignKeySet = {};
for (const [entityName, foreignKey] of oneToManySet) {
if (!foreignKeySet[entityName]) {
foreignKeySet[entityName] = [];
}
foreignKeySet[entityName].push(foreignKey);
}
for (const entityName in foreignKeySet) {
const entityNameLc = (0, string_1.firstLetterLowerCase)(entityName);
for (const foreignKey of foreignKeySet[entityName]) {
const identifier = `${entityNameLc}$${foreignKey}`;
keys.push(identifier);
const aggrKey = _getAggrKey(entityNameLc, foreignKey);
if (typeof aggrKey === 'string') {
keys.push(aggrKey);
}
else {
// 如果是 union 类型,用映射表达式模拟(如 ["xxx$$aggr", `xxx$$${number}$$aggr`]
keys.push(`${identifier}$$aggr`);
}
}
}
return [...new Set([...keys, ...getOpProjectionKeys(entity)])];
}
exports.getProjectionKeys = getProjectionKeys;
function _outputSchema(outputDir, printer) {
for (const entity in Schema) {
const statements = [
factory.createExportDeclaration(undefined, false, undefined, factory.createStringLiteral("./_baseSchema"), undefined),
factory.createImportDeclaration(undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier(entity))
])), factory.createStringLiteral("../EntityDict"), undefined),
];
const keys = [
'Schema', 'Action', 'Projection', 'Filter', 'SortNode', 'Sorter', 'Selection',
'Aggregation', 'CreateOperationData', 'CreateSingle', 'CreateMulti', 'Create',
'UpdateOperationData', 'Update', 'RemoveOperationData', 'Remove', 'Operation'
];
statements.push(...keys.map((ele) => factory.createTypeAliasDeclaration([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier(ele), undefined, factory.createIndexedAccessTypeNode(factory.createTypeReferenceNode(factory.createIdentifier(entity), undefined), factory.createLiteralTypeNode(factory.createStringLiteral(ele))))));
const result = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray(statements), undefined);
const fileName = path_1.default.join(outputDir, entity, 'Schema.ts');
(0, fs_1.writeFileSync)(fileName, result, { flag: 'w' });
}
}
function buildSchema(outputDir) {
addReverseRelationship();
// setRelationEntities();
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
resetOutputDir(outputDir);
outputAction(outputDir, printer);
_outputBaseSchema(outputDir, printer);
outputLocale(outputDir, printer);
_outputEntityDict(outputDir, printer);
_outputSchema(outputDir, printer);
outputStorage(outputDir, printer);
outputRelation2(outputDir, printer);
outputStyleDict(outputDir, printer);
outputIndexTs(outputDir);
}
exports.buildSchema = buildSchema;