diff --git a/lib/store/TriggerExecutor.js b/lib/store/TriggerExecutor.js index 2ad37ef..c6a7e8f 100644 --- a/lib/store/TriggerExecutor.js +++ b/lib/store/TriggerExecutor.js @@ -33,7 +33,7 @@ var TriggerExecutor = /** @class */ (function () { TriggerExecutor.prototype.registerChecker = function (checker) { var entity = checker.entity, action = checker.action, type = checker.type, conditionalFilter = checker.conditionalFilter; var triggerName = "".concat(String(entity)).concat(action, "\u6743\u9650\u68C0\u67E5-").concat(this.counter++); - var _a = (0, checker_1.translateCheckerInAsyncContext)(checker), fn = _a.fn, when = _a.when; + var _a = (0, checker_1.translateCheckerInAsyncContext)(checker, true), fn = _a.fn, when = _a.when; var priority = type === 'data' ? Trigger_1.DATA_CHECKER_DEFAULT_PRIORITY : Trigger_1.CHECKER_DEFAULT_PRIORITY; // checker的默认优先级最低(前面的trigger可能会赋上一些相应的值) var trigger = { checkerType: type, diff --git a/lib/store/checker.d.ts b/lib/store/checker.d.ts index f385b1b..71791d7 100644 --- a/lib/store/checker.d.ts +++ b/lib/store/checker.d.ts @@ -2,7 +2,13 @@ import { AuthDefDict, Checker, EntityDict, OperateOption, SelectOption, StorageS import { EntityDict as BaseEntityDict } from '../base-app-domain'; import { AsyncContext } from "./AsyncRowStore"; import { SyncContext } from './SyncRowStore'; -export declare function translateCheckerInAsyncContext>(checker: Checker): { +/** + * + * @param checker 要翻译的checker + * @param silent 如果silent,则row和relation类型的checker只会把限制条件加到查询上,而不报错(除掉create动作) + * @returns + */ +export declare function translateCheckerInAsyncContext>(checker: Checker, silent?: boolean): { fn: Trigger['fn']; when: 'before' | 'after'; }; diff --git a/lib/store/checker.js b/lib/store/checker.js index 82716cf..957b8ff 100644 --- a/lib/store/checker.js +++ b/lib/store/checker.js @@ -11,7 +11,13 @@ 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) { +/** + * + * @param checker 要翻译的checker + * @param silent 如果silent,则row和relation类型的checker只会把限制条件加到查询上,而不报错(除掉create动作) + * @returns + */ +function translateCheckerInAsyncContext(checker, silent) { var _this = this; var entity = checker.entity, type = checker.type; var when = 'before'; // 现在create的relation改成提前的expression检查了,原先是先插入再后检查,性能不行,而且select也需要实现前检查 @@ -59,7 +65,7 @@ function translateCheckerInAsyncContext(checker) { _c.label = 3; case 3: filter2 = _b; - if (!['select', 'count', 'stat'].includes(action)) return [3 /*break*/, 4]; + if (!silent) 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)]; @@ -102,11 +108,11 @@ function translateCheckerInAsyncContext(checker) { }; } case 'relation': { - var relationFilter_1 = checker.relationFilter, errMsg = checker.errMsg; + var relationFilter_1 = checker.relationFilter, errMsg_2 = 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; + var result, _b, filter, action; return tslib_1.__generator(this, function (_c) { switch (_c.label) { case 0: @@ -123,15 +129,24 @@ function translateCheckerInAsyncContext(checker) { _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]); - } + if (!result) return [3 /*break*/, 5]; + 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 [2 /*return*/, 0]; } - return [2 /*return*/, 0]; + if (silent) { + operation.filter = (0, filter_1.addFilterSegment)(filter || {}, result); + return [2 /*return*/, 0]; + } + (0, assert_1.default)(filter); + return [4 /*yield*/, (0, filter_1.checkFilterContains)(entity, context, result, filter, true)]; + case 4: + if (_c.sent()) { + return [2 /*return*/]; + } + throw new Exception_1.OakUserUnpermittedException(errMsg_2); + case 5: return [2 /*return*/, 0]; } }); }); @@ -185,23 +200,17 @@ function translateCheckerInSyncContext(checker) { }; } case 'row': { - var filter_3 = checker.filter, errMsg_2 = checker.errMsg; + var filter_3 = checker.filter, errMsg_3 = 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; + (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_3); + throw e; }; return { fn: fn, @@ -209,7 +218,7 @@ function translateCheckerInSyncContext(checker) { }; } case 'relation': { - var relationFilter_2 = checker.relationFilter, errMsg_3 = checker.errMsg; + var relationFilter_2 = checker.relationFilter, errMsg_4 = checker.errMsg; var fn = function (operation, context, option) { if (context.isRoot()) { return; @@ -226,7 +235,7 @@ function translateCheckerInSyncContext(checker) { if ((0, filter_1.checkFilterContains)(entity, context, result, filter, true)) { return; } - throw new Exception_1.OakUserUnpermittedException(errMsg_3); + throw new Exception_1.OakUserUnpermittedException(errMsg_4); } }; return { diff --git a/lib/store/filter.d.ts b/lib/store/filter.d.ts index 6f7c213..4ae7028 100644 --- a/lib/store/filter.d.ts +++ b/lib/store/filter.d.ts @@ -107,3 +107,4 @@ export declare function makeTreeDescendantFilter | AsyncContext>(entity: T, context: Cxt, contained: ED[T]['Selection']['filter'], filter?: ED[T]['Selection']['filter'], dataCompare?: true): boolean | Promise; export declare function checkFilterRepel | AsyncContext>(entity: T, context: Cxt, filter1: ED[T]['Selection']['filter'], filter2: ED[T]['Selection']['filter'], dataCompare?: true): boolean | Promise; +export declare function getCascadeEntityFilter(filter: NonNullable, attr: keyof NonNullable): ED[keyof ED]['Selection']['filter']; diff --git a/lib/store/filter.js b/lib/store/filter.js index e903de7..afe3793 100644 --- a/lib/store/filter.js +++ b/lib/store/filter.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.checkFilterRepel = exports.checkFilterContains = exports.makeTreeDescendantFilter = exports.makeTreeAncestorFilter = exports.same = exports.getRelevantIds = exports.repel = exports.contains = exports.judgeValueRelation = exports.combineFilters = exports.unionFilterSegment = exports.addFilterSegment = void 0; +exports.getCascadeEntityFilter = exports.checkFilterRepel = exports.checkFilterContains = exports.makeTreeDescendantFilter = exports.makeTreeAncestorFilter = exports.same = exports.getRelevantIds = exports.repel = exports.contains = exports.judgeValueRelation = exports.combineFilters = exports.unionFilterSegment = exports.addFilterSegment = void 0; var tslib_1 = require("tslib"); var assert_1 = tslib_1.__importDefault(require("assert")); var types_1 = require("../types"); @@ -845,6 +845,7 @@ function checkFilterContains(entity, context, contained, filter, dataCompare) { }]); var count = context.count(entity, { filter: filter2, + count: 1, }, { dontCollect: true, blockTrigger: true, @@ -883,3 +884,22 @@ function checkFilterRepel(entity, context, filter1, filter2, dataCompare) { return false; } exports.checkFilterRepel = checkFilterRepel; +function getCascadeEntityFilter(filter, attr) { + var filters = []; + if (filter[attr]) { + (0, assert_1.default)(typeof filter[attr] === 'object'); + filters.push(filter[attr]); + } + if (filter.$and) { + filter.$and.forEach(function (ele) { + var f2 = getCascadeEntityFilter(ele, attr); + if (f2) { + filters.push(f2); + } + }); + } + if (filters.length > 0) { + return combineFilters(filters); + } +} +exports.getCascadeEntityFilter = getCascadeEntityFilter; diff --git a/package.json b/package.json index 17a400b..3e068e3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oak-domain", - "version": "2.6.5", + "version": "2.6.6", "author": { "name": "XuChang" }, diff --git a/src/store/TriggerExecutor.ts b/src/store/TriggerExecutor.ts index 3b7c726..c7888c2 100644 --- a/src/store/TriggerExecutor.ts +++ b/src/store/TriggerExecutor.ts @@ -49,7 +49,7 @@ export class TriggerExecutor { registerChecker>(checker: Checker): void { const { entity, action, type, conditionalFilter } = checker; const triggerName = `${String(entity)}${action}权限检查-${this.counter++}`; - const { fn, when } = translateCheckerInAsyncContext(checker); + const { fn, when } = translateCheckerInAsyncContext(checker, true); const priority = type === 'data' ? DATA_CHECKER_DEFAULT_PRIORITY : CHECKER_DEFAULT_PRIORITY; // checker的默认优先级最低(前面的trigger可能会赋上一些相应的值) const trigger = { checkerType: type, diff --git a/src/store/checker.ts b/src/store/checker.ts index e36a5c4..2b30d91 100644 --- a/src/store/checker.ts +++ b/src/store/checker.ts @@ -14,11 +14,17 @@ import { union, uniq, difference } from '../utils/lodash'; import { judgeRelation } from './relation'; import { generateNewId } from '../utils/uuid'; +/** + * + * @param checker 要翻译的checker + * @param silent 如果silent,则row和relation类型的checker只会把限制条件加到查询上,而不报错(除掉create动作) + * @returns + */ export function translateCheckerInAsyncContext< ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends AsyncContext ->(checker: Checker): { +>(checker: Checker, silent?: boolean): { fn: Trigger['fn']; when: 'before' | 'after'; } { @@ -42,7 +48,7 @@ export function translateCheckerInAsyncContext< const fn = (async ({ operation }, context, option) => { const { filter: operationFilter, action } = operation; const filter2 = typeof filter === 'function' ? await (filter as Function)(operation, context, option) : filter; - if (['select', 'count', 'stat'].includes(action)) { + if (silent) { operation.filter = addFilterSegment(operationFilter || {}, filter2); return 0; } @@ -95,12 +101,20 @@ export function translateCheckerInAsyncContext< const result = typeof relationFilter === 'function' ? await relationFilter(operation, context, option) : relationFilter; if (result) { - if (operation.action === 'create') { + const { filter, action } = operation; + if (action === 'create') { console.warn(`${entity as string}对象的create类型的checker中,存在无法转换为表达式形式的情况,请尽量使用authDef格式定义这类checker`); + return 0; } - else { - operation.filter = combineFilters([operation.filter, result as ED[T]['Selection']['filter']]); + if (silent) { + operation.filter = addFilterSegment(filter || {}, result); + return 0; } + assert(filter); + if (await checkFilterContains(entity, context, result, filter, true)) { + return; + } + throw new OakUserUnpermittedException(errMsg); } return 0; }) as UpdateTriggerInTxn['fn']; @@ -155,18 +169,12 @@ export function translateCheckerInSyncContext< const { filter: operationFilter, action } = operation; const filter2 = typeof filter === 'function' ? (filter as Function)(operation, context, option) : filter; assert(operationFilter); - if (['select', 'count', 'stat'].includes(action)) { - operation.filter = addFilterSegment(operationFilter, filter2); - return 0; - } - else { - assert(!(filter2 instanceof Promise)); - if (checkFilterContains(entity, context, filter2, operationFilter, true)) { - return; - } - const e = new OakRowInconsistencyException(undefined, errMsg); - throw e; + assert(!(filter2 instanceof Promise)); + if (checkFilterContains(entity, context, filter2, operationFilter, true)) { + return; } + const e = new OakRowInconsistencyException(undefined, errMsg); + throw e; }; return { fn, diff --git a/src/store/filter.ts b/src/store/filter.ts index 7750bf8..1b5c9d7 100644 --- a/src/store/filter.ts +++ b/src/store/filter.ts @@ -901,6 +901,7 @@ export function checkFilterContains( + filter: NonNullable, + attr: keyof NonNullable +): ED[keyof ED]['Selection']['filter'] { + const filters: ED[keyof ED]['Selection']['filter'][] = []; + if (filter![attr]) { + assert(typeof filter![attr] === 'object'); + filters.push(filter![attr]); + } + if (filter.$and) { + filter.$and.forEach( + (ele: NonNullable) => { + const f2 = getCascadeEntityFilter(ele, attr); + if (f2) { + filters.push(f2) + } + } + ); + } + if (filters.length > 0) { + return combineFilters(filters); + } } \ No newline at end of file