relation的一堆代码

This commit is contained in:
Xu Chang 2023-05-10 19:41:34 +08:00
parent 81440dd064
commit 5b749e94bd
16 changed files with 555 additions and 287 deletions

View File

@ -1,8 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.relations = exports.RelationCascadePathGraph = exports.ActionCascadePathGraph = void 0;
exports.ActionCascadePathGraph = [
["userRelation", "user", "userRelation", false]
];
exports.ActionCascadePathGraph = [];
exports.RelationCascadePathGraph = [];
exports.relations = [];

View File

@ -1,3 +1,5 @@
export declare function registerIgnoredRelationPathSet(set: Record<string, string[]>): void;
export declare function registerIgnoredForeignKeyMap(map: Record<string, string[]>): void;
export declare function registerIgnoredRelationPathMap(map: Record<string, string[]>): void;
export declare function registerDeducedRelationMap(map: Record<string, string>): void;
export declare function analyzeEntities(inputDir: string, relativePath?: string): void;
export declare function buildSchema(outputDir: string): void;

View File

@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildSchema = exports.analyzeEntities = exports.registerIgnoredRelationPathSet = void 0;
exports.buildSchema = exports.analyzeEntities = exports.registerDeducedRelationMap = exports.registerIgnoredRelationPathMap = exports.registerIgnoredForeignKeyMap = void 0;
var tslib_1 = require("tslib");
var path_1 = tslib_1.__importDefault(require("path"));
var assert_1 = tslib_1.__importDefault(require("assert"));
@ -3445,35 +3445,68 @@ function analyzeInModi() {
}
}
}
var IGNORED_RELATION_PATH_SET = {};
function registerIgnoredRelationPathSet(set) {
IGNORED_RELATION_PATH_SET = set;
var IGNORED_FOREIGN_KEY_MAP = {};
var IGNORED_RELATION_PATH_MAP = {};
var DEDUCED_RELATION_MAP = {};
function registerIgnoredForeignKeyMap(map) {
IGNORED_FOREIGN_KEY_MAP = map;
}
exports.registerIgnoredRelationPathSet = registerIgnoredRelationPathSet;
exports.registerIgnoredForeignKeyMap = registerIgnoredForeignKeyMap;
function registerIgnoredRelationPathMap(map) {
for (var k in map) {
IGNORED_RELATION_PATH_MAP[(0, string_1.firstLetterUpperCase)(k)] = map[k];
}
}
exports.registerIgnoredRelationPathMap = registerIgnoredRelationPathMap;
function registerDeducedRelationMap(map) {
var _loop_12 = function (k) {
var entity = (0, string_1.firstLetterUpperCase)(k);
(0, assert_1.default)(Schema.hasOwnProperty(entity), "config/relation.ts\u4E2D\u914D\u7F6E\u7684DeducedRelationMap\u5305\u542B\u4E0D\u5408\u6CD5\u7684\u5BF9\u8C61\u540D\u79F0\u300C".concat(k, "\u300D"));
// 定义的deduce的属性一定是多对一的外键此时ReversePointerEntities还未处理
if (ReversePointerEntities[entity] && map[k] === 'entity') {
}
else {
var mto = ManyToOne[entity].find(function (ele) { return ele[1] === map[k]; });
(0, assert_1.default)(mto, "config/relation.ts\u4E2D\u914D\u7F6E\u7684DeducedRelationMap\u6240\u5B9A\u4E49\u7684\u300C".concat(k, "\u300D\u7684deduce\u5C5E\u6027\u300C").concat(map[k], "\u300D\u4E0D\u662F\u4E00\u4E2A\u6709\u6548\u7684\u5916\u952E\u6307\u9488"));
}
DEDUCED_RELATION_MAP[entity] = map[k];
};
for (var k in map) {
_loop_12(k);
}
}
exports.registerDeducedRelationMap = registerDeducedRelationMap;
/**
* 输出所有和User相关的对象的后继
*/
function outputRelation(outputDir, printer) {
var ExcludedEntities = ['Oper', 'User', 'OperEntity', 'Modi', 'ModiEntity', 'UserEntityGrant'];
var ExcludedEntities = ['Oper', 'User', 'OperEntity', 'Modi', 'ModiEntity', 'UserRelation'];
var actionPath = [];
var relationPath = [];
var outputRecursively = function (root, entity, path, paths, isRelation) {
var _a;
if (ExcludedEntities.includes(entity)) {
return;
}
if (paths.length > 32) {
if ((_a = IGNORED_RELATION_PATH_MAP[entity]) === null || _a === void 0 ? void 0 : _a.find(function (ele) { return path.includes(ele); })) {
return;
}
if (paths.length > 12) {
throw new Error('对象之间的关系深度过长,请优化设计加以避免');
}
actionPath.push([(0, string_1.firstLetterLowerCase)(entity), path, root, isRelation]);
if (!DEDUCED_RELATION_MAP[entity]) {
actionPath.push([(0, string_1.firstLetterLowerCase)(entity), path, root, isRelation]);
}
if (Schema[entity].hasRelationDef) {
// assert(!DEDUCED_RELATION_MAP[entity], `${entity}对象定义了deducedRelationMap但它有relation`);
relationPath.push([(0, string_1.firstLetterLowerCase)(entity), path, root, isRelation]);
}
var _a = OneToMany, _b = entity, parent = _a[_b];
var _b = OneToMany, _c = entity, parent = _b[_c];
if (parent) {
parent.forEach(function (_a) {
var _b;
var _c = tslib_1.__read(_a, 2), child = _c[0], foreignKey = _c[1];
if (child !== entity && !paths.includes((0, string_1.firstLetterLowerCase)(child)) && !((_b = IGNORED_RELATION_PATH_SET[(0, string_1.firstLetterLowerCase)(child)]) === null || _b === void 0 ? void 0 : _b.includes(foreignKey))) {
if (child !== entity && !paths.includes((0, string_1.firstLetterLowerCase)(child)) && !((_b = IGNORED_FOREIGN_KEY_MAP[(0, string_1.firstLetterLowerCase)(child)]) === null || _b === void 0 ? void 0 : _b.includes(foreignKey))) {
// 如果有递归直接忽略,递归对象在设计时不要进入这个链条
var fk = foreignKey === 'entity' ? (0, string_1.firstLetterLowerCase)(entity) : foreignKey;
var path2 = path ? "".concat(fk, ".").concat(path) : fk;
@ -3516,7 +3549,10 @@ function outputRelation(outputDir, printer) {
}
}
var stmts = [
factory.createImportDeclaration(undefined, undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, undefined, factory.createIdentifier("AuthCascadePath"))])), factory.createStringLiteral("".concat((0, env_1.TYPE_PATH_IN_OAK_DOMAIN)(1), "Entity")), undefined),
factory.createImportDeclaration(undefined, undefined, factory.createImportClause(false, undefined, factory.createNamedImports([
factory.createImportSpecifier(false, undefined, factory.createIdentifier("AuthCascadePath")),
factory.createImportSpecifier(false, undefined, factory.createIdentifier("AuthDeduceRelationMap"))
])), factory.createStringLiteral("".concat((0, env_1.TYPE_PATH_IN_OAK_DOMAIN)(1), "Entity")), undefined),
factory.createImportDeclaration(undefined, undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, undefined, factory.createIdentifier("EntityDict"))])), factory.createStringLiteral("./EntityDict"), undefined),
factory.createImportDeclaration(undefined, undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, factory.createIdentifier("CreateOperationData"), factory.createIdentifier("Relation"))])), factory.createStringLiteral("./Relation/Schema"), undefined),
factory.createVariableStatement([factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([factory.createVariableDeclaration(factory.createIdentifier("ActionCascadePathGraph"), undefined, factory.createArrayTypeNode(factory.createTypeReferenceNode(factory.createIdentifier("AuthCascadePath"), [factory.createTypeReferenceNode(factory.createIdentifier("EntityDict"), undefined)])), factory.createArrayLiteralExpression(actionPath.map(function (_a) {
@ -3546,6 +3582,13 @@ function outputRelation(outputDir, printer) {
], true); });
})), true))], ts.NodeFlags.Const))
];
if (Object.keys(DEDUCED_RELATION_MAP).length > 0) {
stmts.push(factory.createVariableStatement([
factory.createToken(ts.SyntaxKind.ExportKeyword)
], factory.createVariableDeclarationList([
factory.createVariableDeclaration(factory.createIdentifier("DeducedRelationMap"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("AuthDeduceRelationMap"), [factory.createTypeReferenceNode(factory.createIdentifier("EntityDict"), undefined)]), factory.createObjectLiteralExpression(Object.keys(DEDUCED_RELATION_MAP).map(function (ele) { return factory.createPropertyAssignment(factory.createIdentifier((0, string_1.firstLetterLowerCase)(ele)), factory.createStringLiteral(DEDUCED_RELATION_MAP[ele])); }), true))
], ts.NodeFlags.Const)));
}
var result = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray(stmts), ts.createSourceFile("someFileName.ts", "", ts.ScriptTarget.Latest, /*setParentNodes*/ false, ts.ScriptKind.TS));
var filename = path_1.default.join(outputDir, 'Relation.ts');
(0, fs_1.writeFileSync)(filename, result, { flag: 'w' });

