diff --git a/lib/base-app-domain/Modi/Schema.d.ts b/lib/base-app-domain/Modi/Schema.d.ts index 3040758..759fc64 100644 --- a/lib/base-app-domain/Modi/Schema.d.ts +++ b/lib/base-app-domain/Modi/Schema.d.ts @@ -1,4 +1,4 @@ -import { String, Datetime, PrimaryKey, ForeignKey } from "../../types/DataType"; +import { String, Datetime, PrimaryKey } from "../../types/DataType"; import { Q_DateValue, Q_StringValue, Q_EnumValue, NodeId, MakeFilter, ExprOp, ExpressionKey } from "../../types/Demand"; import { OneOf } from "../../types/Polyfill"; import * as SubQuery from "../_SubQuery"; @@ -11,11 +11,13 @@ export declare type OpSchema = { $$createAt$$: Datetime; $$updateAt$$: Datetime; $$deleteAt$$?: Datetime | null; + targetEntity: String<32>; + entity: String<32>; + entityId: String<64>; action: String<16>; data: Object; filter?: Object | null; extra?: Object | null; - parentId?: ForeignKey<"modi"> | null; iState?: IState | null; }; export declare type OpAttr = keyof OpSchema; @@ -24,14 +26,14 @@ export declare type Schema = { $$createAt$$: Datetime; $$updateAt$$: Datetime; $$deleteAt$$?: Datetime | null; + targetEntity: String<32>; + entity: String<32>; + entityId: String<64>; action: String<16>; data: Object; filter?: Object | null; extra?: Object | null; - parentId?: ForeignKey<"modi"> | null; iState?: IState | null; - parent?: Schema | null; - modi$parent?: Array; modiEntity$modi?: Array; operEntity$entity?: Array; } & { @@ -41,9 +43,10 @@ declare type AttrFilter = { id: Q_StringValue | SubQuery.ModiIdSubQuery; $$createAt$$: Q_DateValue; $$updateAt$$: Q_DateValue; + targetEntity: Q_StringValue; + entity: Q_StringValue; + entityId: Q_StringValue; action: Q_StringValue; - parentId: Q_StringValue | SubQuery.ModiIdSubQuery; - parent: Filter; iState: Q_EnumValue; }; export declare type Filter = MakeFilter>; @@ -53,16 +56,14 @@ export declare type Projection = { id: 1; $$createAt$$?: 1; $$updateAt$$?: 1; + targetEntity?: 1; + entity?: 1; + entityId?: 1; action?: 1; data?: 1; filter?: 1; extra?: 1; - parentId?: 1; - parent?: Projection; iState?: 1; - modi$parent?: Selection & { - $entity: "modi"; - }; modiEntity$modi?: ModiEntity.Selection & { $entity: "modiEntity"; }; @@ -76,16 +77,14 @@ export declare type ExportProjection = { id?: string; $$createAt$$?: string; $$updateAt$$?: string; + targetEntity?: string; + entity?: string; + entityId?: string; action?: string; data?: string; filter?: string; extra?: string; - parentId?: string; - parent?: ExportProjection; iState?: string; - modi$parent?: Exportation & { - $entity: "modi"; - }; modiEntity$modi?: ModiEntity.Exportation & { $entity: "modiEntity"; }; @@ -95,7 +94,6 @@ export declare type ExportProjection = { } & Partial>; declare type ModiIdProjection = OneOf<{ id: 1; - parentId: 1; }>; export declare type SortAttr = { id: 1; @@ -103,12 +101,14 @@ export declare type SortAttr = { $$createAt$$: 1; } | { $$updateAt$$: 1; +} | { + targetEntity: 1; +} | { + entity: 1; +} | { + entityId: 1; } | { action: 1; -} | { - parentId: 1; -} | { - parent: SortAttr; } | { iState: 1; } | { @@ -122,44 +122,29 @@ export declare type Sorter = SortNode[]; export declare type SelectOperation

= Omit, "id">; export declare type Selection

= Omit, "action">; export declare type Exportation = OakOperation<"export", ExportProjection, Filter, Sorter>; -export declare type CreateOperationData = FormCreateData> & (({ - parentId?: never | null; - parent?: CreateSingleOperation; -} | { - parentId?: String<64>; - parent?: UpdateOperation; -})) & { - [k: string]: any; - modi$parent?: OakOperation, Filter> | Array | Omit[]> | OakOperation, Filter>>; +export declare type CreateOperationData = FormCreateData> & ({ + entity?: string; + entityId?: string; + [K: string]: any; +}) & { modiEntity$modi?: OakOperation, ModiEntity.Filter> | Array | Omit[]> | OakOperation, ModiEntity.Filter>>; operEntity$entity?: OakOperation, OperEntity.Filter> | Array | Omit[]> | OakOperation, OperEntity.Filter>>; }; export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>; export declare type CreateMultipleOperation = OakOperation<"create", Array>; export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation; -export declare type UpdateOperationData = FormUpdateData> & (({ - parent?: CreateSingleOperation | UpdateOperation | RemoveOperation; - parentId?: undefined; -} | { - parent?: undefined; - parentId?: String<64> | null; -})) & { +export declare type UpdateOperationData = FormUpdateData & { [k: string]: any; - modis$parent?: UpdateOperation | RemoveOperation | Array | Omit[]> | UpdateOperation | RemoveOperation>; modiEntitys$modi?: ModiEntity.UpdateOperation | ModiEntity.RemoveOperation | Array | Omit[]> | ModiEntity.UpdateOperation | ModiEntity.RemoveOperation>; operEntitys$entity?: OperEntity.UpdateOperation | OperEntity.RemoveOperation | Array | Omit[]> | OperEntity.UpdateOperation | OperEntity.RemoveOperation>; }; export declare type UpdateOperation = OakOperation; -export declare type RemoveOperationData = {} & (({ - parent?: UpdateOperation; -} | { - parent?: RemoveOperation; -})); +export declare type RemoveOperationData = {}; export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation | SelectOperation; export declare type ModiIdSubQuery = Selection; -export declare type NativeAttr = OpAttr | `parent.${OpAttr}` | `parent.parent.${OpAttr}` | `parent.parent.parent.${OpAttr}`; -export declare type FullAttr = NativeAttr | `modis$${number}.${NativeAttr}` | `modiEntitys$${number}.${ModiEntity.NativeAttr}` | `operEntitys$${number}.${OperEntity.NativeAttr}`; +export declare type NativeAttr = OpAttr; +export declare type FullAttr = NativeAttr | `modiEntitys$${number}.${ModiEntity.NativeAttr}` | `operEntitys$${number}.${OperEntity.NativeAttr}`; export declare type EntityDef = { Schema: Schema; OpSchema: OpSchema; diff --git a/lib/base-app-domain/Modi/Storage.js b/lib/base-app-domain/Modi/Storage.js index d2aaa20..973fc6b 100644 --- a/lib/base-app-domain/Modi/Storage.js +++ b/lib/base-app-domain/Modi/Storage.js @@ -3,6 +3,24 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.desc = void 0; exports.desc = { attributes: { + targetEntity: { + type: "varchar", + params: { + length: 32 + } + }, + entity: { + type: "varchar", + params: { + length: 32 + } + }, + entityId: { + type: "varchar", + params: { + length: 64 + } + }, action: { type: "varchar", params: { @@ -18,10 +36,6 @@ exports.desc = { extra: { type: "object" }, - parentId: { - type: "ref", - ref: "modi" - }, iState: { type: "varchar", params: { diff --git a/lib/base-app-domain/ModiEntity/Schema.d.ts b/lib/base-app-domain/ModiEntity/Schema.d.ts index 744de18..bb397f6 100644 --- a/lib/base-app-domain/ModiEntity/Schema.d.ts +++ b/lib/base-app-domain/ModiEntity/Schema.d.ts @@ -37,6 +37,7 @@ declare type AttrFilter = { modi: Modi.Filter; entity: E; entityId: Q_StringValue; + user: User.Filter; }; export declare type Filter> = MakeFilter & ExprOp>; export declare type Projection = { @@ -99,7 +100,7 @@ export declare type Sorter = SortNode[]; export declare type SelectOperation

= Omit, "id">; export declare type Selection

= Omit, "action">; export declare type Exportation = OakOperation<"export", ExportProjection, Filter, Sorter>; -export declare type CreateOperationData = FormCreateData> & (({ +export declare type CreateOperationData = FormCreateData> & (({ modiId?: never | null; modi: Modi.CreateSingleOperation; } | { @@ -114,14 +115,14 @@ export declare type CreateOperationData = FormCreateData; user?: User.UpdateOperation; } | { + entity?: string; + entityId?: string; [K: string]: any; -}) & { - [k: string]: any; -}; +}); export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>; export declare type CreateMultipleOperation = OakOperation<"create", Array>; export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation; -export declare type UpdateOperationData = FormUpdateData> & (({ +export declare type UpdateOperationData = FormUpdateData> & (({ modi?: Modi.CreateSingleOperation | Modi.UpdateOperation | Modi.RemoveOperation; modiId?: undefined; } | { diff --git a/lib/base-app-domain/Oper/Schema.d.ts b/lib/base-app-domain/Oper/Schema.d.ts index f6003e1..5033030 100644 --- a/lib/base-app-domain/Oper/Schema.d.ts +++ b/lib/base-app-domain/Oper/Schema.d.ts @@ -110,7 +110,6 @@ export declare type CreateOperationData = FormCreateData; operator?: User.UpdateOperation; })) & { - [k: string]: any; operEntity$oper?: OakOperation, OperEntity.Filter> | Array | Omit[]> | OakOperation, OperEntity.Filter>>; }; export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>; diff --git a/lib/base-app-domain/OperEntity/Schema.d.ts b/lib/base-app-domain/OperEntity/Schema.d.ts index 4956124..3e54054 100644 --- a/lib/base-app-domain/OperEntity/Schema.d.ts +++ b/lib/base-app-domain/OperEntity/Schema.d.ts @@ -39,6 +39,8 @@ declare type AttrFilter = { oper: Oper.Filter; entity: E; entityId: Q_StringValue; + modi: Modi.Filter; + user: User.Filter; }; export declare type Filter> = MakeFilter & ExprOp>; export declare type Projection = { @@ -108,7 +110,7 @@ export declare type Sorter = SortNode[]; export declare type SelectOperation

= Omit, "id">; export declare type Selection

= Omit, "action">; export declare type Exportation = OakOperation<"export", ExportProjection, Filter, Sorter>; -export declare type CreateOperationData = FormCreateData> & (({ +export declare type CreateOperationData = FormCreateData> & (({ operId?: never | null; oper: Oper.CreateSingleOperation; } | { @@ -131,14 +133,14 @@ export declare type CreateOperationData = FormCreateData; user?: User.UpdateOperation; } | { + entity?: string; + entityId?: string; [K: string]: any; -}) & { - [k: string]: any; -}; +}); export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>; export declare type CreateMultipleOperation = OakOperation<"create", Array>; export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation; -export declare type UpdateOperationData = FormUpdateData> & (({ +export declare type UpdateOperationData = FormUpdateData> & (({ oper?: Oper.CreateSingleOperation | Oper.UpdateOperation | Oper.RemoveOperation; operId?: undefined; } | { diff --git a/lib/base-app-domain/User/Schema.d.ts b/lib/base-app-domain/User/Schema.d.ts index 21cab8d..ffcddd1 100644 --- a/lib/base-app-domain/User/Schema.d.ts +++ b/lib/base-app-domain/User/Schema.d.ts @@ -105,7 +105,6 @@ export declare type SelectOperation

= Omit = Omit, "action">; export declare type Exportation = OakOperation<"export", ExportProjection, Filter, Sorter>; export declare type CreateOperationData = FormCreateData & { - [k: string]: any; oper$operator?: OakOperation, Oper.Filter> | Array | Omit[]> | OakOperation, Oper.Filter>>; operEntity$entity?: OakOperation, OperEntity.Filter> | Array | Omit[]> | OakOperation, OperEntity.Filter>>; modiEntity$entity?: OakOperation, ModiEntity.Filter> | Array | Omit[]> | OakOperation, ModiEntity.Filter>>; diff --git a/lib/base-app-domain/_SubQuery.d.ts b/lib/base-app-domain/_SubQuery.d.ts index 8555bb8..4b68ed6 100644 --- a/lib/base-app-domain/_SubQuery.d.ts +++ b/lib/base-app-domain/_SubQuery.d.ts @@ -4,9 +4,7 @@ import * as Oper from "./Oper/Schema"; import * as OperEntity from "./OperEntity/Schema"; import * as User from "./User/Schema"; export declare type ModiIdSubQuery = { - [K in "$in" | "$nin"]?: (Modi.ModiIdSubQuery & { - entity: "modi"; - }) | (ModiEntity.ModiIdSubQuery & { + [K in "$in" | "$nin"]?: (ModiEntity.ModiIdSubQuery & { entity: "modiEntity"; }) | (Modi.ModiIdSubQuery & { entity: "modi"; diff --git a/lib/compiler/env.d.ts b/lib/compiler/env.d.ts index 4eba91d..2c217c4 100644 --- a/lib/compiler/env.d.ts +++ b/lib/compiler/env.d.ts @@ -1,6 +1,7 @@ export declare const LIB_OAK_DOMAIN = "oak-domain"; export declare const LIB_PATH: () => string; export declare const ENTITY_PATH_IN_OAK_GENERAL_BUSINESS: () => string; +export declare const ENTITY_PATH_IN_OAK_DOMAIN: () => string; export declare const TYPE_PATH_IN_OAK_DOMAIN: (level?: number) => string; export declare const ACTION_CONSTANT_IN_OAK_DOMAIN: (level?: number) => string; export declare const RESERVED_ENTITIES: string[]; diff --git a/lib/compiler/env.js b/lib/compiler/env.js index 12a064f..0991562 100644 --- a/lib/compiler/env.js +++ b/lib/compiler/env.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.INT_LITERL_DEFAULT_WIDTH = exports.NUMERICAL_LITERL_DEFAULT_SCALE = exports.NUMERICAL_LITERL_DEFAULT_PRECISION = exports.STRING_LITERAL_MAX_LENGTH = exports.RESERVED_ENTITIES = exports.ACTION_CONSTANT_IN_OAK_DOMAIN = exports.TYPE_PATH_IN_OAK_DOMAIN = exports.ENTITY_PATH_IN_OAK_GENERAL_BUSINESS = exports.LIB_PATH = exports.LIB_OAK_DOMAIN = void 0; +exports.INT_LITERL_DEFAULT_WIDTH = exports.NUMERICAL_LITERL_DEFAULT_SCALE = exports.NUMERICAL_LITERL_DEFAULT_PRECISION = exports.STRING_LITERAL_MAX_LENGTH = exports.RESERVED_ENTITIES = exports.ACTION_CONSTANT_IN_OAK_DOMAIN = exports.TYPE_PATH_IN_OAK_DOMAIN = exports.ENTITY_PATH_IN_OAK_DOMAIN = exports.ENTITY_PATH_IN_OAK_GENERAL_BUSINESS = exports.LIB_PATH = exports.LIB_OAK_DOMAIN = void 0; exports.LIB_OAK_DOMAIN = 'oak-domain'; var LIB_OAK_GENERAL_BUSINESS = 'oak-general-business'; var LIB_PATH = function () { return 'lib'; }; @@ -10,6 +10,10 @@ var ENTITY_PATH_IN_OAK_GENERAL_BUSINESS = function () { return "".concat(LIB_OAK_GENERAL_BUSINESS, "/").concat((0, exports.LIB_PATH)(), "/entities/"); }; exports.ENTITY_PATH_IN_OAK_GENERAL_BUSINESS = ENTITY_PATH_IN_OAK_GENERAL_BUSINESS; +var ENTITY_PATH_IN_OAK_DOMAIN = function () { + return "".concat(exports.LIB_OAK_DOMAIN, "/").concat((0, exports.LIB_PATH)(), "/entities/"); +}; +exports.ENTITY_PATH_IN_OAK_DOMAIN = ENTITY_PATH_IN_OAK_DOMAIN; var TYPE_PATH_IN_OAK_DOMAIN = function (level) { if (level === void 0) { level = 2; } if (process.env.COMPLING_IN_DOMAIN) { diff --git a/lib/compiler/schemalBuilder.js b/lib/compiler/schemalBuilder.js index cd673a5..592fc74 100644 --- a/lib/compiler/schemalBuilder.js +++ b/lib/compiler/schemalBuilder.js @@ -256,6 +256,9 @@ function getEntityImported(declaration, filename) { else if (moduleSpecifier.text.startsWith((0, env_1.ENTITY_PATH_IN_OAK_GENERAL_BUSINESS)())) { entityImported = moduleSpecifier.text.slice((0, env_1.ENTITY_PATH_IN_OAK_GENERAL_BUSINESS)().length); } + else if (moduleSpecifier.text.startsWith((0, env_1.ENTITY_PATH_IN_OAK_DOMAIN)())) { + entityImported = moduleSpecifier.text.slice((0, env_1.ENTITY_PATH_IN_OAK_DOMAIN)().length); + } } if (entityImported) { var namedBindings = importClause.namedBindings; @@ -311,6 +314,7 @@ function analyzeEntity(filename, path, program) { var hasActionDef = false; var hasRelationDef = false; var hasActionOrStateDef = false; + var toModi = false; var enumStringAttrs = []; var states = []; var localEnumStringTypes = []; @@ -332,8 +336,8 @@ function analyzeEntity(filename, path, program) { var members = node.members, heritageClauses = node.heritageClauses; (0, assert_1.default)(['EntityShape', 'FileCarrierEntityShape'].includes(heritageClauses[0].types[0].expression.text)); members.forEach(function (attrNode) { - var _a; - var _b = attrNode, type = _b.type, name = _b.name, questionToken = _b.questionToken; + var _a, _b; + var _c = attrNode, type = _c.type, name = _c.name, questionToken = _c.questionToken; var attrName = name.text; if (ts.isTypeReferenceNode(type) && ts.isIdentifier(type.typeName)) { @@ -357,6 +361,9 @@ function analyzeEntity(filename, path, program) { _a[reverseEntity] = [moduleName], _a)); } + if (reverseEntity === 'Modi') { + toModi = true; + } } else { schemaAttrs.push(attrNode); @@ -365,6 +372,27 @@ function analyzeEntity(filename, path, program) { } } } + else if (ts.isArrayTypeNode(type) && ts.isTypeReferenceNode(type.elementType) && ts.isIdentifier(type.elementType.typeName)) { + var typeName = type.elementType.typeName; + if (referencedSchemas.includes(typeName.text)) { + // 这也是一对多的反指定义 + var reverseEntity = typeName.text; + if (ReversePointerRelations[reverseEntity]) { + ReversePointerRelations[reverseEntity].push(moduleName); + } + else { + (0, lodash_1.assign)(ReversePointerRelations, (_b = {}, + _b[reverseEntity] = [moduleName], + _b)); + } + if (reverseEntity === 'Modi') { + toModi = true; + } + } + else { + throw new Error("\u5BF9\u8C61".concat(moduleName, "\u4E2D\u5B9A\u4E49\u7684\u5C5E\u6027").concat(attrName, "\u662F\u4E0D\u53EF\u8BC6\u522B\u7684\u6570\u7EC4\u7C7B\u522B")); + } + } else { schemaAttrs.push(attrNode); if (ts.isUnionTypeNode(type)) { @@ -381,7 +409,7 @@ function analyzeEntity(filename, path, program) { if (type.typeName.text === 'String' && typeArguments && typeArguments.length === 1) { - var _c = tslib_1.__read(typeArguments, 1), node_1 = _c[0]; + var _d = tslib_1.__read(typeArguments, 1), node_1 = _d[0]; if (ts.isLiteralTypeNode(node_1) && ts.isNumericLiteral(node_1.literal)) { if (parseInt(node_1.literal.text) > 32) { console.warn("\u300C\u300D\u4E2Dentity\u5C5E\u6027\u5B9A\u4E49\u7684\u957F\u5EA6\u5927\u4E8E32\uFF0C\u8BF7\u786E\u8BA4\u5B83\u4E0D\u662F\u4E00\u4E2A\u53CD\u6307\u5BF9\u8C61"); @@ -399,7 +427,7 @@ function analyzeEntity(filename, path, program) { if (type.typeName.text === 'String' && typeArguments && typeArguments.length === 1) { - var _d = tslib_1.__read(typeArguments, 1), node_2 = _d[0]; + var _e = tslib_1.__read(typeArguments, 1), node_2 = _e[0]; if (ts.isLiteralTypeNode(node_2) && ts.isNumericLiteral(node_2.literal)) { if (parseInt(node_2.literal.text) !== 64) { console.warn("\u300C".concat(filename, "\u300D\u4E2DentityId\u5C5E\u6027\u5B9A\u4E49\u7684\u957F\u5EA6\u4E0D\u7B49\u4E8E64\uFF0C\u8BF7\u786E\u8BA4\u5B83\u4E0D\u662F\u4E00\u4E2A\u53CD\u6307\u5BF9\u8C61")); @@ -417,7 +445,7 @@ function analyzeEntity(filename, path, program) { _a)); } beforeSchema = false; - // 对于不是Oper的对象,全部建立和Oper的反指关系 + // 对于不是Oper的对象,全部建立和OperEntity的反指关系 if (!['Oper', 'OperEntity', 'ModiEntity'].includes(moduleName)) { if (ReversePointerRelations['OperEntity'] && !ReversePointerRelations['OperEntity'].includes(moduleName)) { ReversePointerRelations['OperEntity'].push(moduleName); @@ -427,8 +455,8 @@ function analyzeEntity(filename, path, program) { _b['OperEntity'] = [moduleName], _b)); } - // 对于不是Modi的对象,全部建立和Modi的反指关系 - if (!['Modi'].includes(moduleName)) { + // 对于不是Modi的对象,全部建立和ModiEntity的反指关系 + if (!['Modi'].includes(moduleName) && !toModi) { if (ReversePointerRelations['ModiEntity'] && !ReversePointerRelations['ModiEntity'].includes(moduleName)) { ReversePointerRelations['ModiEntity'].push(moduleName); } @@ -722,6 +750,7 @@ function analyzeEntity(filename, path, program) { var schema = { schemaAttrs: schemaAttrs, sourceFile: sourceFile, + toModi: toModi, }; if (hasFulltextIndex) { (0, lodash_1.assign)(schema, { @@ -1022,6 +1051,12 @@ function constructFilter(statements, entity) { finally { if (e_3) throw e_3.error; } } // type AttrFilter = {}; + if (ReversePointerRelations[entity]) { + // 有反向指针,将反向指针关联的对象的Filter也注入 + ReversePointerRelations[entity].forEach(function (ele) { + return members.push(factory.createPropertySignature(undefined, (0, string_1.firstLetterLowerCase)(ele), undefined, factory.createTypeReferenceNode(createForeignRef(entity, ele, 'Filter')))); + }); + } var eumUnionTypeNode = ReversePointerRelations[entity] && ReversePointerRelations[entity].map(function (ele) { return factory.createLiteralTypeNode(factory.createStringLiteral((0, string_1.firstLetterLowerCase)(ele))); }); if (process.env.COMPLING_AS_LIB) { eumUnionTypeNode && eumUnionTypeNode.push(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)); @@ -1655,6 +1690,9 @@ function constructActions(statements, entity) { } // CreateOperationData var foreignKeyAttr = []; + if (ReversePointerEntities[entity]) { + foreignKeyAttr.push('entity', 'entityId'); + } if (manyToOneSet) { try { for (var manyToOneSet_2 = tslib_1.__values(manyToOneSet), manyToOneSet_2_1 = manyToOneSet_2.next(); !manyToOneSet_2_1.done; manyToOneSet_2_1 = manyToOneSet_2.next()) { @@ -1671,9 +1709,6 @@ function constructActions(statements, entity) { } finally { if (e_10) throw e_10.error; } } - if (ReversePointerEntities[entity]) { - foreignKeyAttr.push('entity', 'entityId'); - } } var adNodes = [ factory.createTypeReferenceNode(factory.createIdentifier("FormCreateData"), [ @@ -1720,7 +1755,12 @@ function constructActions(statements, entity) { } finally { if (e_11) throw e_11.error; } } - var reverseOneNodes = []; + if (upsertOneNodes.length > 0) { + adNodes.push(factory.createIntersectionTypeNode(upsertOneNodes)); + } + } + var reverseOneNodes = []; + if (ReversePointerEntities[entity]) { if (ReversePointerRelations[entity]) { try { for (var _q = tslib_1.__values(ReversePointerRelations[entity]), _r = _q.next(); !_r.done; _r = _q.next()) { @@ -1746,15 +1786,14 @@ function constructActions(statements, entity) { } finally { if (e_12) throw e_12.error; } } - if (process.env.COMPLING_AS_LIB) { - // 如果是base,要包容更多可能的反指 - reverseOneNodes.push(factory.createTypeLiteralNode([ - 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 (upsertOneNodes.length > 0) { - adNodes.push(factory.createIntersectionTypeNode(upsertOneNodes)); + 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, undefined, [factory.createParameterDeclaration(undefined, 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)); @@ -1762,9 +1801,24 @@ function constructActions(statements, entity) { } // 一对多 var propertySignatures = []; - if (process.env.COMPLING_AS_LIB) { - propertySignatures.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 (process.env.COMPLING_AS_LIB) { + propertySignatures.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) { var _loop_8 = function (entityName) { var entityNameLc = (0, string_1.firstLetterLowerCase)(entityName); @@ -1831,6 +1885,9 @@ function constructActions(statements, entity) { ]))); // UpdateOperationData foreignKeyAttr = []; + if (ReversePointerRelations[entity]) { + foreignKeyAttr.push('entity', 'entityId'); + } if (manyToOneSet) { try { for (var manyToOneSet_4 = tslib_1.__values(manyToOneSet), manyToOneSet_4_1 = manyToOneSet_4.next(); !manyToOneSet_4_1.done; manyToOneSet_4_1 = manyToOneSet_4.next()) { @@ -1847,9 +1904,6 @@ function constructActions(statements, entity) { } finally { if (e_13) throw e_13.error; } } - if (ReversePointerRelations[entity]) { - foreignKeyAttr.push('entity', 'entityId'); - } } adNodes = [ factory.createTypeReferenceNode(factory.createIdentifier("FormUpdateData"), [ @@ -1901,14 +1955,14 @@ function constructActions(statements, entity) { if (upsertOneNodes.length > 0) { adNodes.push(factory.createIntersectionTypeNode(upsertOneNodes)); } - var reverseOneNodes = []; + var reverseOneNodes_1 = []; if (ReversePointerRelations[entity]) { var refEntityLitrals = []; try { for (var _s = tslib_1.__values(ReversePointerRelations[entity]), _t = _s.next(); !_t.done; _t = _s.next()) { var one = _t.value; refEntityLitrals.push(factory.createLiteralTypeNode(factory.createStringLiteral("".concat((0, string_1.firstLetterLowerCase)(one))))); - reverseOneNodes.push(factory.createTypeLiteralNode([ + reverseOneNodes_1.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, 'CreateSingleOperation')), factory.createTypeReferenceNode(createForeignRef(entity, one, 'UpdateOperation')), @@ -1930,7 +1984,7 @@ function constructActions(statements, entity) { // 如果是base,要包容更多可能的反指 refEntityLitrals.push(factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)); } - reverseOneNodes.push(factory.createTypeLiteralNode([ + reverseOneNodes_1.push(factory.createTypeLiteralNode([ factory.createPropertySignature(undefined, factory.createIdentifier('entity'), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createUnionTypeNode([ factory.createUnionTypeNode(refEntityLitrals), factory.createLiteralTypeNode(factory.createNull()) @@ -1941,8 +1995,8 @@ function constructActions(statements, entity) { ])) ])); } - if (reverseOneNodes.length > 0) { - adNodes.push(factory.createUnionTypeNode(reverseOneNodes)); + if (reverseOneNodes_1.length > 0) { + adNodes.push(factory.createUnionTypeNode(reverseOneNodes_1)); } } var propertySignatures2 = []; @@ -2039,14 +2093,14 @@ function constructActions(statements, entity) { } finally { if (e_16) throw e_16.error; } } - var reverseOneNodes = []; + var reverseOneNodes_2 = []; if (ReversePointerRelations[entity]) { var refEntityLitrals = []; try { for (var _u = tslib_1.__values(ReversePointerRelations[entity]), _v = _u.next(); !_v.done; _v = _u.next()) { var one = _v.value; refEntityLitrals.push(factory.createLiteralTypeNode(factory.createStringLiteral("".concat((0, string_1.firstLetterLowerCase)(one))))); - reverseOneNodes.push(factory.createTypeLiteralNode([ + reverseOneNodes_2.push(factory.createTypeLiteralNode([ factory.createPropertySignature(undefined, factory.createIdentifier((0, string_1.firstLetterLowerCase)(one)), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(createForeignRef(entity, one, 'UpdateOperation'))) ]), factory.createTypeLiteralNode([ factory.createPropertySignature(undefined, factory.createIdentifier((0, string_1.firstLetterLowerCase)(one)), factory.createToken(ts.SyntaxKind.QuestionToken), factory.createTypeReferenceNode(createForeignRef(entity, one, 'RemoveOperation'))) @@ -2061,7 +2115,7 @@ function constructActions(statements, entity) { finally { if (e_17) throw e_17.error; } } if (process.env.COMPLING_AS_LIB) { - reverseOneNodes.push(factory.createTypeLiteralNode([ + reverseOneNodes_2.push(factory.createTypeLiteralNode([ factory.createIndexSignature(undefined, undefined, [factory.createParameterDeclaration(undefined, undefined, undefined, factory.createIdentifier("k"), undefined, factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword), undefined)], factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword)) ])); } @@ -2069,8 +2123,8 @@ function constructActions(statements, entity) { if (upsertOneNodes.length > 0) { adNodes.push(factory.createIntersectionTypeNode(upsertOneNodes)); } - if (reverseOneNodes.length > 0) { - adNodes.push(factory.createUnionTypeNode(reverseOneNodes)); + if (reverseOneNodes_2.length > 0) { + adNodes.push(factory.createUnionTypeNode(reverseOneNodes_2)); } } /** @@ -2585,7 +2639,7 @@ function outputStorage(outputDir, printer) { var entityAssignments = []; for (var entity in Schema) { var indexExpressions = []; - var _a = Schema[entity], sourceFile = _a.sourceFile, fulltextIndex = _a.fulltextIndex, indexes = _a.indexes; + var _a = Schema[entity], sourceFile = _a.sourceFile, fulltextIndex = _a.fulltextIndex, indexes = _a.indexes, toModi = _a.toModi; var statements = [ factory.createImportDeclaration(undefined, undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, undefined, factory.createIdentifier("StorageDesc"))])), factory.createStringLiteral("".concat((0, env_1.TYPE_PATH_IN_OAK_DOMAIN)(), "Storage")), undefined), factory.createImportDeclaration(undefined, undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, undefined, factory.createIdentifier("OpSchema"))])), factory.createStringLiteral("./Schema"), undefined) @@ -2596,6 +2650,9 @@ function outputStorage(outputDir, printer) { if (indexes) { indexExpressions.push.apply(indexExpressions, tslib_1.__spreadArray([], tslib_1.__read(indexes.elements), false)); } + if (toModi) { + propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("toModi"), factory.createTrue())); + } if (indexExpressions.length > 0) { propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("indexes"), factory.createArrayLiteralExpression(indexExpressions, true))); } diff --git a/lib/entities/Modi.d.ts b/lib/entities/Modi.d.ts index 12daade..9bfb641 100644 --- a/lib/entities/Modi.d.ts +++ b/lib/entities/Modi.d.ts @@ -1,9 +1,11 @@ import { String } from '../types/DataType'; import { EntityShape } from '../types/Entity'; export interface Schema extends EntityShape { + targetEntity: String<32>; + entity: String<32>; + entityId: String<64>; action: String<16>; data: Object; filter?: Object; extra?: Object; - parent?: Schema; } diff --git a/lib/entities/Modi.js b/lib/entities/Modi.js index c374a7f..5beec49 100644 --- a/lib/entities/Modi.js +++ b/lib/entities/Modi.js @@ -22,12 +22,14 @@ var indexes = [ var locale = { zh_CN: { attr: { + targetEntity: '目标对象', + entity: '关联对象', + entityId: '关联对象Id', action: '动作', data: '数据', filter: '条件', extra: '其它', iState: '状态', - parent: '关联父更新' }, action: { abandon: '放弃', diff --git a/lib/store/CascadeStore.js b/lib/store/CascadeStore.js index 4e612a9..529ad68 100644 --- a/lib/store/CascadeStore.js +++ b/lib/store/CascadeStore.js @@ -6,7 +6,6 @@ var assert_1 = tslib_1.__importDefault(require("assert")); var RowStore_1 = require("../types/RowStore"); var filter_1 = require("./filter"); var relation_1 = require("./relation"); -var action_1 = require("./action"); var types_1 = require("../types"); var lodash_1 = require("../utils/lodash"); /**这个用来处理级联的select和update,对不同能力的 */ @@ -295,15 +294,23 @@ var CascadeStore = /** @class */ (function (_super) { }; CascadeStore.prototype.destructCascadeUpdate = function (entity, action, data, context, option, result, filter) { return tslib_1.__awaiter(this, void 0, void 0, function () { - var opData, laterAction, _loop_1, this_1, _a, _b, _i, attr; + var modiAttr, option2, opData, _loop_1, this_1, _a, _b, _i, attr; var _this = this; return tslib_1.__generator(this, function (_c) { switch (_c.label) { case 0: + modiAttr = this.getSchema()[entity].toModi; + option2 = Object.assign({}, option); opData = {}; - laterAction = (0, action_1.isLaterAction)(action); + if (modiAttr && action !== 'remove') { + // create/update具有modi对象的对象,对其子对象的update行为全部是create modi对象(缓存动作) + // delete是什么情况?似乎应该先把所有的modi给abandon掉 by Xc + (0, assert_1.default)(!option2.modiParentId && !option2.modiParentEntity); + option2.modiParentId = data.id; + option2.modiParentEntity = entity; + } _loop_1 = function (attr) { - var relation, operationMto, actionMto, dataMto, filterMto, subLaterAction, laterLine, fkId, entity_1, result2, operationMto, actionMto, dataMto, filterMto, subLaterAction, _d, _e, fkId, result2, _f, entityOtm_1, foreignKey_1, otmOperations, dealWithOneToMany, otmOperations_1, otmOperations_1_1, oper, e_1_1; + var relation, operationMto, actionMto, dataMto, filterMto, fkId, entity_1, result2, operationMto, actionMto, dataMto, filterMto, _d, _e, fkId, result2, _f, entityOtm_1, foreignKey_1, otmOperations, dealWithOneToMany, otmOperations_1, otmOperations_1_1, oper, e_1_1; var _g, _h, _j, e_1, _k; return tslib_1.__generator(this, function (_l) { switch (_l.label) { @@ -318,28 +325,7 @@ var CascadeStore = /** @class */ (function (_super) { if (!(relation === 2)) return [3 /*break*/, 3]; operationMto = data[attr]; actionMto = operationMto.action, dataMto = operationMto.data, filterMto = operationMto.filter; - subLaterAction = (0, action_1.isLaterAction)(actionMto); - laterLine = false; - if (laterAction) { - (0, assert_1.default)(subLaterAction, '所有延时动作的子对象的动作也必须是延时的'); - } - else if (subLaterAction) { - if (!laterAction) { - laterLine = true; - } - } - if (laterLine) { - // 如果是对子对象的延时更新,此时对子对象的更新被转换成对Modi对象的插入 - (0, assert_1.default)(action === 'create', '延时更新必须是在对父级的申请对象create动作时进行'); - Object.assign(opData, { - entity: 'modi', - entityId: operationMto.id, - }); - Object.assign(option, { - parentModiId: operationMto.id, - }); - } - else if (actionMto === 'create') { + if (actionMto === 'create') { Object.assign(opData, { entityId: dataMto.id, entity: attr, @@ -374,7 +360,7 @@ var CascadeStore = /** @class */ (function (_super) { }, filterMto), }); } - return [4 /*yield*/, this_1.cascadeUpdate(attr, operationMto, context, option)]; + return [4 /*yield*/, this_1.cascadeUpdate(attr, operationMto, context, option2)]; case 2: result2 = _l.sent(); this_1.mergeOperationResult(result, result2); @@ -383,8 +369,6 @@ var CascadeStore = /** @class */ (function (_super) { if (!(typeof relation === 'string')) return [3 /*break*/, 5]; operationMto = data[attr]; actionMto = operationMto.action, dataMto = operationMto.data, filterMto = operationMto.filter; - subLaterAction = (0, action_1.isLaterAction)(actionMto); - (0, assert_1.default)(laterAction && subLaterAction || !laterAction && !subLaterAction, '延时动作的子对象的动作也必须是延时动作'); if (actionMto === 'create') { Object.assign(opData, (_h = {}, _h["".concat(attr, "Id")] = dataMto.id, @@ -415,7 +399,7 @@ var CascadeStore = /** @class */ (function (_super) { }), }); } - return [4 /*yield*/, this_1.cascadeUpdate(relation, operationMto, context, option)]; + return [4 /*yield*/, this_1.cascadeUpdate(relation, operationMto, context, option2)]; case 4: result2 = _l.sent(); this_1.mergeOperationResult(result, result2); @@ -425,14 +409,12 @@ var CascadeStore = /** @class */ (function (_super) { _f = tslib_1.__read(relation, 2), entityOtm_1 = _f[0], foreignKey_1 = _f[1]; otmOperations = data[attr]; dealWithOneToMany = function (otm) { return tslib_1.__awaiter(_this, void 0, void 0, function () { - var actionOtm, dataOtm, filterOtm, subLaterAction, id_1, id_2, id, id_3, id_4, id, result2; + var actionOtm, dataOtm, filterOtm, id_1, id_2, id, id_3, id_4, id, result2; var _a, _b, _c, _d; return tslib_1.__generator(this, function (_e) { switch (_e.label) { case 0: actionOtm = otm.action, dataOtm = otm.data, filterOtm = otm.filter; - subLaterAction = (0, action_1.isLaterAction)(actionOtm); - (0, assert_1.default)(laterAction && subLaterAction || !laterAction && !subLaterAction, '延时动作的子对象的动作也必须是延时动作'); if (!foreignKey_1) { // 基于entity/entityId的one-to-many if (action === 'create') { @@ -531,7 +513,7 @@ var CascadeStore = /** @class */ (function (_super) { } } } - return [4 /*yield*/, this.cascadeUpdate(entityOtm_1, otm, context, option)]; + return [4 /*yield*/, this.cascadeUpdate(entityOtm_1, otm, context, option2)]; case 1: result2 = _e.sent(); this.mergeOperationResult(result, result2); @@ -633,7 +615,7 @@ var CascadeStore = /** @class */ (function (_super) { case 0: action = operation.action, data = operation.data, filter = operation.filter, id = operation.id; result = {}; - if (!(['create', 'create-l'].includes(action) && data instanceof Array)) return [3 /*break*/, 17]; + if (!(['create', 'create-l'].includes(action) && data instanceof Array)) return [3 /*break*/, 18]; multipleCreate = this.supportMultipleCreate(); if (!multipleCreate) return [3 /*break*/, 9]; opData = []; @@ -648,9 +630,7 @@ var CascadeStore = /** @class */ (function (_super) { return [4 /*yield*/, this.destructCascadeUpdate(entity, action, d, context, option, result)]; case 3: od = _e.sent(); - if (Object.keys(od).length > 0) { - opData.push(od); - } + opData.push(od); _e.label = 4; case 4: data_1_1 = data_1.next(); @@ -666,7 +646,7 @@ var CascadeStore = /** @class */ (function (_super) { } finally { if (e_2) throw e_2.error; } return [7 /*endfinally*/]; - case 8: return [3 /*break*/, 16]; + case 8: return [3 /*break*/, 17]; case 9: _e.trys.push([9, 14, 15, 16]); data_2 = tslib_1.__values(data), data_2_1 = data_2.next(); @@ -698,16 +678,17 @@ var CascadeStore = /** @class */ (function (_super) { finally { if (e_3) throw e_3.error; } return [7 /*endfinally*/]; case 16: return [2 /*return*/, result]; - case 17: return [4 /*yield*/, this.destructCascadeUpdate(entity, action, data, context, option, result, filter)]; - case 18: - opData = _e.sent(); - _e.label = 19; + case 17: return [3 /*break*/, 20]; + case 18: return [4 /*yield*/, this.destructCascadeUpdate(entity, action, data, context, option, result, filter)]; case 19: + opData = _e.sent(); + _e.label = 20; + case 20: operation2 = Object.assign({}, operation, { data: opData, }); return [4 /*yield*/, this.doUpdateSingleRow(entity, operation2, context, option)]; - case 20: + case 21: count = _e.sent(); this.mergeOperationResult(result, (_c = {}, _c[entity] = (_d = {}, @@ -728,26 +709,39 @@ var CascadeStore = /** @class */ (function (_super) { */ CascadeStore.prototype.doUpdateSingleRow = function (entity, operation, context, option) { return tslib_1.__awaiter(this, void 0, void 0, function () { - var data, action, operId, filter, now, laterAction, _a, addTimestamp_1, result, e_4, congruentRow_1, rest, result2, row, updateData, result3, _b, _c, updateData, result2, _d, _e, createOper, _f, ids, selection, rows, result, createOper; - var _g, _h, _j, _k, _l, _m, _o, _p; + var data, action, operId, filter, now, _a, modiCreate, addTimestamp_1, result, e_4, congruentRow_1, rest, result2, row, updateData, result3, _b, _c, updateData, result2, _d, _e, createOper, _f, ids, selection, rows, modiCreate, result, createOper; + var _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t; var _this = this; - return tslib_1.__generator(this, function (_q) { - switch (_q.label) { + return tslib_1.__generator(this, function (_u) { + switch (_u.label) { case 0: data = operation.data, action = operation.action, operId = operation.id, filter = operation.filter; now = Date.now(); - laterAction = (0, action_1.isLaterAction)(action); - _a = action || laterAction; + _a = action; switch (_a) { case 'create': return [3 /*break*/, 1]; } - return [3 /*break*/, 22]; + return [3 /*break*/, 23]; case 1: - if (!laterAction) return [3 /*break*/, 2]; - // 变成对modi的插入 - (0, assert_1.default)(false, '还未实现'); - return [3 /*break*/, 22]; + if (!(option.modiParentEntity && !['modi', 'modiEntity'].includes(entity))) return [3 /*break*/, 3]; + modiCreate = { + id: 'dummy', + action: 'create', + data: { + id: operId, + targetEntity: entity, + action: action, + entity: option.modiParentEntity, + entityId: option.modiParentId, + data: data, + iState: 'active', + }, + }; + return [4 /*yield*/, this.cascadeUpdate('modi', modiCreate, context, option)]; case 2: + _u.sent(); + return [2 /*return*/, 1]; + case 3: addTimestamp_1 = function (data2) { Object.assign(data2, { $$createAt$$: now, @@ -761,19 +755,19 @@ var CascadeStore = /** @class */ (function (_super) { addTimestamp_1(data); } result = void 0; - _q.label = 3; - case 3: - _q.trys.push([3, 5, , 14]); - return [4 /*yield*/, this.updateAbjointRow(entity, operation, context, option)]; + _u.label = 4; case 4: - result = _q.sent(); - return [3 /*break*/, 14]; + _u.trys.push([4, 6, , 15]); + return [4 /*yield*/, this.updateAbjointRow(entity, operation, context, option)]; case 5: - e_4 = _q.sent(); - if (!(e_4 instanceof types_1.OakCongruentRowExists)) return [3 /*break*/, 13]; - if (!option.allowExists) return [3 /*break*/, 12]; + result = _u.sent(); + return [3 /*break*/, 15]; + case 6: + e_4 = _u.sent(); + if (!(e_4 instanceof types_1.OakCongruentRowExists)) return [3 /*break*/, 14]; + if (!option.allowExists) return [3 /*break*/, 13]; congruentRow_1 = e_4.getData(); - if (!(data instanceof Array)) return [3 /*break*/, 9]; + if (!(data instanceof Array)) return [3 /*break*/, 10]; rest = data.filter(function (ele) { return ele.id !== congruentRow_1.id; }); if (rest.length === data.length) { throw e_4; @@ -781,15 +775,15 @@ var CascadeStore = /** @class */ (function (_super) { return [4 /*yield*/, this.updateAbjointRow(entity, Object.assign({}, operation, { data: rest, }), context, option)]; - case 6: - result2 = _q.sent(); + case 7: + result2 = _u.sent(); row = data.find(function (ele) { return ele.id === congruentRow_1.id; }); updateData = (0, lodash_1.omit)(row, ['id', '$$createAt$$']); _b = this.updateAbjointRow; _c = [entity]; _g = {}; return [4 /*yield*/, generateNewId()]; - case 7: return [4 /*yield*/, _b.apply(this, _c.concat([(_g.id = _q.sent(), + case 8: return [4 /*yield*/, _b.apply(this, _c.concat([(_g.id = _u.sent(), _g.action = 'update', _g.data = updateData, _g.filter = { @@ -797,10 +791,10 @@ var CascadeStore = /** @class */ (function (_super) { }, _g), context, option]))]; - case 8: - result3 = _q.sent(); - return [2 /*return*/, result2 + result3]; case 9: + result3 = _u.sent(); + return [2 /*return*/, result2 + result3]; + case 10: if (data.id !== congruentRow_1.id) { throw e_4; } @@ -809,7 +803,7 @@ var CascadeStore = /** @class */ (function (_super) { _e = [entity]; _h = {}; return [4 /*yield*/, generateNewId()]; - case 10: return [4 /*yield*/, _d.apply(this, _e.concat([(_h.id = _q.sent(), + case 11: return [4 /*yield*/, _d.apply(this, _e.concat([(_h.id = _u.sent(), _h.action = 'update', _h.data = updateData, _h.filter = { @@ -817,12 +811,12 @@ var CascadeStore = /** @class */ (function (_super) { }, _h), context, option]))]; - case 11: - result2 = _q.sent(); + case 12: + result2 = _u.sent(); return [2 /*return*/, result2]; - case 12: throw e_4; - case 13: return [3 /*break*/, 14]; - case 14: + case 13: throw e_4; + case 14: return [3 /*break*/, 15]; + case 15: if (!option.dontCollect) { context.opRecords.push({ a: 'c', @@ -830,7 +824,7 @@ var CascadeStore = /** @class */ (function (_super) { d: data, }); } - if (!(!option.dontCreateOper && !['oper', 'operEntity', 'modiEntity'].includes(entity))) return [3 /*break*/, 21]; + if (!(!option.dontCreateOper && !['oper', 'operEntity', 'modiEntity'].includes(entity))) return [3 /*break*/, 22]; // 按照框架要求生成Oper和OperEntity这两个内置的对象 (0, assert_1.default)(operId); _j = { @@ -843,46 +837,46 @@ var CascadeStore = /** @class */ (function (_super) { data: data }; return [4 /*yield*/, context.getCurrentUserId()]; - case 15: - _k.operatorId = _q.sent(); - if (!(data instanceof Array)) return [3 /*break*/, 17]; - return [4 /*yield*/, Promise.all(data.map(function (ele) { return tslib_1.__awaiter(_this, void 0, void 0, function () { - var _a, _b; - return tslib_1.__generator(this, function (_c) { - switch (_c.label) { - case 0: - _a = { - id: 'dummy', - action: 'create' - }; - _b = {}; - return [4 /*yield*/, generateNewId()]; - case 1: return [2 /*return*/, (_a.data = (_b.id = _c.sent(), - _b.entity = entity, - _b.entityId = ele.id, - _b), - _a)]; - } - }); - }); }))]; case 16: - _f = _q.sent(); - return [3 /*break*/, 19]; - case 17: + _k.operatorId = _u.sent(); + if (!(data instanceof Array)) return [3 /*break*/, 18]; _l = { id: 'dummy', action: 'create' }; - _m = {}; - return [4 /*yield*/, generateNewId()]; - case 18: - _f = [(_l.data = (_m.id = _q.sent(), - _m.entity = entity, - _m.entityId = data.id, - _m), + return [4 /*yield*/, Promise.all(data.map(function (ele) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + _a = {}; + return [4 /*yield*/, generateNewId()]; + case 1: return [2 /*return*/, (_a.id = _b.sent(), + _a.entity = entity, + _a.entityId = ele.id, + _a)]; + } + }); + }); }))]; + case 17: + _f = [(_l.data = _u.sent(), _l)]; - _q.label = 19; + return [3 /*break*/, 20]; + case 18: + _m = { + id: 'dummy', + action: 'create' + }; + _o = {}; + return [4 /*yield*/, generateNewId()]; case 19: + _f = [(_m.data = (_o.id = _u.sent(), + _o.entity = entity, + _o.entityId = data.id, + _o), + _m)]; + _u.label = 20; + case 20: createOper = (_j.data = (_k.operEntity$oper = _f, _k), _j); @@ -890,13 +884,13 @@ var CascadeStore = /** @class */ (function (_super) { dontCollect: true, dontCreateOper: true, })]; - case 20: - _q.sent(); - _q.label = 21; - case 21: return [2 /*return*/, result]; - case 22: + case 21: + _u.sent(); + _u.label = 22; + case 22: return [2 /*return*/, result]; + case 23: ids = (0, filter_1.getRelevantIds)(filter); - if (!(ids.length === 0)) return [3 /*break*/, 24]; + if (!(ids.length === 0)) return [3 /*break*/, 25]; selection = { data: { id: 1, @@ -908,16 +902,60 @@ var CascadeStore = /** @class */ (function (_super) { return [4 /*yield*/, this.selectAbjointRow(entity, selection, context, { dontCollect: true, })]; - case 23: - rows = _q.sent(); - ids.push.apply(ids, tslib_1.__spreadArray([], tslib_1.__read((rows.map(function (ele) { return ele.id; }))), false)); - _q.label = 24; case 24: - if (!laterAction) return [3 /*break*/, 25]; - // 延时更新,变成对modi的插入 - (0, assert_1.default)(false, '还未实现'); - return [3 /*break*/, 30]; + rows = _u.sent(); + ids.push.apply(ids, tslib_1.__spreadArray([], tslib_1.__read((rows.map(function (ele) { return ele.id; }))), false)); + _u.label = 25; case 25: + if (!(option.modiParentEntity && !['modi', 'modiEntity'].includes(entity))) return [3 /*break*/, 28]; + _p = { + id: 'dummy', + action: 'create' + }; + _q = { + id: operId, + targetEntity: entity, + entity: option.modiParentEntity, + entityId: option.modiParentId, + action: action, + data: data, + iState: 'active', + filter: { + id: { + $in: ids, + }, + } + }; + _r = { + id: 'dummy', + action: 'create' + }; + return [4 /*yield*/, Promise.all(ids.map(function (id) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var _a; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + _a = {}; + return [4 /*yield*/, generateNewId()]; + case 1: return [2 /*return*/, (_a.id = _b.sent(), + _a.entity = entity, + _a.entityId = id, + _a)]; + } + }); + }); }))]; + case 26: + modiCreate = (_p.data = (_q.modiEntity$modi = [ + (_r.data = _u.sent(), + _r) + ], + _q), + _p); + return [4 /*yield*/, this.cascadeUpdate('modi', modiCreate, context, option)]; + case 27: + _u.sent(); + return [2 /*return*/, 1]; + case 28: if (action === 'remove') { if (!option.dontCollect) { context.opRecords.push({ @@ -932,6 +970,10 @@ var CascadeStore = /** @class */ (function (_super) { } } else { + if (Object.keys(data).length === 0) { + // 优化一下,如果不更新任何属性,则不实际执行 + return [2 /*return*/, 0]; + } Object.assign(data, { $$updateAt$$: now, }); @@ -949,16 +991,16 @@ var CascadeStore = /** @class */ (function (_super) { } } return [4 /*yield*/, this.updateAbjointRow(entity, operation, context, option)]; - case 26: - result = _q.sent(); - if (!(!(option === null || option === void 0 ? void 0 : option.dontCreateOper) && !['oper', 'operEntity', 'modiEntity'].includes(entity) && ids.length > 0)) return [3 /*break*/, 29]; + case 29: + result = _u.sent(); + if (!(!(option === null || option === void 0 ? void 0 : option.dontCreateOper) && !['oper', 'operEntity', 'modiEntity'].includes(entity) && ids.length > 0)) return [3 /*break*/, 32]; // 按照框架要求生成Oper和OperEntity这两个内置的对象 (0, assert_1.default)(operId); - _o = { + _s = { id: 'dummy', action: 'create' }; - _p = { + _t = { id: operId, action: action, data: data @@ -982,19 +1024,18 @@ var CascadeStore = /** @class */ (function (_super) { } }); }); }))]; - case 27: - createOper = (_o.data = (_p.operEntity$oper = _q.sent(), - _p), - _o); + case 30: + createOper = (_s.data = (_t.operEntity$oper = _u.sent(), + _t), + _s); return [4 /*yield*/, this.cascadeUpdate('oper', createOper, context, { dontCollect: true, dontCreateOper: true, })]; - case 28: - _q.sent(); - _q.label = 29; - case 29: return [2 /*return*/, result]; - case 30: return [2 /*return*/]; + case 31: + _u.sent(); + _u.label = 32; + case 32: return [2 /*return*/, result]; } }); }); diff --git a/lib/store/filter.js b/lib/store/filter.js index a7af5e3..899a0d8 100644 --- a/lib/store/filter.js +++ b/lib/store/filter.js @@ -106,6 +106,14 @@ function getRelevantIds(filter) { var ids; var idsAnd; var idsOr; + if (!filter) { + return []; + } + // 因为要准确判定id,如果有其它的过滤条件,可能会使实际处理的行数少于id指向的行数,只能返回空数组 + var attrs = Object.keys(filter); + if ((0, lodash_1.union)(attrs, ['id', '$and', '$or']).length > 3) { + return []; + } if (filter === null || filter === void 0 ? void 0 : filter.$and) { var idss = filter.$and.map(function (ele) { return getRelevantIds(ele); }); idsAnd = lodash_1.intersection.apply(void 0, tslib_1.__spreadArray([], tslib_1.__read(idss), false)); diff --git a/lib/store/modi.d.ts b/lib/store/modi.d.ts new file mode 100644 index 0000000..3f44c55 --- /dev/null +++ b/lib/store/modi.d.ts @@ -0,0 +1,6 @@ +import { OpSchema as Modi } from '../base-app-domain/Modi/Schema'; +import { Operation } from '../types'; +export declare function createOperationsFromModies(modies: Modi[]): Array<{ + operation: Operation; + entity: string; +}>; diff --git a/lib/store/modi.js b/lib/store/modi.js new file mode 100644 index 0000000..130c043 --- /dev/null +++ b/lib/store/modi.js @@ -0,0 +1,17 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createOperationsFromModies = void 0; +function createOperationsFromModies(modies) { + return modies.map(function (modi) { + return { + entity: modi.targetEntity, + operation: { + id: modi.id, + action: modi.action, + data: modi.data, + filter: modi.filter, + } + }; + }); +} +exports.createOperationsFromModies = createOperationsFromModies; diff --git a/lib/triggers/index.d.ts b/lib/triggers/index.d.ts new file mode 100644 index 0000000..7a942c4 --- /dev/null +++ b/lib/triggers/index.d.ts @@ -0,0 +1,2 @@ +declare const _default: import("../types").Trigger>[]; +export default _default; diff --git a/lib/triggers/index.js b/lib/triggers/index.js new file mode 100644 index 0000000..7b9e89c --- /dev/null +++ b/lib/triggers/index.js @@ -0,0 +1,5 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var tslib_1 = require("tslib"); +var modi_1 = tslib_1.__importDefault(require("./modi")); +exports.default = tslib_1.__spreadArray([], tslib_1.__read(modi_1.default), false); diff --git a/lib/triggers/modi.d.ts b/lib/triggers/modi.d.ts new file mode 100644 index 0000000..e9952d3 --- /dev/null +++ b/lib/triggers/modi.d.ts @@ -0,0 +1,5 @@ +import { EntityDict } from "../base-app-domain"; +import { Trigger } from "../types"; +import { UniversalContext } from "../store/UniversalContext"; +declare const triggers: Trigger>[]; +export default triggers; diff --git a/lib/triggers/modi.js b/lib/triggers/modi.js new file mode 100644 index 0000000..f2b9c6a --- /dev/null +++ b/lib/triggers/modi.js @@ -0,0 +1,70 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +var tslib_1 = require("tslib"); +var triggers = [ + { + name: '当modi被应用时,将相应的operate完成', + entity: 'modi', + action: 'apply', + when: 'after', + fn: function (_a, context, option) { + var operation = _a.operation; + return tslib_1.__awaiter(void 0, void 0, void 0, function () { + var filter, modies, modies_1, modies_1_1, modi, targetEntity, id, action, data, filter_1, e_1_1; + var e_1, _b; + return tslib_1.__generator(this, function (_c) { + switch (_c.label) { + case 0: + filter = operation.filter; + return [4 /*yield*/, context.rowStore.select('modi', { + data: { + id: 1, + action: 1, + data: 1, + filter: 1, + targetEntity: 1, + }, + filter: filter, + }, context, option)]; + case 1: + modies = (_c.sent()).result; + _c.label = 2; + case 2: + _c.trys.push([2, 7, 8, 9]); + modies_1 = tslib_1.__values(modies), modies_1_1 = modies_1.next(); + _c.label = 3; + case 3: + if (!!modies_1_1.done) return [3 /*break*/, 6]; + modi = modies_1_1.value; + targetEntity = modi.targetEntity, id = modi.id, action = modi.action, data = modi.data, filter_1 = modi.filter; + return [4 /*yield*/, context.rowStore.operate(targetEntity, { + id: id, + action: action, + data: data, + filter: filter_1, + }, context, option)]; + case 4: + _c.sent(); + _c.label = 5; + case 5: + modies_1_1 = modies_1.next(); + return [3 /*break*/, 3]; + case 6: return [3 /*break*/, 9]; + case 7: + e_1_1 = _c.sent(); + e_1 = { error: e_1_1 }; + return [3 /*break*/, 9]; + case 8: + try { + if (modies_1_1 && !modies_1_1.done && (_b = modies_1.return)) _b.call(modies_1); + } + finally { if (e_1) throw e_1.error; } + return [7 /*endfinally*/]; + case 9: return [2 /*return*/, modies.length]; + } + }); + }); + } + } +]; +exports.default = triggers; diff --git a/lib/types/Entity.d.ts b/lib/types/Entity.d.ts index c4be09c..7d85b31 100644 --- a/lib/types/Entity.d.ts +++ b/lib/types/Entity.d.ts @@ -23,7 +23,8 @@ export declare type OperateOption = { dontCollect?: boolean; dontCreateOper?: boolean; allowExists?: boolean; - parentModiId?: string; + modiParentId?: string; + modiParentEntity?: string; dummy?: 1; }; export declare type FormUpdateData = Partial<{ @@ -51,7 +52,7 @@ export interface FileCarrierEntityShape extends EntityShape { interface GeneralEntityShape extends EntityShape { [K: string]: any; } -export declare type MakeAction = A | `${A}-l`; +export declare type MakeAction = A; export interface EntityDef { Schema: GeneralEntityShape; OpSchema: GeneralEntityShape; diff --git a/lib/types/Storage.d.ts b/lib/types/Storage.d.ts index e2ae894..d888764 100644 --- a/lib/types/Storage.d.ts +++ b/lib/types/Storage.d.ts @@ -41,6 +41,7 @@ export interface StorageDesc { uniqueConstraints?: UniqConstraint[]; indexes?: Index[]; config?: EntityConfig; + toModi?: true; view?: true; } export declare type StorageSchema = { diff --git a/src/compiler/env.ts b/src/compiler/env.ts index f9b445c..430a085 100644 --- a/src/compiler/env.ts +++ b/src/compiler/env.ts @@ -8,6 +8,10 @@ export const ENTITY_PATH_IN_OAK_GENERAL_BUSINESS = () => { return `${LIB_OAK_GENERAL_BUSINESS}/${LIB_PATH()}/entities/`; } +export const ENTITY_PATH_IN_OAK_DOMAIN = () => { + return `${LIB_OAK_DOMAIN}/${LIB_PATH()}/entities/`; +} + export const TYPE_PATH_IN_OAK_DOMAIN = (level = 2) => { if (process.env.COMPLING_IN_DOMAIN) { return `${LEVEL_PREFIX[level]}/types/`; diff --git a/src/compiler/schemalBuilder.ts b/src/compiler/schemalBuilder.ts index 40822ef..3de14ff 100644 --- a/src/compiler/schemalBuilder.ts +++ b/src/compiler/schemalBuilder.ts @@ -12,6 +12,7 @@ import { TYPE_PATH_IN_OAK_DOMAIN, RESERVED_ENTITIES, STRING_LITERAL_MAX_LENGTH, + ENTITY_PATH_IN_OAK_DOMAIN, NUMERICAL_LITERL_DEFAULT_PRECISION, NUMERICAL_LITERL_DEFAULT_SCALE, INT_LITERL_DEFAULT_WIDTH, @@ -25,6 +26,7 @@ const Schema: Record = {}; const OneToMany: Record> = {}; const ManyToOne: Record> = {}; @@ -355,6 +357,9 @@ function getEntityImported(declaration: ts.ImportDeclaration, filename: string) else if (moduleSpecifier.text.startsWith(ENTITY_PATH_IN_OAK_GENERAL_BUSINESS())) { entityImported = moduleSpecifier.text.slice(ENTITY_PATH_IN_OAK_GENERAL_BUSINESS().length); } + else if (moduleSpecifier.text.startsWith(ENTITY_PATH_IN_OAK_DOMAIN())) { + entityImported = moduleSpecifier.text.slice(ENTITY_PATH_IN_OAK_DOMAIN().length) + } } if (entityImported) { @@ -423,6 +428,7 @@ function analyzeEntity(filename: string, path: string, program: ts.Program) { let hasActionDef = false; let hasRelationDef = false; let hasActionOrStateDef = false; + let toModi = false; const enumStringAttrs: string[] = []; const states: string[] = []; const localEnumStringTypes: string[] = []; @@ -470,6 +476,10 @@ function analyzeEntity(filename: string, path: string, program: ts.Program) { [reverseEntity]: [moduleName], }); } + + if (reverseEntity === 'Modi') { + toModi = true; + } } else { schemaAttrs.push(attrNode); @@ -478,6 +488,29 @@ function analyzeEntity(filename: string, path: string, program: ts.Program) { } } } + 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]) { + ReversePointerRelations[reverseEntity].push(moduleName); + } + else { + assign(ReversePointerRelations, { + [reverseEntity]: [moduleName], + }); + } + + if (reverseEntity === 'Modi') { + toModi = true; + } + } + else { + throw new Error(`对象${moduleName}中定义的属性${attrName}是不可识别的数组类别`); + } + } else { schemaAttrs.push(attrNode); if (ts.isUnionTypeNode(type!)) { @@ -534,7 +567,7 @@ function analyzeEntity(filename: string, path: string, program: ts.Program) { } beforeSchema = false; - // 对于不是Oper的对象,全部建立和Oper的反指关系 + // 对于不是Oper的对象,全部建立和OperEntity的反指关系 if (!['Oper', 'OperEntity', 'ModiEntity'].includes(moduleName)) { if (ReversePointerRelations['OperEntity'] && !ReversePointerRelations['OperEntity'].includes(moduleName)) { ReversePointerRelations['OperEntity'].push(moduleName); @@ -545,8 +578,8 @@ function analyzeEntity(filename: string, path: string, program: ts.Program) { }); } - // 对于不是Modi的对象,全部建立和Modi的反指关系 - if (!['Modi'].includes(moduleName)) { + // 对于不是Modi的对象,全部建立和ModiEntity的反指关系 + if (!['Modi'].includes(moduleName) && !toModi) { if (ReversePointerRelations['ModiEntity'] && !ReversePointerRelations['ModiEntity'].includes(moduleName)) { ReversePointerRelations['ModiEntity'].push(moduleName); } @@ -954,6 +987,7 @@ function analyzeEntity(filename: string, path: string, program: ts.Program) { const schema = { schemaAttrs, sourceFile, + toModi, }; if (hasFulltextIndex) { assign(schema, { @@ -1473,6 +1507,22 @@ function constructFilter(statements: Array, entity: string) { } // type AttrFilter = {}; + if (ReversePointerRelations[entity]) { + // 有反向指针,将反向指针关联的对象的Filter也注入 + ReversePointerRelations[entity].forEach( + ele => + members.push( + factory.createPropertySignature( + undefined, + firstLetterLowerCase(ele), + undefined, + factory.createTypeReferenceNode( + createForeignRef(entity, ele, 'Filter') + ) + ) + ) + ); + } const eumUnionTypeNode: ts.TypeNode[] = ReversePointerRelations[entity] && ReversePointerRelations[entity].map( ele => factory.createLiteralTypeNode( factory.createStringLiteral(firstLetterLowerCase(ele)) @@ -2647,18 +2697,18 @@ function constructActions(statements: Array, entity: string) { } // CreateOperationData let foreignKeyAttr: string[] = []; + + if (ReversePointerEntities[entity]) { + foreignKeyAttr.push( + 'entity', 'entityId' + ); + } if (manyToOneSet) { for (const one of manyToOneSet) { if (!ReversePointerRelations[entity] || !ReversePointerRelations[entity].includes(one[1])) { foreignKeyAttr.push(`${one[1]}Id`); } } - - if (ReversePointerEntities[entity]) { - foreignKeyAttr.push( - 'entity', 'entityId' - ); - } } let adNodes: ts.TypeNode[] = [ factory.createTypeReferenceNode( @@ -2747,7 +2797,16 @@ function constructActions(statements: Array, entity: string) { } } - const reverseOneNodes: ts.TypeNode[] = []; + if (upsertOneNodes.length > 0) { + adNodes.push( + factory.createIntersectionTypeNode( + upsertOneNodes + ) + ); + } + } + const reverseOneNodes: ts.TypeNode[] = []; + if (ReversePointerEntities[entity]) { if (ReversePointerRelations[entity]) { for (const one of ReversePointerRelations[entity]) { reverseOneNodes.push( @@ -2805,39 +2864,44 @@ function constructActions(statements: Array, entity: string) { ) ); } - - if (process.env.COMPLING_AS_LIB) { - // 如果是base,要包容更多可能的反指 - reverseOneNodes.push( - factory.createTypeLiteralNode( - [ - 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 (upsertOneNodes.length > 0) { - adNodes.push( - factory.createIntersectionTypeNode( - upsertOneNodes + 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, + undefined, + [factory.createParameterDeclaration( + undefined, + 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( @@ -2849,7 +2913,7 @@ function constructActions(statements: Array, entity: string) { // 一对多 const propertySignatures: ts.TypeElement[] = []; - if (process.env.COMPLING_AS_LIB) { + /* if (process.env.COMPLING_AS_LIB) { propertySignatures.push( factory.createIndexSignature( undefined, @@ -2866,7 +2930,7 @@ function constructActions(statements: Array, entity: string) { factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword) ) ); - } + } */ if (oneToManySet) { for (const entityName in foreignKeySet) { const entityNameLc = firstLetterLowerCase(entityName); @@ -3025,15 +3089,15 @@ function constructActions(statements: Array, entity: string) { // UpdateOperationData foreignKeyAttr = []; + if (ReversePointerRelations[entity]) { + foreignKeyAttr.push('entity', 'entityId'); + } if (manyToOneSet) { for (const one of manyToOneSet) { if (!ReversePointerRelations[entity] || !ReversePointerRelations[entity].includes(one[1])) { foreignKeyAttr.push(`${one[1]}Id`); } } - if (ReversePointerRelations[entity]) { - foreignKeyAttr.push('entity', 'entityId'); - } } adNodes = [ factory.createTypeReferenceNode( @@ -4858,7 +4922,7 @@ function outputStorage(outputDir: string, printer: ts.Printer) { for (const entity in Schema) { const indexExpressions: ts.Expression[] = []; - const { sourceFile, fulltextIndex, indexes } = Schema[entity]; + const { sourceFile, fulltextIndex, indexes, toModi } = Schema[entity]; const statements: ts.Statement[] = [ factory.createImportDeclaration( undefined, @@ -4909,6 +4973,14 @@ function outputStorage(outputDir: string, printer: ts.Printer) { ...indexes.elements ) } + if (toModi) { + propertyAssignments.push( + factory.createPropertyAssignment( + factory.createIdentifier("toModi"), + factory.createTrue() + ) + ); + } if (indexExpressions.length > 0) { propertyAssignments.push( diff --git a/src/entities/Modi.ts b/src/entities/Modi.ts index 44bf635..c7e1c23 100644 --- a/src/entities/Modi.ts +++ b/src/entities/Modi.ts @@ -5,11 +5,13 @@ import { LocaleDef } from '../types/Locale'; import { Index } from '../types/Storage'; export interface Schema extends EntityShape { + targetEntity: String<32>; // 要操作的目标对象 + entity: String<32>; // 关联的目标对象 + entityId: String<64>; // 关联的目标对象id action: String<16>; data: Object; filter?: Object; extra?: Object; - parent?: Schema; }; type IState = 'active' | 'applied' | 'abandoned'; @@ -42,12 +44,14 @@ const locale: LocaleDef = { zh_CN: { attr: { + targetEntity: '目标对象', + entity: '关联对象', + entityId: '关联对象Id', action: '动作', data: '数据', filter: '条件', extra: '其它', iState: '状态', - parent: '关联父更新' }, action: { abandon: '放弃', diff --git a/src/store/CascadeStore.ts b/src/store/CascadeStore.ts index b8304a1..38e1f2b 100644 --- a/src/store/CascadeStore.ts +++ b/src/store/CascadeStore.ts @@ -9,8 +9,8 @@ import { RowStore } from '../types/RowStore'; import { StorageSchema } from '../types/Storage'; import { addFilterSegment, getRelevantIds } from "./filter"; import { judgeRelation } from "./relation"; -import { isLaterAction } from "./action"; import { CreateOperation as CreateOperOperation } from '../base-app-domain/Oper/Schema'; +import { CreateOperation as CreateModiOperation } from '../base-app-domain/Modi/Schema'; import { OakCongruentRowExists } from "../types"; import { omit, cloneDeep } from '../utils/lodash'; @@ -296,8 +296,17 @@ export abstract class CascadeStore, filter?: DeduceFilter ) { - const opData = {}; - const laterAction = isLaterAction(action); + const modiAttr = this.getSchema()[entity].toModi; + const option2 = Object.assign({}, option); + + const opData: Record = {}; + if (modiAttr && action !== 'remove') { + // create/update具有modi对象的对象,对其子对象的update行为全部是create modi对象(缓存动作) + // delete是什么情况?似乎应该先把所有的modi给abandon掉 by Xc + assert(!option2.modiParentId && !option2.modiParentEntity); + option2.modiParentId = data.id; + option2.modiParentEntity = entity as string; + } for (const attr in data) { const relation = judgeRelation(this.storageSchema, entity, attr); if (relation === 1) { @@ -309,28 +318,8 @@ export abstract class CascadeStore) => { const { action: actionOtm, data: dataOtm, filter: filterOtm } = otm; - const subLaterAction = isLaterAction(actionOtm); - assert(laterAction && subLaterAction || !laterAction && !subLaterAction, '延时动作的子对象的动作也必须是延时动作'); if (!foreignKey) { // 基于entity/entityId的one-to-many if (action === 'create') { @@ -521,7 +507,7 @@ export abstract class CascadeStore 0) { - opData.push(od); - } + opData.push(od); } } else { @@ -603,8 +587,8 @@ export abstract class CascadeStore { @@ -704,7 +701,7 @@ export abstract class CascadeStore ({ - id: 'dummy', - action: 'create', - data: { + operEntity$oper: data instanceof Array ? [{ + id: 'dummy', + action: 'create', + data: await Promise.all( + data.map( + async (ele) => ({ id: await generateNewId(), entity, - entityId: (ele as ED[T]['CreateSingle']['data']).id, - }, - }) - ) - ) : [{ + entityId: ele.id, + }) + ) + ), + }] : [{ id: 'dummy', action: 'create', data: { @@ -810,9 +807,44 @@ export abstract class CascadeStore ele.id! as string))); } - if (laterAction) { + if (option.modiParentEntity && !['modi', 'modiEntity'].includes(entity as string)) { // 延时更新,变成对modi的插入 - assert(false, '还未实现'); + // 变成对modi的插入 + const modiCreate: CreateModiOperation = { + id: 'dummy', + action: 'create', + data: { + id: operId, + targetEntity: entity as string, + entity: option.modiParentEntity!, + entityId: option.modiParentId!, + action, + data, + iState: 'active', + filter: { + id: { + $in: ids, + }, + }, + modiEntity$modi: [ + { + id: 'dummy', + action: 'create', + data: await Promise.all( + ids.map( + async (id) => ({ + id: await generateNewId(), + entity, + entityId: id, + }) + ) + ), + } + ], + }, + }; + await this.cascadeUpdate('modi', modiCreate, context, option); + return 1; } else { if (action === 'remove') { @@ -829,6 +861,10 @@ export abstract class CascadeStore(filter let idsAnd: string[] | undefined; let idsOr: string[] | undefined; + if (!filter) { + return []; + } + + // 因为要准确判定id,如果有其它的过滤条件,可能会使实际处理的行数少于id指向的行数,只能返回空数组 + const attrs = Object.keys(filter); + if (union(attrs, ['id', '$and', '$or']).length > 3) { + return []; + } + if (filter?.$and) { const idss = filter.$and.map( ele => getRelevantIds(ele) diff --git a/src/store/modi.ts b/src/store/modi.ts new file mode 100644 index 0000000..126b4a7 --- /dev/null +++ b/src/store/modi.ts @@ -0,0 +1,20 @@ +import { OpSchema as Modi } from '../base-app-domain/Modi/Schema'; +import { Operation } from '../types'; +export function createOperationsFromModies(modies: Modi[]): Array<{ + operation: Operation , + entity: string, +}>{ + return modies.map( + (modi) => { + return { + entity: modi.targetEntity, + operation: { + id: modi.id, + action: modi.action, + data: modi.data, + filter: modi.filter as any, + } + } + } + ); +} \ No newline at end of file diff --git a/src/triggers/index.ts b/src/triggers/index.ts new file mode 100644 index 0000000..705beca --- /dev/null +++ b/src/triggers/index.ts @@ -0,0 +1,3 @@ +import modiTriggers from './modi'; + +export default [...modiTriggers]; diff --git a/src/triggers/modi.ts b/src/triggers/modi.ts new file mode 100644 index 0000000..b79dcaa --- /dev/null +++ b/src/triggers/modi.ts @@ -0,0 +1,39 @@ +import { EntityDict } from "../base-app-domain"; +import { Trigger } from "../types"; +import { UniversalContext } from "../store/UniversalContext"; + +const triggers: Trigger>[] = [ + { + name: '当modi被应用时,将相应的operate完成', + entity: 'modi', + action: 'apply', + when: 'after', + fn: async ({ operation }, context, option) => { + const { filter } = operation; + const { result: modies } = await context.rowStore.select('modi', { + data: { + id: 1, + action: 1, + data: 1, + filter: 1, + targetEntity: 1, + }, + filter, + }, context, option); + + for (const modi of modies) { + const { targetEntity, id, action, data, filter} = modi; + await context.rowStore.operate(targetEntity as keyof EntityDict, { + id, + action, + data, + filter: filter as any, + }, context, option); + } + + return modies.length; + } + } +]; + +export default triggers; \ No newline at end of file diff --git a/src/types/Entity.ts b/src/types/Entity.ts index dd7c721..8f4af5d 100644 --- a/src/types/Entity.ts +++ b/src/types/Entity.ts @@ -28,7 +28,8 @@ export type OperateOption = { dontCollect?: boolean; dontCreateOper?: boolean; allowExists?: boolean; // 插入时允许已经存在唯一键值的行了,即insert / update逻辑 - parentModiId?: string; // 如果是延时更新,所有的相关modi要关联到一个父亲上统一应用 + modiParentId?: string; // 如果是延时更新,相关modi要关联到一个父亲上统一应用 + modiParentEntity?: string; // 如果是延时更新,相关modi要关联到一个父亲上统一应用 dummy?: 1; // 无用,为了继承Option通过编译 }; @@ -67,7 +68,7 @@ interface GeneralEntityShape extends EntityShape { [K: string]: any; } -export type MakeAction = A | `${A}-l`; +export type MakeAction = A; export interface EntityDef { // Name: E; diff --git a/src/types/Storage.ts b/src/types/Storage.ts index 97f30cc..e2c2ea1 100644 --- a/src/types/Storage.ts +++ b/src/types/Storage.ts @@ -52,6 +52,7 @@ export interface StorageDesc { uniqueConstraints?: UniqConstraint[]; indexes?: Index[]; config?: EntityConfig; + toModi?: true, // 标识一下是否关联在modi上 // view 相关 view?: true; }