oak-domain/lib/store/checker.js

1066 lines
49 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

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

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createRemoveCheckers = exports.createAuthCheckers = exports.translateCheckerInSyncContext = exports.translateCheckerInAsyncContext = void 0;
var tslib_1 = require("tslib");
var assert_1 = tslib_1.__importDefault(require("assert"));
var filter_1 = require("../store/filter");
var Exception_1 = require("../types/Exception");
var types_1 = require("../types");
var actionDef_1 = require("./actionDef");
var string_1 = require("../utils/string");
var lodash_1 = require("../utils/lodash");
var relation_1 = require("./relation");
var uuid_1 = require("../utils/uuid");
function translateCheckerInAsyncContext(checker) {
var _this = this;
var entity = checker.entity, type = checker.type;
var when = 'before'; // 现在create的relation改成提前的expression检查了原先是先插入再后检查性能不行而且select也需要实现前检查
switch (type) {
case 'data': {
var checkerFn_1 = checker.checker;
var fn = (function (_a, context) {
var operation = _a.operation;
return tslib_1.__awaiter(_this, void 0, void 0, function () {
var data;
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
data = operation.data;
return [4 /*yield*/, checkerFn_1(data, context)];
case 1:
_b.sent();
return [2 /*return*/, 0];
}
});
});
});
return {
fn: fn,
when: when,
};
}
case 'row': {
var filter_2 = checker.filter, errMsg_1 = checker.errMsg, inconsistentRows_1 = checker.inconsistentRows;
var fn = (function (_a, context, option) {
var operation = _a.operation;
return tslib_1.__awaiter(_this, void 0, void 0, function () {
var operationFilter, action, filter2, _b, entity2, selection2, rows2, e, rows2, e;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
operationFilter = operation.filter, action = operation.action;
if (!(typeof filter_2 === 'function')) return [3 /*break*/, 2];
return [4 /*yield*/, filter_2(operation, context, option)];
case 1:
_b = _c.sent();
return [3 /*break*/, 3];
case 2:
_b = filter_2;
_c.label = 3;
case 3:
filter2 = _b;
if (!['select', 'count', 'stat'].includes(action)) return [3 /*break*/, 4];
operation.filter = (0, filter_1.addFilterSegment)(operationFilter || {}, filter2);
return [2 /*return*/, 0];
case 4: return [4 /*yield*/, (0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter || {}, true)];
case 5:
if (_c.sent()) {
return [2 /*return*/, 0];
}
if (!inconsistentRows_1) return [3 /*break*/, 7];
entity2 = inconsistentRows_1.entity, selection2 = inconsistentRows_1.selection;
return [4 /*yield*/, context.select(entity2, selection2(operationFilter), {
dontCollect: true,
blockTrigger: true,
})];
case 6:
rows2 = _c.sent();
e = new Exception_1.OakRowInconsistencyException(undefined, errMsg_1);
e.addData(entity2, rows2);
throw e;
case 7: return [4 /*yield*/, context.select(entity, {
data: (0, actionDef_1.getFullProjection)(entity, context.getSchema()),
filter: Object.assign({}, operationFilter, {
$not: filter2,
})
}, {
dontCollect: true,
blockTrigger: true,
})];
case 8:
rows2 = _c.sent();
e = new Exception_1.OakRowInconsistencyException(undefined, errMsg_1);
e.addData(entity, rows2);
throw e;
}
});
});
});
return {
fn: fn,
when: when,
};
}
case 'relation': {
var relationFilter_1 = checker.relationFilter, errMsg = checker.errMsg;
var fn = (function (_a, context, option) {
var operation = _a.operation;
return tslib_1.__awaiter(_this, void 0, void 0, function () {
var result, _b;
return tslib_1.__generator(this, function (_c) {
switch (_c.label) {
case 0:
if (context.isRoot()) {
return [2 /*return*/, 0];
}
if (!(typeof relationFilter_1 === 'function')) return [3 /*break*/, 2];
return [4 /*yield*/, relationFilter_1(operation, context, option)];
case 1:
_b = _c.sent();
return [3 /*break*/, 3];
case 2:
_b = relationFilter_1;
_c.label = 3;
case 3:
result = _b;
if (result) {
if (operation.action === 'create') {
console.warn("".concat(entity, "\u5BF9\u8C61\u7684create\u7C7B\u578B\u7684checker\u4E2D\uFF0C\u5B58\u5728\u65E0\u6CD5\u8F6C\u6362\u4E3A\u8868\u8FBE\u5F0F\u5F62\u5F0F\u7684\u60C5\u51B5\uFF0C\u8BF7\u5C3D\u91CF\u4F7F\u7528authDef\u683C\u5F0F\u5B9A\u4E49\u8FD9\u7C7Bchecker"));
}
else {
operation.filter = (0, filter_1.combineFilters)([operation.filter, result]);
}
}
return [2 /*return*/, 0];
}
});
});
});
return {
fn: fn,
when: when,
};
}
case 'logical':
case 'logicalRelation': {
var checkerFn_2 = checker.checker;
var fn = (function (_a, context, option) {
var operation = _a.operation;
return tslib_1.__awaiter(_this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_b) {
switch (_b.label) {
case 0:
if (context.isRoot() && type === 'logicalRelation') {
return [2 /*return*/, 0];
}
return [4 /*yield*/, checkerFn_2(operation, context, option)];
case 1:
_b.sent();
return [2 /*return*/, 0];
}
});
});
});
return {
fn: fn,
when: when,
};
}
default: {
(0, assert_1.default)(false);
}
}
}
exports.translateCheckerInAsyncContext = translateCheckerInAsyncContext;
function translateCheckerInSyncContext(checker) {
var entity = checker.entity, type = checker.type;
var when = 'before'; // 现在create的relation改成提前的expression检查了原先是先插入再后检查性能不行而且select也需要实现前检查
switch (type) {
case 'data': {
var checkerFn_3 = checker.checker;
var fn = function (operation, context) { return checkerFn_3(operation.data, context); };
return {
fn: fn,
when: when,
};
}
case 'row': {
var filter_3 = checker.filter, errMsg_2 = checker.errMsg;
var fn = function (operation, context, option) {
var operationFilter = operation.filter, action = operation.action;
var filter2 = typeof filter_3 === 'function' ? filter_3(operation, context, option) : filter_3;
(0, assert_1.default)(operationFilter);
if (['select', 'count', 'stat'].includes(action)) {
operation.filter = (0, filter_1.addFilterSegment)(operationFilter, filter2);
return 0;
}
else {
(0, assert_1.default)(!(filter2 instanceof Promise));
if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter, true)) {
return;
}
var e = new Exception_1.OakRowInconsistencyException(undefined, errMsg_2);
throw e;
}
};
return {
fn: fn,
when: when,
};
}
case 'relation': {
var relationFilter_2 = checker.relationFilter, errMsg_3 = checker.errMsg;
var fn = function (operation, context, option) {
if (context.isRoot()) {
return;
}
var result = typeof relationFilter_2 === 'function' ? relationFilter_2(operation, context, option) : relationFilter_2;
(0, assert_1.default)(!(result instanceof Promise));
if (result) {
var filter = operation.filter, action = operation.action;
if (action === 'create') {
console.warn("".concat(entity, "\u5BF9\u8C61\u7684create\u7C7B\u578B\u7684checker\u4E2D\uFF0C\u5B58\u5728\u65E0\u6CD5\u8F6C\u6362\u4E3A\u8868\u8FBE\u5F0F\u5F62\u5F0F\u7684\u60C5\u51B5\uFF0C\u8BF7\u5C3D\u91CF\u4F7F\u7528authDef\u683C\u5F0F\u5B9A\u4E49\u8FD9\u7C7Bchecker"));
return;
}
(0, assert_1.default)(filter);
if ((0, filter_1.checkFilterContains)(entity, context, result, filter, true)) {
return;
}
throw new Exception_1.OakUserUnpermittedException(errMsg_3);
}
};
return {
fn: fn,
when: when,
};
}
case 'logical':
case 'logicalRelation': {
var checkerFn_4 = checker.checker;
var fn = function (operation, context, option) {
if (context.isRoot() && type === 'logicalRelation') {
return;
}
checkerFn_4(operation, context, option);
};
return {
fn: fn,
when: when,
};
}
default: {
(0, assert_1.default)(false);
}
}
}
exports.translateCheckerInSyncContext = translateCheckerInSyncContext;
function translateCascadeRelationFilterMaker(schema, lch, entity2, pathPrefix) {
var cascadePath = lch.cascadePath, relations = lch.relations;
var paths = cascadePath ? cascadePath.split('.') : [];
if (pathPrefix) {
paths.unshift(pathPrefix);
}
var translateRelationFilter = function (entity) {
// 有两种情况此entity和user有Relation定义或是此entity已经指向user
if (entity === 'user') {
return function (userId) { return ({
id: userId,
}); };
}
else if (schema[entity].relation) {
if (relations) {
var diff = (0, lodash_1.difference)(relations, schema[entity].relation);
if (diff.length > 0) {
throw new Error("".concat(entity2, "\u4E0A\u67D0auth\u5B9A\u4E49\u7684relations\u4E2D\u542B\u6709\u4E0D\u53EF\u8BC6\u522B\u7684\u5173\u7CFB\u5B9A\u4E49").concat(diff.join(','), "\uFF0C \u8BF7\u4ED4\u7EC6\u68C0\u67E5"));
}
}
var relationEntityName_1 = "user".concat((0, string_1.firstLetterUpperCase)(entity));
return function (userId) {
var _a;
var filter = relations ? {
userId: userId,
relation: {
$in: relations,
},
} : {
userId: userId,
};
return {
id: {
$in: {
entity: relationEntityName_1,
data: (_a = {},
_a["".concat(entity, "Id")] = 1,
_a),
filter: filter,
},
},
};
};
}
else {
(0, assert_1.default)(false, "".concat(entity2, "\u4E0A\u67D0auth\u5B9A\u4E49\u7684cascadePath").concat(cascadePath, "\u4E0D\u80FD\u5B9A\u4F4D\u5230User\u5BF9\u8C61\u6216\u8005\u548CUser\u5173\u8054\u7684\u5173\u7CFB\u5BF9\u8C61\uFF0C \u8BF7\u4ED4\u7EC6\u68C0\u67E5"));
}
};
var translateFilterMakerIter = function (entity, iter) {
var relation = (0, relation_1.judgeRelation)(schema, entity, paths[iter]);
(0, assert_1.default)(relation === 2 || typeof relation === 'string');
if (iter === paths.length - 1) {
if (relation === 2) {
var filterMaker2_1 = translateRelationFilter(paths[iter]);
return function (userId) {
var filter = filterMaker2_1(userId);
(0, assert_1.default)(filter.id);
return {
entity: paths[iter],
entityId: filter.id,
};
};
}
var filterMaker2_2 = translateRelationFilter(relation);
return function (userId) {
var _a;
var filter = filterMaker2_2(userId);
(0, assert_1.default)(filter.id);
return _a = {},
_a["".concat(paths[iter], "Id")] = filter.id,
_a;
};
}
else {
var filterMaker_1 = relation === 2 ? translateFilterMakerIter(paths[iter], iter + 1) : translateFilterMakerIter(relation, iter + 1);
return function (userId) {
var _a;
return (_a = {},
_a[paths[iter]] = filterMaker_1(userId),
_a);
};
}
};
var filterMaker = paths.length ? translateFilterMakerIter(entity2, 0) : translateRelationFilter(entity2);
if (!paths.length) {
return function (oper, userId) { return filterMaker(userId); };
}
/**
* 针对第一层做一下特别优化比如对象A指向对象B多对一如果A的cascadePath是 'B'
* 当create A时会带有Bid。此时生成该B对象上的相关表达式查询返回可以避免必须将此判定在对象创建之后再做
* 另一使用场景是在查询A时如果带有Bid在对象跳一对多子对象场景下很常见可以提前判定这个查询对某些用户一定返回空集
*/
var _a = tslib_1.__read(paths, 1), attr = _a[0];
var relation = (0, relation_1.judgeRelation)(schema, entity2, attr);
(0, assert_1.default)(relation === 2 || typeof relation === 'string');
var filterMaker2 = paths.length > 1
? (relation === 2 ? translateFilterMakerIter(attr, 1) : translateFilterMakerIter(relation, 1))
: (relation === 2 ? translateRelationFilter(attr) : translateRelationFilter(relation));
return function (operation, userId) {
var action = operation.action;
if (action === 'create') {
var data = operation.data;
var getForeignKeyId_1 = function (d) {
if (relation === 2) {
if (d.entity === attr && typeof d.entityId === 'string') {
return d.entitId;
}
throw new Exception_1.OakUserUnpermittedException();
}
else {
(0, assert_1.default)(typeof relation === 'string');
if (typeof d["".concat(attr, "Id")] === 'string') {
return d["".concat(attr, "Id")];
}
throw new Exception_1.OakUserUnpermittedException();
}
};
if (relation === 2) {
if (data instanceof Array) {
var fkIds = (0, lodash_1.uniq)(data.map(function (d) { return getForeignKeyId_1(d); }));
return {
$entity: attr,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: { $in: fkIds } }),
$count: fkIds.length,
};
}
var fkId_1 = getForeignKeyId_1(data);
return {
$entity: attr,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: fkId_1 }),
};
}
(0, assert_1.default)(typeof relation === 'string');
if (data instanceof Array) {
var fkIds = (0, lodash_1.uniq)(data.map(function (d) { return getForeignKeyId_1(d); }));
return {
$entity: relation,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: { $in: fkIds } }),
$count: fkIds.length,
};
}
var fkId = getForeignKeyId_1(data);
return {
$entity: relation,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: fkId }),
};
}
var filter = operation.filter;
if (relation === 2 && (filter === null || filter === void 0 ? void 0 : filter.entity) === attr && (filter === null || filter === void 0 ? void 0 : filter.entityId)) {
if (typeof filter.entityId === 'string') {
return {
$entity: attr,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: filter.entityId }),
};
}
else if (filter.entityId.$in && filter.entityId.$in instanceof Array) {
var entityIds = (0, lodash_1.uniq)(filter.entityId.$in);
return {
$entity: relation,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: { $in: entityIds } }),
$count: entityIds.length,
};
}
}
else if (filter && filter["".concat(attr, "Id")]) {
if (typeof filter["".concat(attr, "Id")] === 'string') {
return {
$entity: attr,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: filter["".concat(attr, "Id")] }),
};
}
else if (filter["".concat(attr, "Id")].$in && filter["".concat(attr, "Id")].$in instanceof Array) {
var entityIds = (0, lodash_1.uniq)(filter["".concat(attr, "Id")].$in);
return {
$entity: relation,
$filter: (0, filter_1.addFilterSegment)(filterMaker2(userId), { id: { $in: entityIds } }),
$count: entityIds.length,
};
}
}
return filterMaker(userId);
};
}
function translateActionAuthFilterMaker(schema, relationItem, entity, pathPrefix) {
if (relationItem instanceof Array) {
var maker = relationItem.map(function (ele) {
if (ele instanceof Array) {
return ele.map(function (ele2) { return translateCascadeRelationFilterMaker(schema, ele2, entity, pathPrefix); });
}
return translateCascadeRelationFilterMaker(schema, ele, entity, pathPrefix);
});
return maker;
}
var filterMaker = translateCascadeRelationFilterMaker(schema, relationItem, entity, pathPrefix);
return filterMaker;
}
function makePotentialFilter(operation, context, filterMaker) {
var e_1, _a;
var userId = context.getCurrentUserId();
(0, assert_1.default)(userId);
var filters = filterMaker instanceof Array ? filterMaker.map(function (ele) {
if (ele instanceof Array) {
return ele.map(function (ele2) { return ele2(operation, userId); });
}
return ele(operation, userId);
}) : [filterMaker(operation, userId)];
/**
* 在下面的逻辑中如果某个maker返回的是$entity类型则检查是否有满足条件的项没有就要抛出异常有就返回undefined
* undefined项即意味着该条件通过
* 再加上and和or的布尔逻辑判断得到最终结果
* 还要考虑同步和异步……
* 代码比较复杂,因为原先没有$entity这种返回结果的设计
* by Xc 20130219
*/
var filtersOr = [];
var isAsyncOr = false;
var _loop_1 = function (f) {
var e_2, _b;
if (f instanceof Array) {
var isAsyncAnd = true;
var filtersAnd = [];
var _loop_2 = function (ff) {
if (ff === null || ff === void 0 ? void 0 : ff.$entity) {
var _e = ff, $entity = _e.$entity, $filter = _e.$filter, _f = _e.$count, $count_1 = _f === void 0 ? 1 : _f;
var count = context.count($entity, {
filter: $filter,
}, {});
if (count instanceof Promise) {
isAsyncAnd = true;
filtersAnd.push(count.then(function (c2) {
if (c2 >= $count_1) {
return undefined;
}
return new Exception_1.OakUserUnpermittedException();
}));
}
else {
filtersAnd.push(count >= $count_1 ? undefined : new Exception_1.OakUserUnpermittedException());
}
}
else if (ff) {
filtersAnd.push(ff);
}
};
try {
for (var f_1 = (e_2 = void 0, tslib_1.__values(f)), f_1_1 = f_1.next(); !f_1_1.done; f_1_1 = f_1.next()) {
var ff = f_1_1.value;
_loop_2(ff);
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (f_1_1 && !f_1_1.done && (_b = f_1.return)) _b.call(f_1);
}
finally { if (e_2) throw e_2.error; }
}
if (isAsyncAnd = true) {
isAsyncOr = true;
filtersOr.push(isAsyncAnd ? Promise.all(filtersAnd).then(function (fa) {
var e_3, _a;
var faR = [];
try {
for (var fa_1 = (e_3 = void 0, tslib_1.__values(fa)), fa_1_1 = fa_1.next(); !fa_1_1.done; fa_1_1 = fa_1.next()) {
var faItem = fa_1_1.value;
if (faItem instanceof Exception_1.OakUserUnpermittedException) {
return faItem;
}
else if (faItem) {
faR.push(faItem);
}
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (fa_1_1 && !fa_1_1.done && (_a = fa_1.return)) _a.call(fa_1);
}
finally { if (e_3) throw e_3.error; }
}
if (faR.length > 0) {
return {
$and: faR,
};
}
}) : {
$and: filtersAnd,
});
}
}
else {
if (f === null || f === void 0 ? void 0 : f.$entity) {
var _c = f, $entity = _c.$entity, $filter = _c.$filter, _d = _c.$count, $count_2 = _d === void 0 ? 1 : _d;
var count = context.count($entity, {
filter: $filter,
}, {});
if (count instanceof Promise) {
isAsyncOr = true;
filtersOr.push(count.then(function (c2) { return c2 >= $count_2 ? undefined : new Exception_1.OakUserUnpermittedException(); }));
}
else {
filtersOr.push(count >= $count_2 ? undefined : new Exception_1.OakUserUnpermittedException());
}
}
else if (f) {
filtersOr.push(f);
}
}
};
try {
for (var filters_1 = tslib_1.__values(filters), filters_1_1 = filters_1.next(); !filters_1_1.done; filters_1_1 = filters_1.next()) {
var f = filters_1_1.value;
_loop_1(f);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (filters_1_1 && !filters_1_1.done && (_a = filters_1.return)) _a.call(filters_1);
}
finally { if (e_1) throw e_1.error; }
}
// or的逻辑是有一个成功就直接通过
var returnOrFilters = function (filters) {
if (filters.length === 0 || filters.includes(undefined)) {
return undefined;
}
var foFilters = filters.filter(function (ele) { return ele !== undefined && !(ele instanceof Exception_1.OakUserUnpermittedException); });
if (foFilters.length > 0) {
return {
$or: foFilters,
};
}
throw new Exception_1.OakUserUnpermittedException();
};
if (isAsyncOr) {
return Promise.all(filtersOr)
.then(function (filters) { return returnOrFilters(filters); });
}
return returnOrFilters(filtersOr);
}
/**
* 根据权限定义创建出相应的checker
* @param schema
* @param authDict
* @returns
*/
function createAuthCheckers(schema, authDict) {
var checkers = [];
var _loop_3 = function (entity) {
var _a;
if (authDict[entity]) {
var _b = authDict[entity], relationAuth = _b.relationAuth, actionAuth = _b.actionAuth;
if (relationAuth) {
var raFilterMakerDict_1 = {};
var userEntityName = "user".concat((0, string_1.firstLetterUpperCase)(entity));
for (var r in relationAuth) {
Object.assign(raFilterMakerDict_1, (_a = {},
_a[r] = translateActionAuthFilterMaker(schema, relationAuth[r], userEntityName, entity),
_a));
}
var entityIdAttr_1 = "".concat(entity, "Id");
checkers.push({
entity: userEntityName,
action: 'create',
type: 'relation',
relationFilter: function (operation, context) {
var data = operation.data;
(0, assert_1.default)(!(data instanceof Array));
var _a = data, relation = _a.relation, _b = entityIdAttr_1, entityId = _a[_b];
if (!raFilterMakerDict_1[relation]) {
return;
}
var filter = makePotentialFilter(operation, context, raFilterMakerDict_1[relation]);
return filter;
},
errMsg: '越权操作',
});
checkers.push({
entity: userEntityName,
action: 'remove',
type: 'relation',
relationFilter: function (operation, context) {
// 目前过不去
return undefined;
/* const userId = context.getCurrentUserId();
const { filter } = operation as ED[keyof ED]['Remove'];
const makeFilterFromRows = (rows: Partial<ED[keyof ED]['Schema']>[]): SyncOrAsync<ED[keyof ED]['Selection']['filter']> => {
const relations = uniq(rows.map(ele => ele.relation));
const entityIds = uniq(rows.map(ele => ele[entityIdAttr]));
assert(entityIds.length === 1, `在回收${userEntityName}上权限时,单次回收涉及到了不同的对象,此操作不被允许`);
// const entityId = entityIds[0]!;
// 所有的relation条件要同时满足and关系注意这里的filter翻译出来是在entity对象上不是在userEntity对象上
const filtersAnd = relations.map(
(relation) => raFilterMakerDict[relation!]
).filter(
ele => !!ele
).map(
ele => makePotentialFilter(operation, context, ele)
);
if (filtersAnd.find(ele => ele instanceof Promise)) {
return Promise.all(filtersAnd).then(
(fa) => {
if (fa.length > 0) {
return {
$and: fa,
} as ED[keyof ED]['Selection']['filter'];
}
}
);
}
if (filtersAnd.length > 0) {
return {
$and: filtersAnd
} as ED[keyof ED]['Selection']['filter'];
}
};
const toBeRemoved = context.select(userEntityName, {
data: {
id: 1,
relation: 1,
[entityIdAttr]: 1,
},
filter,
}, { dontCollect: true });
if (toBeRemoved instanceof Promise) {
return toBeRemoved.then(
(rows) => makeFilterFromRows(rows)
);
}
return makeFilterFromRows(toBeRemoved); */
},
errMsg: '越权操作',
});
// 转让权限现在用update动作只允许update userId给其它人
// todo 等实现的时候再写
}
if (actionAuth) {
var _loop_4 = function (a) {
var filterMaker = translateActionAuthFilterMaker(schema, actionAuth[a], entity);
checkers.push({
entity: entity,
action: a,
type: 'relation',
relationFilter: function (operation, context) {
// const { filter } = operation;
var filter = makePotentialFilter(operation, context, filterMaker);
return filter;
},
errMsg: '定义的actionAuth中检查出来越权操作',
});
};
for (var a in actionAuth) {
_loop_4(a);
}
}
}
};
for (var entity in schema) {
_loop_3(entity);
}
return checkers;
}
exports.createAuthCheckers = createAuthCheckers;
/**
* 对对象的删除,检查其是否会产生其他行上的空指针,不允许这种情况的出现
* @param schema
* @returns
* 如果有的对象允许删除需要使用trigger来处理其相关联的外键对象这些trigger写作before则会在checker之前执行仍然可以删除成功
*/
function createRemoveCheckers(schema, authDict) {
var e_4, _a;
var checkers = [];
// 先建立所有的一对多的关系
var OneToManyMatrix = {};
var OneToManyOnEntityMatrix = {};
var addToMto = function (e, f, attr) {
var _a;
if (OneToManyMatrix[f]) {
(_a = OneToManyMatrix[f]) === null || _a === void 0 ? void 0 : _a.push([e, attr]);
}
else {
OneToManyMatrix[f] = [[e, attr]];
}
};
var addToMtoEntity = function (e, fs) {
var e_5, _a;
var _b;
try {
for (var fs_1 = tslib_1.__values(fs), fs_1_1 = fs_1.next(); !fs_1_1.done; fs_1_1 = fs_1.next()) {
var f = fs_1_1.value;
if (!OneToManyOnEntityMatrix[f]) {
OneToManyOnEntityMatrix[f] = [e];
}
else {
(_b = OneToManyOnEntityMatrix[f]) === null || _b === void 0 ? void 0 : _b.push(e);
}
}
}
catch (e_5_1) { e_5 = { error: e_5_1 }; }
finally {
try {
if (fs_1_1 && !fs_1_1.done && (_a = fs_1.return)) _a.call(fs_1);
}
finally { if (e_5) throw e_5.error; }
}
};
for (var entity in schema) {
if (['operEntity', 'modiEntity', 'userEntityGrant'].includes(entity)) {
continue; // 系统功能性数据,不用处理
}
var attributes = schema[entity].attributes;
for (var attr in attributes) {
if (attributes[attr].type === 'ref') {
addToMto(entity, attributes[attr].ref, attr);
}
else if (attr === 'entity') {
if (attributes[attr].ref) {
addToMtoEntity(entity, attributes[attr].ref);
}
else if (process.env.NODE_ENV === 'development') {
console.warn("".concat(entity, "\u7684entity\u53CD\u6307\u6307\u9488\u627E\u4E0D\u5230\u6709\u6548\u7684\u5BF9\u8C61"));
}
}
}
}
// 当删除一时,要确认多上面没有指向一的数据
var entities = (0, lodash_1.union)(Object.keys(OneToManyMatrix), Object.keys(OneToManyOnEntityMatrix));
var _loop_5 = function (entity) {
checkers.push({
entity: entity,
action: 'remove',
type: 'logical',
checker: function (operation, context, option) {
var e_6, _a, e_7, _b;
var promises = [];
if (OneToManyMatrix[entity]) {
var _loop_7 = function (otm) {
var _g, _h;
var _j = tslib_1.__read(otm, 2), e = _j[0], attr = _j[1];
var proj = (_g = {
id: 1
},
_g[attr] = 1,
_g);
var filter = operation.filter && (_h = {},
_h[attr.slice(0, attr.length - 2)] = operation.filter,
_h);
var result = context.select(e, {
data: proj,
filter: filter,
indexFrom: 0,
count: 1
}, { dontCollect: true });
if (result instanceof Promise) {
promises.push(result.then(function (_a) {
var _b = tslib_1.__read(_a, 1), row = _b[0];
if (row) {
var err = new Exception_1.OakRowInconsistencyException(undefined, "\u60A8\u65E0\u6CD5\u5220\u9664\u5B58\u5728\u6709\u6548\u6570\u636E\u300C".concat(e, "\u300D\u5173\u8054\u7684\u884C"));
err.addData(e, [row]);
throw err;
}
}));
}
else {
var _k = tslib_1.__read(result, 1), row = _k[0];
if (row) {
var err = new Exception_1.OakRowInconsistencyException(undefined, "\u60A8\u65E0\u6CD5\u5220\u9664\u5B58\u5728\u6709\u6548\u6570\u636E\u300C".concat(e, "\u300D\u5173\u8054\u7684\u884C"));
err.addData(e, [row]);
throw err;
}
}
};
try {
for (var _c = (e_6 = void 0, tslib_1.__values(OneToManyMatrix[entity])), _d = _c.next(); !_d.done; _d = _c.next()) {
var otm = _d.value;
_loop_7(otm);
}
}
catch (e_6_1) { e_6 = { error: e_6_1 }; }
finally {
try {
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
}
finally { if (e_6) throw e_6.error; }
}
}
if (OneToManyOnEntityMatrix[entity]) {
var _loop_8 = function (otm) {
var _l, _m, _o;
var proj = {
id: 1,
entity: 1,
entityId: 1,
};
var filter = operation.filter && (_l = {},
_l[entity] = operation.filter,
_l);
var result = context.select(otm, {
data: proj,
filter: filter,
indexFrom: 0,
count: 1
}, { dontCollect: true });
if (result instanceof Promise) {
promises.push(result.then(function (_a) {
var _b = tslib_1.__read(_a, 1), row = _b[0];
if (row) {
var e = new Exception_1.OakRowInconsistencyException(undefined, "\u60A8\u65E0\u6CD5\u5220\u9664\u5B58\u5728\u6709\u6548\u6570\u636E\u300C".concat(otm, "\u300D\u5173\u8054\u7684\u884C"));
e.addData(otm, [row]);
throw e;
}
}));
}
else {
var _p = tslib_1.__read(result, 1), row = _p[0];
if (row) {
var record = {
a: 's',
d: (_m = {},
_m[otm] = (_o = {},
_o[row.id] = row,
_o),
_m)
};
var e = new Exception_1.OakRowInconsistencyException(undefined, "\u60A8\u65E0\u6CD5\u5220\u9664\u5B58\u5728\u6709\u6548\u6570\u636E\u300C".concat(otm, "\u300D\u5173\u8054\u7684\u884C"));
e.addData(otm, [row]);
throw e;
}
}
};
try {
for (var _e = (e_7 = void 0, tslib_1.__values(OneToManyOnEntityMatrix[entity])), _f = _e.next(); !_f.done; _f = _e.next()) {
var otm = _f.value;
_loop_8(otm);
}
}
catch (e_7_1) { e_7 = { error: e_7_1 }; }
finally {
try {
if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
}
finally { if (e_7) throw e_7.error; }
}
}
if (promises.length > 0) {
return Promise.all(promises).then(function () { return undefined; });
}
}
});
};
try {
for (var entities_1 = tslib_1.__values(entities), entities_1_1 = entities_1.next(); !entities_1_1.done; entities_1_1 = entities_1.next()) {
var entity = entities_1_1.value;
_loop_5(entity);
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (entities_1_1 && !entities_1_1.done && (_a = entities_1.return)) _a.call(entities_1);
}
finally { if (e_4) throw e_4.error; }
}
var _loop_6 = function (entity) {
var e_8, _b;
var cascadeRemove = authDict[entity].cascadeRemove;
if (cascadeRemove) {
var entitiesOnEntityAttr = [];
var hasAllEntity = false;
var _loop_9 = function (attr) {
if (attr === '@entity') {
hasAllEntity = true;
return "continue";
}
var rel = (0, relation_1.judgeRelation)(schema, entity, attr);
if (rel === 2) {
entitiesOnEntityAttr.push(attr);
checkers.push({
entity: attr,
action: 'remove',
type: 'logical',
priority: types_1.REMOVE_CASCADE_PRIORITY,
checker: function (operation, context) {
var _a, _b;
var filter = operation.filter;
if (cascadeRemove[attr] === 'remove') {
return context.operate(entity, {
id: (0, uuid_1.generateNewId)(),
action: 'remove',
data: {},
filter: filter ? (_a = {},
_a[attr] = filter,
_a) : undefined,
}, { dontCollect: true });
}
return context.operate(entity, {
id: (0, uuid_1.generateNewId)(),
action: 'update',
data: {
entity: null,
entityId: null,
},
filter: filter ? (_b = {},
_b[attr] = filter,
_b) : undefined,
}, { dontCollect: true });
}
});
}
else {
(0, assert_1.default)(typeof rel === 'string');
checkers.push({
entity: rel,
action: 'remove',
type: 'logical',
priority: types_1.REMOVE_CASCADE_PRIORITY,
checker: function (operation, context) {
var _a, _b, _c;
var filter = operation.filter;
if (cascadeRemove[attr] === 'remove') {
return context.operate(entity, {
id: (0, uuid_1.generateNewId)(),
action: 'remove',
data: {},
filter: filter ? (_a = {},
_a[attr] = filter,
_a) : undefined,
}, { dontCollect: true });
}
return context.operate(entity, {
id: (0, uuid_1.generateNewId)(),
action: 'update',
data: (_b = {},
_b["".concat(attr, "Id")] = null,
_b),
filter: filter ? (_c = {},
_c[attr] = filter,
_c) : undefined,
}, { dontCollect: true });
}
});
}
};
for (var attr in cascadeRemove) {
_loop_9(attr);
}
if (hasAllEntity) {
var attributes = schema[entity].attributes;
var ref = attributes.entity.ref;
var restEntities = (0, lodash_1.difference)(ref, entitiesOnEntityAttr);
var _loop_10 = function (e) {
checkers.push({
entity: e,
action: 'remove',
type: 'logical',
priority: types_1.REMOVE_CASCADE_PRIORITY,
checker: function (operation, context) {
var _a, _b;
var filter = operation.filter;
if (cascadeRemove['@entity'] === 'remove') {
return context.operate(entity, {
id: (0, uuid_1.generateNewId)(),
action: 'remove',
data: {},
filter: filter ? (_a = {},
_a[e] = filter,
_a) : undefined,
}, { dontCollect: true });
}
return context.operate(entity, {
id: (0, uuid_1.generateNewId)(),
action: 'update',
data: {
entity: null,
entityId: null,
},
filter: filter ? (_b = {},
_b[e] = filter,
_b) : undefined,
}, { dontCollect: true });
}
});
};
try {
for (var restEntities_1 = (e_8 = void 0, tslib_1.__values(restEntities)), restEntities_1_1 = restEntities_1.next(); !restEntities_1_1.done; restEntities_1_1 = restEntities_1.next()) {
var e = restEntities_1_1.value;
_loop_10(e);
}
}
catch (e_8_1) { e_8 = { error: e_8_1 }; }
finally {
try {
if (restEntities_1_1 && !restEntities_1_1.done && (_b = restEntities_1.return)) _b.call(restEntities_1);
}
finally { if (e_8) throw e_8.error; }
}
}
}
};
// 注入声明的cascade删除时的外键处理动作
for (var entity in authDict) {
_loop_6(entity);
}
return checkers;
}
exports.createRemoveCheckers = createRemoveCheckers;