modi的相关逻辑的实现

This commit is contained in:
Xu Chang 2022-08-27 17:11:40 +08:00
parent 730f0beed4
commit 87b30fb8fa
33 changed files with 758 additions and 358 deletions

View File

@ -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<Schema>;
modiEntity$modi?: Array<ModiEntity.Schema>;
operEntity$entity?: Array<OperEntity.Schema>;
} & {
@ -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<IState>;
};
export declare type Filter = MakeFilter<AttrFilter & ExprOp<OpAttr | string>>;
@ -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<ExprOp<OpAttr | string>>;
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<P = Projection> = Omit<OakOperation<"select", P, Filter, Sorter>, "id">;
export declare type Selection<P = Projection> = Omit<SelectOperation<P>, "action">;
export declare type Exportation = OakOperation<"export", ExportProjection, Filter, Sorter>;
export declare type CreateOperationData = FormCreateData<Omit<OpSchema, "parentId">> & (({
parentId?: never | null;
parent?: CreateSingleOperation;
} | {
parentId?: String<64>;
parent?: UpdateOperation;
})) & {
[k: string]: any;
modi$parent?: OakOperation<UpdateOperation["action"], Omit<UpdateOperationData, "parent" | "parentId">, Filter> | Array<OakOperation<"create", Omit<CreateOperationData, "parent" | "parentId"> | Omit<CreateOperationData, "parent" | "parentId">[]> | OakOperation<UpdateOperation["action"], Omit<UpdateOperationData, "parent" | "parentId">, Filter>>;
export declare type CreateOperationData = FormCreateData<Omit<OpSchema, "entity" | "entityId">> & ({
entity?: string;
entityId?: string;
[K: string]: any;
}) & {
modiEntity$modi?: OakOperation<ModiEntity.UpdateOperation["action"], Omit<ModiEntity.UpdateOperationData, "modi" | "modiId">, ModiEntity.Filter> | Array<OakOperation<"create", Omit<ModiEntity.CreateOperationData, "modi" | "modiId"> | Omit<ModiEntity.CreateOperationData, "modi" | "modiId">[]> | OakOperation<ModiEntity.UpdateOperation["action"], Omit<ModiEntity.UpdateOperationData, "modi" | "modiId">, ModiEntity.Filter>>;
operEntity$entity?: OakOperation<OperEntity.UpdateOperation["action"], Omit<OperEntity.UpdateOperationData, "entity" | "entityId">, OperEntity.Filter> | Array<OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId"> | Omit<OperEntity.CreateOperationData, "entity" | "entityId">[]> | OakOperation<OperEntity.UpdateOperation["action"], Omit<OperEntity.UpdateOperationData, "entity" | "entityId">, OperEntity.Filter>>;
};
export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>;
export declare type CreateMultipleOperation = OakOperation<"create", Array<CreateOperationData>>;
export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
export declare type UpdateOperationData = FormUpdateData<Omit<OpSchema, "parentId">> & (({
parent?: CreateSingleOperation | UpdateOperation | RemoveOperation;
parentId?: undefined;
} | {
parent?: undefined;
parentId?: String<64> | null;
})) & {
export declare type UpdateOperationData = FormUpdateData<OpSchema> & {
[k: string]: any;
modis$parent?: UpdateOperation | RemoveOperation | Array<OakOperation<"create", Omit<CreateOperationData, "parent" | "parentId"> | Omit<CreateOperationData, "parent" | "parentId">[]> | UpdateOperation | RemoveOperation>;
modiEntitys$modi?: ModiEntity.UpdateOperation | ModiEntity.RemoveOperation | Array<OakOperation<"create", Omit<ModiEntity.CreateOperationData, "modi" | "modiId"> | Omit<ModiEntity.CreateOperationData, "modi" | "modiId">[]> | ModiEntity.UpdateOperation | ModiEntity.RemoveOperation>;
operEntitys$entity?: OperEntity.UpdateOperation | OperEntity.RemoveOperation | Array<OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId"> | Omit<OperEntity.CreateOperationData, "entity" | "entityId">[]> | OperEntity.UpdateOperation | OperEntity.RemoveOperation>;
};
export declare type UpdateOperation = OakOperation<ParticularAction | "update" | string, UpdateOperationData, Filter, Sorter>;
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<ModiIdProjection>;
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;

View File

@ -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: {

View File

@ -37,6 +37,7 @@ declare type AttrFilter<E> = {
modi: Modi.Filter;
entity: E;
entityId: Q_StringValue;
user: User.Filter;
};
export declare type Filter<E = Q_EnumValue<"user" | string>> = MakeFilter<AttrFilter<E> & ExprOp<OpAttr | string>>;
export declare type Projection = {
@ -99,7 +100,7 @@ export declare type Sorter = SortNode[];
export declare type SelectOperation<P = Projection> = Omit<OakOperation<"select", P, Filter, Sorter>, "id">;
export declare type Selection<P = Projection> = Omit<SelectOperation<P>, "action">;
export declare type Exportation = OakOperation<"export", ExportProjection, Filter, Sorter>;
export declare type CreateOperationData = FormCreateData<Omit<OpSchema, "modiId" | "entityId" | "entity">> & (({
export declare type CreateOperationData = FormCreateData<Omit<OpSchema, "entity" | "entityId" | "modiId">> & (({
modiId?: never | null;
modi: Modi.CreateSingleOperation;
} | {
@ -114,14 +115,14 @@ export declare type CreateOperationData = FormCreateData<Omit<OpSchema, "modiId"
entityId: String<64>;
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<CreateOperationData>>;
export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
export declare type UpdateOperationData = FormUpdateData<Omit<OpSchema, "modiId" | "entityId" | "entity">> & (({
export declare type UpdateOperationData = FormUpdateData<Omit<OpSchema, "entity" | "entityId" | "modiId">> & (({
modi?: Modi.CreateSingleOperation | Modi.UpdateOperation | Modi.RemoveOperation;
modiId?: undefined;
} | {

View File

@ -110,7 +110,6 @@ export declare type CreateOperationData = FormCreateData<Omit<OpSchema, "operato
operatorId?: String<64>;
operator?: User.UpdateOperation;
})) & {
[k: string]: any;
operEntity$oper?: OakOperation<OperEntity.UpdateOperation["action"], Omit<OperEntity.UpdateOperationData, "oper" | "operId">, OperEntity.Filter> | Array<OakOperation<"create", Omit<OperEntity.CreateOperationData, "oper" | "operId"> | Omit<OperEntity.CreateOperationData, "oper" | "operId">[]> | OakOperation<OperEntity.UpdateOperation["action"], Omit<OperEntity.UpdateOperationData, "oper" | "operId">, OperEntity.Filter>>;
};
export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>;

View File

@ -39,6 +39,8 @@ declare type AttrFilter<E> = {
oper: Oper.Filter;
entity: E;
entityId: Q_StringValue;
modi: Modi.Filter;
user: User.Filter;
};
export declare type Filter<E = Q_EnumValue<"modi" | "user" | string>> = MakeFilter<AttrFilter<E> & ExprOp<OpAttr | string>>;
export declare type Projection = {
@ -108,7 +110,7 @@ export declare type Sorter = SortNode[];
export declare type SelectOperation<P = Projection> = Omit<OakOperation<"select", P, Filter, Sorter>, "id">;
export declare type Selection<P = Projection> = Omit<SelectOperation<P>, "action">;
export declare type Exportation = OakOperation<"export", ExportProjection, Filter, Sorter>;
export declare type CreateOperationData = FormCreateData<Omit<OpSchema, "operId" | "entityId" | "entity">> & (({
export declare type CreateOperationData = FormCreateData<Omit<OpSchema, "entity" | "entityId" | "operId">> & (({
operId?: never | null;
oper: Oper.CreateSingleOperation;
} | {
@ -131,14 +133,14 @@ export declare type CreateOperationData = FormCreateData<Omit<OpSchema, "operId"
entityId: String<64>;
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<CreateOperationData>>;
export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation;
export declare type UpdateOperationData = FormUpdateData<Omit<OpSchema, "operId" | "entityId" | "entity">> & (({
export declare type UpdateOperationData = FormUpdateData<Omit<OpSchema, "entity" | "entityId" | "operId">> & (({
oper?: Oper.CreateSingleOperation | Oper.UpdateOperation | Oper.RemoveOperation;
operId?: undefined;
} | {

View File

@ -105,7 +105,6 @@ export declare type SelectOperation<P = Projection> = Omit<OakOperation<"select"
export declare type Selection<P = Projection> = Omit<SelectOperation<P>, "action">;
export declare type Exportation = OakOperation<"export", ExportProjection, Filter, Sorter>;
export declare type CreateOperationData = FormCreateData<OpSchema> & {
[k: string]: any;
oper$operator?: OakOperation<Oper.UpdateOperation["action"], Omit<Oper.UpdateOperationData, "operator" | "operatorId">, Oper.Filter> | Array<OakOperation<"create", Omit<Oper.CreateOperationData, "operator" | "operatorId"> | Omit<Oper.CreateOperationData, "operator" | "operatorId">[]> | OakOperation<Oper.UpdateOperation["action"], Omit<Oper.UpdateOperationData, "operator" | "operatorId">, Oper.Filter>>;
operEntity$entity?: OakOperation<OperEntity.UpdateOperation["action"], Omit<OperEntity.UpdateOperationData, "entity" | "entityId">, OperEntity.Filter> | Array<OakOperation<"create", Omit<OperEntity.CreateOperationData, "entity" | "entityId"> | Omit<OperEntity.CreateOperationData, "entity" | "entityId">[]> | OakOperation<OperEntity.UpdateOperation["action"], Omit<OperEntity.UpdateOperationData, "entity" | "entityId">, OperEntity.Filter>>;
modiEntity$entity?: OakOperation<ModiEntity.UpdateOperation["action"], Omit<ModiEntity.UpdateOperationData, "entity" | "entityId">, ModiEntity.Filter> | Array<OakOperation<"create", Omit<ModiEntity.CreateOperationData, "entity" | "entityId"> | Omit<ModiEntity.CreateOperationData, "entity" | "entityId">[]> | OakOperation<ModiEntity.UpdateOperation["action"], Omit<ModiEntity.UpdateOperationData, "entity" | "entityId">, ModiEntity.Filter>>;

View File

@ -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";

View File

@ -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[];

View File

@ -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) {

View File

@ -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)));
}

View File

@ -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;
}

View File

@ -22,12 +22,14 @@ var indexes = [
var locale = {
zh_CN: {
attr: {
targetEntity: '目标对象',
entity: '关联对象',
entityId: '关联对象Id',
action: '动作',
data: '数据',
filter: '条件',
extra: '其它',
iState: '状态',
parent: '关联父更新'
},
action: {
abandon: '放弃',

View File

@ -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];
}
});
});

View File

@ -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));

6
lib/store/modi.d.ts vendored Normal file
View File

@ -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<string, Object, Object>;
entity: string;
}>;

17
lib/store/modi.js Normal file
View File

@ -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;

2
lib/triggers/index.d.ts vendored Normal file
View File

@ -0,0 +1,2 @@
declare const _default: import("../types").Trigger<import("../base-app-domain").EntityDict, "modi", import("../store/UniversalContext").UniversalContext<import("../base-app-domain").EntityDict>>[];
export default _default;

5
lib/triggers/index.js Normal file
View File

@ -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);

5
lib/triggers/modi.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
import { EntityDict } from "../base-app-domain";
import { Trigger } from "../types";
import { UniversalContext } from "../store/UniversalContext";
declare const triggers: Trigger<EntityDict, 'modi', UniversalContext<EntityDict>>[];
export default triggers;

70
lib/triggers/modi.js Normal file
View File

@ -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;

View File

@ -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<SH extends GeneralEntityShape> = Partial<{
@ -51,7 +52,7 @@ export interface FileCarrierEntityShape extends EntityShape {
interface GeneralEntityShape extends EntityShape {
[K: string]: any;
}
export declare type MakeAction<A extends string> = A | `${A}-l`;
export declare type MakeAction<A extends string> = A;
export interface EntityDef {
Schema: GeneralEntityShape;
OpSchema: GeneralEntityShape;

View File

@ -41,6 +41,7 @@ export interface StorageDesc<SH extends EntityShape> {
uniqueConstraints?: UniqConstraint<SH>[];
indexes?: Index<SH>[];
config?: EntityConfig;
toModi?: true;
view?: true;
}
export declare type StorageSchema<ED extends EntityDict> = {

View File

@ -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/`;

View File

@ -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<string, {
states: string[];
sourceFile: ts.SourceFile;
locale: ts.ObjectLiteralExpression;
toModi: boolean;
}> = {};
const OneToMany: Record<string, Array<[string, string, boolean]>> = {};
const ManyToOne: Record<string, Array<[string, string, boolean]>> = {};
@ -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<ts.Statement>, 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<ts.Statement>, 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<ts.Statement>, 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<ts.Statement>, 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<ts.Statement>, 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<ts.Statement>, 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<ts.Statement>, 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(

View File

@ -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<Schema, Action, '', {
}> = {
zh_CN: {
attr: {
targetEntity: '目标对象',
entity: '关联对象',
entityId: '关联对象Id',
action: '动作',
data: '数据',
filter: '条件',
extra: '其它',
iState: '状态',
parent: '关联父更新'
},
action: {
abandon: '放弃',

View File

@ -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<ED extends EntityDict & BaseEntityDict, Cxt e
result: OperationResult<ED>,
filter?: DeduceFilter<ED[T]['Schema']>
) {
const opData = {};
const laterAction = isLaterAction(action);
const modiAttr = this.getSchema()[entity].toModi;
const option2 = Object.assign({}, option);
const opData: Record<string, any> = {};
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<ED extends EntityDict & BaseEntityDict, Cxt e
// 基于entity/entityId的many-to-one
const operationMto = data[attr];
const { action: actionMto, data: dataMto, filter: filterMto } = operationMto;
const subLaterAction = isLaterAction(actionMto);
let laterLine = false; // laterLine代表当前对象是正常动作而子对象是延时动作
if (laterAction) {
assert(subLaterAction, '所有延时动作的子对象的动作也必须是延时的');
}
else if (subLaterAction) {
if (!laterAction) {
laterLine = true;
}
}
if (laterLine) {
// 如果是对子对象的延时更新此时对子对象的更新被转换成对Modi对象的插入
assert(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,
@ -365,15 +354,14 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict, Cxt e
});
}
const result2 = await this.cascadeUpdate(attr, operationMto, context, option);
const result2 = await this.cascadeUpdate(attr, operationMto, context, option2);
this.mergeOperationResult(result, result2);
}
else if (typeof relation === 'string') {
// 基于attr的外键的many-to-one
const operationMto = data[attr];
const { action: actionMto, data: dataMto, filter: filterMto } = operationMto;
const subLaterAction = isLaterAction(actionMto);
assert(laterAction && subLaterAction || !laterAction && !subLaterAction, '延时动作的子对象的动作也必须是延时动作');
if (actionMto === 'create') {
Object.assign(opData, {
[`${attr}Id`]: dataMto.id,
@ -405,7 +393,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict, Cxt e
});
}
const result2 = await this.cascadeUpdate(relation, operationMto, context, option);
const result2 = await this.cascadeUpdate(relation, operationMto, context, option2);
this.mergeOperationResult(result, result2);
}
else {
@ -414,8 +402,6 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict, Cxt e
const otmOperations = data[attr];
const dealWithOneToMany = async (otm: DeduceUpdateOperation<ED[keyof ED]['Schema']>) => {
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<ED extends EntityDict & BaseEntityDict, Cxt e
}
}
const result2 = await this.cascadeUpdate(entityOtm!, otm, context, option);
const result2 = await this.cascadeUpdate(entityOtm!, otm, context, option2);
this.mergeOperationResult(result, result2);
};
@ -589,9 +575,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict, Cxt e
option,
result,
);
if (Object.keys(od).length > 0) {
opData.push(od);
}
opData.push(od);
}
}
else {
@ -603,8 +587,8 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict, Cxt e
}, context, option);
this.mergeOperationResult(result, result2);
}
return result;
}
return result;
}
else {
opData = await this.destructCascadeUpdate(
@ -646,13 +630,26 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict, Cxt e
) {
const { data, action, id: operId, filter } = operation;
const now = Date.now();
const laterAction = isLaterAction(action);
switch (action || laterAction) {
switch (action) {
case 'create': {
if (laterAction) {
if (option.modiParentEntity && !['modi', 'modiEntity'].includes(entity as string)) {
// 变成对modi的插入
assert(false, '还未实现');
const modiCreate: CreateModiOperation = {
id: 'dummy',
action: 'create',
data: {
id: operId,
targetEntity: entity as string,
action,
entity: option.modiParentEntity!,
entityId: option.modiParentId!,
data,
iState: 'active',
},
};
await this.cascadeUpdate('modi', modiCreate, context, option);
return 1;
}
else {
const addTimestamp = (data2: ED[T]['CreateSingle']['data']) => {
@ -704,7 +701,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict, Cxt e
);
const updateData = omit(row, ['id', '$$createAt$$']);
const result3 = await this.updateAbjointRow(
entity,
entity,
{
id: await generateNewId(),
action: 'update',
@ -725,7 +722,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict, Cxt e
}
const updateData = omit(data, ['id', '$$createAt$$']);
const result2 = await this.updateAbjointRow(
entity,
entity,
{
id: await generateNewId(),
action: 'update',
@ -761,19 +758,19 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict, Cxt e
action,
data,
operatorId: await context.getCurrentUserId(),
operEntity$oper: data instanceof Array ? await Promise.all(
data.map(
async (ele) => ({
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<ED extends EntityDict & BaseEntityDict, Cxt e
ids.push(...(rows.map(ele => 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<ED extends EntityDict & BaseEntityDict, Cxt e
}
}
else {
if (Object.keys(data).length === 0) {
// 优化一下,如果不更新任何属性,则不实际执行
return 0;
}
Object.assign(data, {
$$updateAt$$: now,
});

View File

@ -1,10 +0,0 @@
/**
* action是不是延时性操作
* @param action
* @returns
*/
export function isLaterAction(action: string) {
if (action.endsWith('-l')) {
return action.slice(0, action.length -2);
}
}

View File

@ -111,6 +111,16 @@ export function getRelevantIds<ED extends EntityDict, T extends keyof ED>(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)

20
src/store/modi.ts Normal file
View File

@ -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 <string, Object, Object>,
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,
}
}
}
);
}

3
src/triggers/index.ts Normal file
View File

@ -0,0 +1,3 @@
import modiTriggers from './modi';
export default [...modiTriggers];

39
src/triggers/modi.ts Normal file
View File

@ -0,0 +1,39 @@
import { EntityDict } from "../base-app-domain";
import { Trigger } from "../types";
import { UniversalContext } from "../store/UniversalContext";
const triggers: Trigger<EntityDict, 'modi', UniversalContext<EntityDict>>[] = [
{
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;

View File

@ -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 extends string> = A | `${A}-l`;
export type MakeAction<A extends string> = A;
export interface EntityDef {
// Name: E;

View File

@ -52,6 +52,7 @@ export interface StorageDesc<SH extends EntityShape> {
uniqueConstraints?: UniqConstraint<SH>[];
indexes?: Index<SH>[];
config?: EntityConfig;
toModi?: true, // 标识一下是否关联在modi上
// view 相关
view?: true;
}