View File

@ -1,18 +1,19 @@
import { EntityDict } from "../base-app-domain";
import { StorageSchema, Trigger } from "../types";
import { AuthCascadePath, EntityDict as BaseEntityDict } from "../types/Entity";
import { AuthCascadePath, EntityDict as BaseEntityDict, AuthDeduceRelationMap } from "../types/Entity";
import { AsyncContext } from "./AsyncRowStore";
import { SyncContext } from "./SyncRowStore";
export declare class RelationAuth<ED extends EntityDict & BaseEntityDict> {
private actionCascadePathGraph;
private relationCascadePathGraph;
private authDeduceRelationMap;
private schema;
private relationalFilterMaker;
private relationalCreateChecker;
private directActionAuthMap;
private freeActionAuthMap;
private constructFilterMaker;
constructor(actionCascadePathGraph: AuthCascadePath<ED>[], relationCascadePathGraph: AuthCascadePath<ED>[], schema: StorageSchema<ED>);
constructor(schema: StorageSchema<ED>, actionCascadePathGraph: AuthCascadePath<ED>[], relationCascadePathGraph: AuthCascadePath<ED>[], authDeduceRelationMap: AuthDeduceRelationMap<ED>);
private makeDirectionActionAuthMap;
setDirectionActionAuths(directActionAuths: ED['directActionAuth']['OpSchema'][]): void;
setFreeActionAuths(freeActionAuths: ED['freeActionAuth']['OpSchema'][]): void;
@ -20,6 +21,14 @@ export declare class RelationAuth<ED extends EntityDict & BaseEntityDict> {
private upsertDirectActionAuth;
private removeDirectActionAuth;
checkRelationSync<T extends keyof ED, Cxt extends SyncContext<ED>>(entity: T, operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt): void;
private checkActionAsync;
/**
* entity上执行Operationpath路径的父对象上执行相关的action操作relation判定
* @param entity
* @param operation
* @param context
*/
private checkCascadeActionAsync;
checkRelationAsync<T extends keyof ED, Cxt extends AsyncContext<ED>>(entity: T, operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt): Promise<void>;
/**
*

View File

@ -8,13 +8,14 @@ var AsyncRowStore_1 = require("./AsyncRowStore");
var filter_1 = require("./filter");
var relation_1 = require("./relation");
var RelationAuth = /** @class */ (function () {
function RelationAuth(actionCascadePathGraph, relationCascadePathGraph, schema) {
function RelationAuth(schema, actionCascadePathGraph, relationCascadePathGraph, authDeduceRelationMap) {
this.directActionAuthMap = {};
this.actionCascadePathGraph = actionCascadePathGraph;
this.relationCascadePathGraph = relationCascadePathGraph;
this.schema = schema;
this.relationalFilterMaker = {};
this.relationalCreateChecker = {};
this.authDeduceRelationMap = authDeduceRelationMap;
this.constructFilterMaker();
}
RelationAuth.prototype.constructFilterMaker = function () {
@ -112,6 +113,9 @@ var RelationAuth = /** @class */ (function () {
};
};
var _loop_1 = function (entity) {
/* if (pathGroup[entity]!.length > 6) {
throw new Error(`${entity as string}上的actionPath数量大于6请优化}`);
} */
var filterMakers = pathGroup[entity].map(function (ele) {
var _a = tslib_1.__read(ele, 4), e = _a[0], p = _a[1], r = _a[2], ir = _a[3]; // entity, path, root, isRelation
var daKey = "".concat(e, "-").concat(p, "-").concat(r);
@ -149,30 +153,10 @@ var RelationAuth = /** @class */ (function () {
return function (userId, directActionAuth, data, filter) {
if (data) {
var id_1 = data.id;
return function (context) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
var actionAuths, assignPossibleRelation;
return tslib_1.__generator(this, function (_a) {
actionAuths = context.select('actionAuth', {
data: {
id: 1,
relationId: 1,
destEntity: 1,
relation: {
id: 1,
name: 1,
},
},
filter: {
path: '',
deActions: {
$contains: 'create',
},
relation: {
entity: e,
},
},
}, {});
assignPossibleRelation = function (aas) {
return function (context) {
// 只对后台需要创建,前台直接返回
if (context instanceof AsyncRowStore_1.AsyncContext) {
var assignPossibleRelation_1 = function (aas) {
if (aas.length > 0) {
(0, assert_1.default)(aas.length === 1, "\u5728".concat(e, "\u4E0A\u7684\u81EA\u8EAB\u5173\u7CFB\u4E0A\u5B9A\u4E49\u4E86\u8D85\u8FC7\u4E00\u79CDcreate\u7684\u6743\u9650\uFF0C\u300C").concat(aas.map(function (ele) { return ele.relation.name; }).join(','), "\u300D"));
var relationId = aas[0].relationId;
@ -191,12 +175,29 @@ var RelationAuth = /** @class */ (function () {
}
return false;
};
if (actionAuths instanceof Promise) {
return [2 /*return*/, actionAuths.then(function (aas) { return assignPossibleRelation(aas); })];
}
return [2 /*return*/, assignPossibleRelation(actionAuths)];
});
}); };
return context.select('actionAuth', {
data: {
id: 1,
relationId: 1,
destEntity: 1,
relation: {
id: 1,
name: 1,
},
},
filter: {
path: '',
deActions: {
$contains: 'create',
},
relation: {
entity: e,
},
},
}, {}).then(function (actionAuths) { return assignPossibleRelation_1(actionAuths); }).then(function () { return true; });
}
return true;
};
}
return function () { return true; };
};
@ -205,20 +206,25 @@ var RelationAuth = /** @class */ (function () {
// 同样是直接关联在本对象上在create的时候直接赋予userId
var rel_1 = (0, relation_1.judgeRelation)(_this.schema, e, paths[0]);
return function (userId, directActionAuth, data, filter) {
var _a;
if (data) {
if (rel_1 === 2) {
Object.assign(data, {
entity: 'user',
entityId: userId,
});
}
else {
(0, assert_1.default)(typeof rel_1 === 'string');
Object.assign(data, (_a = {},
_a["".concat(paths[0], "Id")] = userId,
_a));
}
return function (context) {
var _a;
if (context instanceof AsyncRowStore_1.AsyncContext) {
if (rel_1 === 2) {
Object.assign(data, {
entity: 'user',
entityId: userId,
});
}
else {
(0, assert_1.default)(typeof rel_1 === 'string');
Object.assign(data, (_a = {},
_a["".concat(paths[0], "Id")] = userId,
_a));
}
}
return true;
};
}
return function () { return true; };
};
@ -271,11 +277,11 @@ var RelationAuth = /** @class */ (function () {
// 其它情况都是检查其data或者filter中的外键指向是否满足relation约束关系
return function (userId, directActionAuthMap, data, filter) {
if (!filter && !data) {
return function () { return false; };
return false;
}
var result = translateFilterToSelect(e, (filter || data), 0, userId, directActionAuthMap);
if (!result) {
return function () { return false; };
return false;
}
return function (context) {
var entity = result.entity, filter = result.filter, relationalFilter = result.relationalFilter;
@ -284,7 +290,10 @@ var RelationAuth = /** @class */ (function () {
};
});
this_1.relationalCreateChecker[entity] = function (userId, directActionAuthMap, data, filter) {
var callbacks = createCheckers.map(function (ele) { return ele(userId, directActionAuthMap, data, filter); });
var callbacks = createCheckers.map(function (ele) { return ele(userId, directActionAuthMap, data, filter); }).filter(function (ele) { return typeof ele === 'function'; });
if (callbacks.length > 6) {
throw new types_1.OakDataException("\u5728create\u300C".concat(entity, "\u300D\u65F6relation\u76F8\u5173\u7684\u6743\u9650\u68C0\u67E5\u8FC7\u591A\uFF0C\u8BF7\u4F18\u5316actionAuth\u7684\u8DEF\u5F84"));
}
return function (context) {
var result = callbacks.map(function (ele) { return ele(context); });
// 回调中只要有一个通过就算过
@ -432,14 +441,74 @@ var RelationAuth = /** @class */ (function () {
}
throw new types_1.OakUnloggedInException();
};
RelationAuth.prototype.checkActionAsync = function (entity, operation, context) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var action, userId, _a, data, filter, callback, filter, operationFilter;
var _this = this;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
action = operation.action || 'select';
userId = context.getCurrentUserId();
if (!(action === 'create' && this.relationalCreateChecker[entity])) return [3 /*break*/, 5];
_a = operation, data = _a.data, filter = _a.filter;
if (!(data instanceof Array)) return [3 /*break*/, 2];
return [4 /*yield*/, Promise.all(data.map(function (ele) {
var callback = _this.relationalCreateChecker[entity](userId, _this.directActionAuthMap, ele);
return callback(context);
}))];
case 1:
_b.sent();
return [3 /*break*/, 4];
case 2:
(0, assert_1.default)(data);
callback = this.relationalCreateChecker[entity](userId, this.directActionAuthMap, data);
return [4 /*yield*/, callback(context)];
case 3:
_b.sent();
_b.label = 4;
case 4: return [3 /*break*/, 7];
case 5:
if (!(action !== 'create' && this.relationalFilterMaker[entity])) return [3 /*break*/, 7];
filter = this.relationalFilterMaker[entity](action, userId, this.directActionAuthMap);
operationFilter = operation.filter;
(0, assert_1.default)(filter, "\u5728\u68C0\u67E5".concat(entity, "\u4E0A\u6267\u884C").concat(action, "\u64CD\u4F5C\u65F6\u6CA1\u6709\u4F20\u5165filter"));
return [4 /*yield*/, (0, filter_1.checkFilterContains)(entity, context, filter, operationFilter, true)];
case 6:
if (_b.sent()) {
return [2 /*return*/];
}
throw new types_1.OakUserUnpermittedException("\u5F53\u524D\u7528\u6237\u4E0D\u5141\u8BB8\u5728".concat(entity, "\u4E0A\u6267\u884C").concat(action, "\u64CD\u4F5C"));
case 7: throw new types_1.OakUnloggedInException();
}
});
});
};
/**
* 在entity上执行Operation等同于在其path路径的父对象上执行相关的action操作进行relation判定
* @param entity
* @param operation
* @param context
*/
RelationAuth.prototype.checkCascadeActionAsync = function (entity, operation, path, action, context) {
return tslib_1.__awaiter(this, void 0, void 0, function () {
var childData, childFilter, childAction, paths;
return tslib_1.__generator(this, function (_a) {
childData = operation.data, childFilter = operation.filter;
childAction = operation.action || 'select';
(0, assert_1.default)(path);
paths = path.split('.');
return [2 /*return*/];
});
});
};
// 后台检查filter是否满足relation约束
RelationAuth.prototype.checkRelationAsync = function (entity, operation, context) {
var _a;
return tslib_1.__awaiter(this, void 0, void 0, function () {
var action, userId, _b, data, filter, callback, callback, filter, operationFilter;
var _this = this;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
var action, userId;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
if (context.isRoot()) {
return [2 /*return*/];
@ -453,43 +522,26 @@ var RelationAuth = /** @class */ (function () {
if (!userId) {
throw new types_1.OakNoRelationDefException(entity, action);
}
if (!(action === 'create' && this.relationalCreateChecker[entity])) return [3 /*break*/, 7];
_b = operation, data = _b.data, filter = _b.filter;
if (!filter) return [3 /*break*/, 2];
callback = this.relationalCreateChecker[entity](userId, this.directActionAuthMap, undefined, filter);
return [4 /*yield*/, callback(context)];
// 对compile中放过的几个特殊meta对象的处理
/* switch (entity as string) {
case 'modi': {
if (action === 'select') {
return this.checkActionAsync()
}
}
} */
return [4 /*yield*/, this.checkActionAsync(entity, operation, context)];
case 1:
_c.sent();
return [3 /*break*/, 6];
case 2:
if (!(data instanceof Array)) return [3 /*break*/, 4];
return [4 /*yield*/, Promise.all(data.map(function (ele) {
var callback = _this.relationalCreateChecker[entity](userId, _this.directActionAuthMap, ele);
return callback(context);
}))];
case 3:
_c.sent();
return [3 /*break*/, 6];
case 4:
(0, assert_1.default)(data);
callback = this.relationalCreateChecker[entity](userId, this.directActionAuthMap, data);
return [4 /*yield*/, callback(context)];
case 5:
_c.sent();
_c.label = 6;
case 6: return [3 /*break*/, 9];
case 7:
if (!(action !== 'create' && this.relationalFilterMaker[entity])) return [3 /*break*/, 9];
filter = this.relationalFilterMaker[entity](action, userId, this.directActionAuthMap);
operationFilter = operation.filter;
(0, assert_1.default)(filter, "\u5728\u68C0\u67E5".concat(entity, "\u4E0A\u6267\u884C").concat(action, "\u64CD\u4F5C\u65F6\u6CA1\u6709\u4F20\u5165filter"));
return [4 /*yield*/, (0, filter_1.checkFilterContains)(entity, context, filter, operationFilter, true)];
case 8:
if (_c.sent()) {
return [2 /*return*/];
}
throw new types_1.OakUserUnpermittedException("\u5F53\u524D\u7528\u6237\u4E0D\u5141\u8BB8\u5728".concat(entity, "\u4E0A\u6267\u884C").concat(action, "\u64CD\u4F5C"));
case 9: throw new types_1.OakUnloggedInException();
// 对compile中放过的几个特殊meta对象的处理
/* switch (entity as string) {
case 'modi': {
if (action === 'select') {
return this.checkActionAsync()
}
}
} */
_b.sent();
return [2 /*return*/];
}
});
});

View File

@ -211,6 +211,73 @@ function createModiRelatedTriggers(schema) {
for (var entity in schema) {
_loop_2(entity);
}
return triggers;
// modi被应用时的效用搬到这里了
var applyTrigger = {
name: '当modi被应用时将相应的operate完成',
entity: 'modi',
action: 'apply',
when: 'after',
fn: function (_a, context, option) {
var operation = _a.operation;
return tslib_1.__awaiter(_this, 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.select('modi', {
data: {
id: 1,
action: 1,
data: 1,
filter: 1,
targetEntity: 1,
},
filter: filter,
}, option)];
case 1:
modies = _c.sent();
_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.operate(targetEntity, {
id: id,
action: action,
data: data,
filter: filter_1,
}, Object.assign({}, option, {
blockTrigger: true,
}))];
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];
}
});
});
}
};
return triggers.concat([applyTrigger]);
}
exports.createModiRelatedTriggers = createModiRelatedTriggers;

View File

@ -1,6 +1,4 @@
import { EntityDict as BaseEntityDict } from '../base-app-domain';
import { StorageSchema, EntityDict } from '../types';
import { AsyncContext } from '../store/AsyncRowStore';
declare const _default: import("../types").Trigger<BaseEntityDict, "modi", AsyncContext<BaseEntityDict>>[];
export default _default;
export declare function createDynamicTriggers<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>>(schema: StorageSchema<ED>): import("../types").Trigger<ED, keyof ED, Cxt>[];

View File

@ -1,11 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createDynamicTriggers = void 0;
var tslib_1 = require("tslib");
var modi_1 = tslib_1.__importDefault(require("./modi"));
var modi_2 = require("../store/modi");
exports.default = tslib_1.__spreadArray([], tslib_1.__read(modi_1.default), false);
var modi_1 = require("../store/modi");
function createDynamicTriggers(schema) {
return (0, modi_2.createModiRelatedTriggers)(schema);
return (0, modi_1.createModiRelatedTriggers)(schema);
}
exports.createDynamicTriggers = createDynamicTriggers;

View File

@ -182,4 +182,7 @@ export declare type Configuration = {
static?: boolean;
};
export declare type AuthCascadePath<ED extends EntityDict> = [keyof ED, string, keyof ED, boolean];
export declare type AuthDeduceRelationMap<ED extends EntityDict> = {
[T in keyof ED]?: keyof ED[T]['OpSchema'];
};
export {};

View File

@ -1998,7 +1998,7 @@ function constructProjection(statements: Array<ts.Statement>, entity: string) {
}
}
else {
if (!enumAttributes || !enumAttributes[attrName]) {
if (!enumAttributes || !enumAttributes[attrName]) {
// 引用的非enum类型shape
properties.push(
[name, false, factory.createUnionTypeNode([
@ -4743,8 +4743,8 @@ function outputSubQuery(outputDir: string, printer: ts.Printer) {
/* .filter(
([e, f]) => f !== 'entity'
) */.map(
([e]) => e
)) : [];
([e]) => e
)) : [];
fromEntites.push(one);
const inUnionTypeNode: ts.TypeNode[] = fromEntites.map(
@ -6012,7 +6012,7 @@ function outputStorage(outputDir: string, printer: ts.Printer) {
)
);
propertyAssignments.push(
factory.createShorthandPropertyAssignment(
factory.createIdentifier("actions"),
@ -6262,34 +6262,72 @@ function analyzeInModi() {
}
let IGNORED_RELATION_PATH_SET: Record<string, string[]> = {}
let IGNORED_FOREIGN_KEY_MAP: Record<string, string[]> = {};
let IGNORED_RELATION_PATH_MAP: Record<string, string[]> = {};
let DEDUCED_RELATION_MAP: Record<string, string> = {};
export function registerIgnoredRelationPathSet(set: Record<string, string[]>) {
IGNORED_RELATION_PATH_SET = set;
export function registerIgnoredForeignKeyMap(map: Record<string, string[]>) {
IGNORED_FOREIGN_KEY_MAP = map;
}
export function registerIgnoredRelationPathMap(map: Record<string, string[]>) {
for (const k in map) {
IGNORED_RELATION_PATH_MAP[firstLetterUpperCase(k)] = map[k];
}
}
export function registerDeducedRelationMap(map: Record<string, string>) {
for (const k in map) {
const entity = firstLetterUpperCase(k);
assert(Schema.hasOwnProperty(entity), `config/relation.ts中配置的DeducedRelationMap包含不合法的对象名称「${k}`);
// 定义的deduce的属性一定是多对一的外键此时ReversePointerEntities还未处理
if (ReversePointerEntities[entity] && map[k] === 'entity') {
}
else {
const mto = ManyToOne[entity].find(
ele => ele[1] === map[k]
);
assert(mto, `config/relation.ts中配置的DeducedRelationMap所定义的「${k}」的deduce属性「${map[k]}」不是一个有效的外键指针`);
}
DEDUCED_RELATION_MAP[entity] = map[k];
}
}
/**
* User相关的对象的后继
*/
function outputRelation(outputDir: string, printer: ts.Printer) {
const ExcludedEntities = ['Oper', 'User', 'OperEntity', 'Modi', 'ModiEntity', 'UserEntityGrant'];
const ExcludedEntities = ['Oper', 'User', 'OperEntity', 'Modi', 'ModiEntity', 'UserRelation'];
const actionPath: [string, string, string, boolean][] = [];
const relationPath: [string, string, string, boolean][] = [];
const outputRecursively = (root: string, entity: string, path: string, paths: string[], isRelation: boolean) => {
if (ExcludedEntities.includes(entity)) {
return;
}
if (paths.length > 32) {
if (IGNORED_RELATION_PATH_MAP[entity]?.find(
(ele) => path.includes(ele)
)) {
return;
}
if (paths.length > 12) {
throw new Error('对象之间的关系深度过长,请优化设计加以避免');
}
actionPath.push([firstLetterLowerCase(entity), path, root, isRelation]);
if (!DEDUCED_RELATION_MAP[entity]) {
actionPath.push([firstLetterLowerCase(entity), path, root, isRelation]);
}
if (Schema[entity].hasRelationDef) {
// assert(!DEDUCED_RELATION_MAP[entity], `${entity}对象定义了deducedRelationMap但它有relation`);
relationPath.push([firstLetterLowerCase(entity), path, root, isRelation]);
}
const { [entity]: parent } = OneToMany;
if (parent) {
parent.forEach(
([child, foreignKey]) => {
if (child !== entity && !paths.includes(firstLetterLowerCase(child)) && !IGNORED_RELATION_PATH_SET[firstLetterLowerCase(child)]?.includes(foreignKey)) {
if (child !== entity && !paths.includes(firstLetterLowerCase(child)) && !IGNORED_FOREIGN_KEY_MAP[firstLetterLowerCase(child)]?.includes(foreignKey)) {
// 如果有递归直接忽略,递归对象在设计时不要进入这个链条
const fk = foreignKey === 'entity' ? firstLetterLowerCase(entity) : foreignKey;
const path2 = path ? `${fk}.${path}` : fk;
@ -6348,11 +6386,18 @@ function outputRelation(outputDir: string, printer: ts.Printer) {
factory.createImportClause(
false,
undefined,
factory.createNamedImports([factory.createImportSpecifier(
false,
undefined,
factory.createIdentifier("AuthCascadePath")
)])
factory.createNamedImports([
factory.createImportSpecifier(
false,
undefined,
factory.createIdentifier("AuthCascadePath")
),
factory.createImportSpecifier(
false,
undefined,
factory.createIdentifier("AuthDeduceRelationMap")
)
])
),
factory.createStringLiteral(`${TYPE_PATH_IN_OAK_DOMAIN(1)}Entity`),
undefined
@ -6489,6 +6534,40 @@ function outputRelation(outputDir: string, printer: ts.Printer) {
)
];
if (Object.keys(DEDUCED_RELATION_MAP).length > 0) {
stmts.push(
factory.createVariableStatement(
[
factory.createToken(ts.SyntaxKind.ExportKeyword)
],
factory.createVariableDeclarationList(
[
factory.createVariableDeclaration(
factory.createIdentifier("DeducedRelationMap"),
undefined,
factory.createTypeReferenceNode(
factory.createIdentifier("AuthDeduceRelationMap"),
[factory.createTypeReferenceNode(
factory.createIdentifier("EntityDict"),
undefined
)]
),
factory.createObjectLiteralExpression(
Object.keys(DEDUCED_RELATION_MAP).map(
ele => factory.createPropertyAssignment(
factory.createIdentifier(firstLetterLowerCase(ele)),
factory.createStringLiteral(DEDUCED_RELATION_MAP[ele])
)
),
true
)
)
],
ts.NodeFlags.Const
)
)
);
}
const result = printer.printList(
ts.ListFormat.SourceFileStatements,

View File

@ -1,7 +1,7 @@
import assert from "assert";
import { EntityDict } from "../base-app-domain";
import { CreateTrigger, OakNoRelationDefException, OakUnloggedInException, OakUserUnpermittedException, RemoveTrigger, StorageSchema, Trigger, UpdateTrigger } from "../types";
import { AuthCascadePath, EntityDict as BaseEntityDict } from "../types/Entity";
import { CreateTrigger, OakDataException, OakNoRelationDefException, OakUnloggedInException, OakUserUnpermittedException, RemoveTrigger, StorageSchema, Trigger, UpdateTrigger } from "../types";
import { AuthCascadePath, EntityDict as BaseEntityDict, AuthDeduceRelationMap } from "../types/Entity";
import { AsyncContext } from "./AsyncRowStore";
import { checkFilterContains } from "./filter";
import { judgeRelation } from "./relation";
@ -10,6 +10,7 @@ import { SyncContext } from "./SyncRowStore";
export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
private actionCascadePathGraph: AuthCascadePath<ED>[];
private relationCascadePathGraph: AuthCascadePath<ED>[];
private authDeduceRelationMap: AuthDeduceRelationMap<ED>;
private schema: StorageSchema<ED>;
private relationalFilterMaker: {
[T in keyof ED]?: (action: ED[T]['Action'] | 'select', userId: string, directActionAuthMap: Record<string, string[]>) => ED[T]['Selection']['filter'];
@ -134,6 +135,9 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
};
for (const entity in pathGroup) {
/* if (pathGroup[entity]!.length > 6) {
throw new Error(`${entity as string}上的actionPath数量大于6请优化}`);
} */
const filterMakers = pathGroup[entity]!.map(
(ele) => {
const [e, p, r, ir] = ele; // entity, path, root, isRelation
@ -180,7 +184,7 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
directActionAuth: Record<string, string[]>,
data?: ED[T]['CreateSingle']['data'],
filter?: ED[T]['Selection']['filter']
) => <Cxt extends AsyncContext<ED> | SyncContext<ED>>(context: Cxt) => boolean | Promise<boolean>)[] = pathGroup[entity]!.map(
) => (<Cxt extends AsyncContext<ED> | SyncContext<ED>>(context: Cxt) => boolean | Promise<boolean>) | false)[] = pathGroup[entity]!.map(
(ele) => {
const [e, p, r, ir] = ele; // entity, path, root, isRelation
const daKey = `${e as string}-${p}-${r as string}`;
@ -197,57 +201,56 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
) => {
if (data) {
const { id } = data;
return async (context: AsyncContext<ED> | SyncContext<ED>) => {
const actionAuths = context.select('actionAuth', {
data: {
id: 1,
relationId: 1,
destEntity: 1,
relation: {
id: 1,
name: 1,
},
},
filter: {
path: '',
deActions: {
$contains: 'create',
},
relation: {
entity: e as string,
},
},
}, {});
const assignPossibleRelation = (aas: ED['actionAuth']['Schema'][]) => {
if (aas.length > 0) {
assert(aas.length === 1, `${e as string}上的自身关系上定义了超过一种create的权限${aas.map(ele => ele.relation!.name).join(',')}`);
const { relationId } = aas[0];
Object.assign(data, {
userRelation$entity: {
action: 'create',
data: {
entity: e as string,
entityId: id,
relationId,
userId,
return (context: AsyncContext<ED> | SyncContext<ED>) => {
// 只对后台需要创建,前台直接返回
if (context instanceof AsyncContext) {
const assignPossibleRelation = (aas: ED['actionAuth']['Schema'][]) => {
if (aas.length > 0) {
assert(aas.length === 1, `${e as string}上的自身关系上定义了超过一种create的权限${aas.map(ele => ele.relation!.name).join(',')}`);
const { relationId } = aas[0];
Object.assign(data, {
userRelation$entity: {
action: 'create',
data: {
entity: e as string,
entityId: id,
relationId,
userId,
}
}
}
});
return true;
}
return false;
};
if (actionAuths instanceof Promise) {
return actionAuths.then(
(aas) => assignPossibleRelation(aas as ED['actionAuth']['Schema'][])
});
return true;
}
return false;
};
return context.select('actionAuth', {
data: {
id: 1,
relationId: 1,
destEntity: 1,
relation: {
id: 1,
name: 1,
},
},
filter: {
path: '',
deActions: {
$contains: 'create',
},
relation: {
entity: e as string,
},
},
}, {}).then(
(actionAuths) => assignPossibleRelation(actionAuths as ED['actionAuth']['Schema'][])
).then(
() => true
);
}
return assignPossibleRelation(actionAuths as ED['actionAuth']['Schema'][]);
return true;
};
}
return () => true;
};
}
@ -261,18 +264,23 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
filter?: ED[T]['Selection']['filter']
) => {
if (data) {
if (rel === 2) {
Object.assign(data, {
entity: 'user',
entityId: userId,
});
}
else {
assert(typeof rel === 'string');
Object.assign(data, {
[`${paths[0]}Id`]: userId,
})
}
return (context) => {
if (context instanceof AsyncContext) {
if (rel === 2) {
Object.assign(data, {
entity: 'user',
entityId: userId,
});
}
else {
assert(typeof rel === 'string');
Object.assign(data, {
[`${paths[0]}Id`]: userId,
});
}
}
return true;
};
}
return () => true;
};
@ -342,11 +350,11 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
filter?: ED[T]['Selection']['filter']
) => {
if (!filter && !data) {
return () => false;
return false;
}
const result = translateFilterToSelect(e, (filter || data)!, 0, userId, directActionAuthMap);
if (!result) {
return () => false;
return false;
}
return (context) => {
const { entity, filter, relationalFilter } = result;
@ -364,7 +372,14 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
) => {
const callbacks = createCheckers.map(
ele => ele(userId, directActionAuthMap, data, filter)
);
).filter(
ele => typeof ele === 'function'
) as (<Cxt extends AsyncContext<ED> | SyncContext<ED>>(context: Cxt) => boolean | Promise<boolean>)[];
if (callbacks.length > 6) {
throw new OakDataException(`在create「${entity}」时relation相关的权限检查过多请优化actionAuth的路径`);
}
return (context) => {
const result = callbacks.map(
ele => ele(context)
@ -390,12 +405,13 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
}
}
constructor(actionCascadePathGraph: AuthCascadePath<ED>[], relationCascadePathGraph: AuthCascadePath<ED>[], schema: StorageSchema<ED>) {
constructor(schema: StorageSchema<ED>, actionCascadePathGraph: AuthCascadePath<ED>[], relationCascadePathGraph: AuthCascadePath<ED>[], authDeduceRelationMap: AuthDeduceRelationMap<ED>) {
this.actionCascadePathGraph = actionCascadePathGraph;
this.relationCascadePathGraph = relationCascadePathGraph;
this.schema = schema;
this.relationalFilterMaker = {};
this.relationalCreateChecker = {};
this.authDeduceRelationMap = authDeduceRelationMap;
this.constructFilterMaker();
}
@ -431,7 +447,7 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
const k = `$${destEntity}-${path}-${sourceEntity}`;
this.directActionAuthMap[k] = deActions;
}
private removeDirectActionAuth(directActionAuth: ED['directActionAuth']['OpSchema']) {
const { deActions, destEntity, sourceEntity, path } = directActionAuth;
const k = `$${destEntity}-${path}-${sourceEntity}`;
@ -514,32 +530,13 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
throw new OakUnloggedInException();
}
// 后台检查filter是否满足relation约束
async checkRelationAsync<T extends keyof ED, Cxt extends AsyncContext<ED>>(entity: T, operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt) {
if (context.isRoot()) {
return;
}
private async checkActionAsync<T extends keyof ED, Cxt extends AsyncContext<ED>>(entity: T, operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt) {
const action = (operation as ED[T]['Operation']).action || 'select';
// 后台用缓存的faa来判定减少对数据库的查询freeActionAuth表很少更新
if (!this.freeActionAuthMap || this.freeActionAuthMap[entity as string]?.includes(action)) {
return;
}
const userId = context.getCurrentUserId();
if (!userId) {
throw new OakNoRelationDefException<ED, T>(entity, action);
}
// 后台用缓存的daa来判定减少对数据库的查询freeActionAuth表很少更新
const userId = context.getCurrentUserId()!;
if (action === 'create' && this.relationalCreateChecker[entity]) {
const { data, filter } = operation as ED[T]['Create'];
if (filter) {
// 如果create传了filter, 前台保证create一定满足此约束优先判断
const callback = this.relationalCreateChecker[entity]!(userId, this.directActionAuthMap, undefined, filter);
await callback(context);
}
else if (data instanceof Array) {
// 后台不用判断filter吧
if (data instanceof Array) {
await Promise.all(
data.map(
(ele) => {
@ -567,6 +564,55 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
throw new OakUnloggedInException();
}
/**
* entity上执行Operationpath路径的父对象上执行相关的action操作relation判定
* @param entity
* @param operation
* @param context
*/
private async checkCascadeActionAsync<T extends keyof ED, Cxt extends AsyncContext<ED>>(
entity: T,
operation: ED[T]['Operation'] | ED[T]['Selection'],
path: string,
action: string,
context: Cxt
) {
const { data: childData, filter: childFilter } = operation;
const childAction = (operation as ED[T]['Operation']).action || 'select';
assert(path);
const paths = path.split('.');
}
// 后台检查filter是否满足relation约束
async checkRelationAsync<T extends keyof ED, Cxt extends AsyncContext<ED>>(entity: T, operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt) {
if (context.isRoot()) {
return;
}
const action = (operation as ED[T]['Operation']).action || 'select';
// 后台用缓存的faa来判定减少对数据库的查询freeActionAuth表很少更新
if (!this.freeActionAuthMap || this.freeActionAuthMap[entity as string]?.includes(action)) {
return;
}
const userId = context.getCurrentUserId();
if (!userId) {
throw new OakNoRelationDefException<ED, T>(entity, action);
}
// 对compile中放过的几个特殊meta对象的处理
/* switch (entity as string) {
case 'modi': {
if (action === 'select') {
return this.checkActionAsync()
}
}
} */
await this.checkActionAsync(entity, operation, context);
}
/**
*
* (todo)
@ -597,7 +643,7 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
action: 'update',
when: 'commit',
name: 'freeActionAuth更新时刷新relationAuth中的缓存数据',
fn: async({ operation }, context) => {
fn: async ({ operation }, context) => {
const { data, filter } = operation;
assert(typeof filter!.id === 'string'); // freeAuthDict不应当有其它更新的情况
assert(!data.destEntity);
@ -623,7 +669,7 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
action: 'remove',
when: 'commit',
name: 'freeActionAuth删除时刷新relationAuth中的缓存数据',
fn: async({ operation }, context) => {
fn: async ({ operation }, context) => {
const { data, filter } = operation;
assert(typeof filter!.id === 'string'); // freeActionAuth不应当有其它更新的情况
const faas = await context.select('freeActionAuth', {
@ -667,7 +713,7 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
action: 'update',
when: 'commit',
name: 'directActionAuth更新时刷新relationAuth中的缓存数据',
fn: async({ operation }, context) => {
fn: async ({ operation }, context) => {
const { data, filter } = operation;
assert(typeof filter!.id === 'string'); // freeAuthDict不应当有其它更新的情况
assert(!data.destEntity && !data.sourceEntity && !data.path);
@ -694,7 +740,7 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
action: 'remove',
when: 'commit',
name: 'directActionAuth删除时刷新relationAuth中的缓存数据',
fn: async({ operation }, context) => {
fn: async ({ operation }, context) => {
const { data, filter } = operation;
assert(typeof filter!.id === 'string'); // directActionAuth不应当有其它更新的情况
const daas = await context.select('directActionAuth', {
@ -715,4 +761,4 @@ export class RelationAuth<ED extends EntityDict & BaseEntityDict>{
} as RemoveTrigger<ED, 'directActionAuth', Cxt>,
] as Trigger<ED, keyof ED, Cxt>[];
}
}
}

View File

@ -1,20 +0,0 @@
import { EntityDict } from '../types/Entity';
import { EntityDict as BaseEntityDict } from '../base-app-domain';
import { StorageSchema } from '../types/Storage';
import { AuthDefDict, RelationChecker } from '../types/Auth';
import { AsyncContext } from './AsyncRowStore';
import { SyncContext } from './SyncRowStore';
export default class ArAuth<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED> | SyncContext<ED>> {
constructor(schema: StorageSchema<ED>, authDict: AuthDefDict<ED>) {
}
getRelationalCheckers(): RelationChecker<ED, keyof ED, Cxt>[] {
throw new Error('method not implemented');
}
addRelation(relation: ED['relation']['Schema']) {
}
}

View File

@ -187,6 +187,41 @@ export function createModiRelatedTriggers<ED extends EntityDict & BaseEntityDict
}
}
return triggers;
// modi被应用时的效用搬到这里了
const applyTrigger: Trigger<EntityDict, 'modi', AsyncContext<EntityDict>> = {
name: '当modi被应用时将相应的operate完成',
entity: 'modi',
action: 'apply',
when: 'after',
fn: async ({ operation }, context, option) => {
const { filter } = operation;
const modies = await context.select('modi', {
data: {
id: 1,
action: 1,
data: 1,
filter: 1,
targetEntity: 1,
},
filter,
}, option);
for (const modi of modies) {
const { targetEntity, id, action, data, filter } = modi;
await context.operate(targetEntity as keyof EntityDict, {
id: id!,
action: action as EntityDict[keyof EntityDict]['Action'],
data: data as EntityDict[keyof EntityDict]['Update']['data'],
filter: filter as EntityDict[keyof EntityDict]['Update']['filter'],
}, Object.assign({}, option, {
blockTrigger: true,
}));
}
return modies.length;
}
};
return triggers.concat([applyTrigger as Trigger<ED, keyof ED, Cxt>]);
}

View File

@ -1,11 +1,8 @@
import { EntityDict as BaseEntityDict } from '../base-app-domain';
import { StorageSchema, EntityDict } from '../types';
import modiTriggers from './modi';
import { createModiRelatedTriggers } from '../store/modi';
import { AsyncContext } from '../store/AsyncRowStore';
export default [...modiTriggers];
export function createDynamicTriggers<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED>>(schema: StorageSchema<ED>) {
return createModiRelatedTriggers<ED, Cxt>(schema);
}

View File

@ -1,41 +0,0 @@
import { EntityDict } from "../base-app-domain";
import { AsyncContext } from "../store/AsyncRowStore";
import { Trigger, UpdateTrigger } from "../types";
const triggers: Trigger<EntityDict, 'modi', AsyncContext<EntityDict>>[] = [
{
name: '当modi被应用时将相应的operate完成',
entity: 'modi',
action: 'apply',
when: 'after',
fn: async ({ operation }, context, option) => {
const { filter } = operation;
const modies = await context.select('modi', {
data: {
id: 1,
action: 1,
data: 1,
filter: 1,
targetEntity: 1,
},
filter,
}, option);
for (const modi of modies) {
const { targetEntity, id, action, data, filter} = modi;
await context.operate(targetEntity as keyof EntityDict, {
id: id!,
action: action as EntityDict[keyof EntityDict]['Action'],
data: data as EntityDict[keyof EntityDict]['Update']['data'],
filter: filter as EntityDict[keyof EntityDict]['Update']['filter'],
}, Object.assign({}, option, {
blockTrigger: true,
}));
}
return modies.length;
}
}
];
export default triggers;

View File

@ -259,3 +259,6 @@ export type Configuration = {
};
export type AuthCascadePath<ED extends EntityDict> = [keyof ED, string, keyof ED, boolean];
export type AuthDeduceRelationMap<ED extends EntityDict> = {
[T in keyof ED]?: keyof ED[T]['OpSchema'];
};