From 3916971d384aa2122ec683c47b27568d708398cc Mon Sep 17 00:00:00 2001 From: Xc Date: Thu, 12 Jan 2023 20:09:33 +0800 Subject: [PATCH 01/19] 2.3.3-dev --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ec44077..e692dd8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oak-domain", - "version": "2.3.2", + "version": "2.3.3", "author": { "name": "XuChang" }, From 127a84bff07518100a548a3602e69458021927c4 Mon Sep 17 00:00:00 2001 From: Xc Date: Thu, 12 Jan 2023 21:40:56 +0800 Subject: [PATCH 02/19] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86concat?= =?UTF-8?q?=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/types/Expression.d.ts | 7 ++++++- lib/types/Expression.js | 18 ++++++++++++++++-- src/types/Expression.ts | 29 +++++++++++++++++++++++++++-- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/lib/types/Expression.d.ts b/lib/types/Expression.d.ts index a76c16f..7cc62ef 100644 --- a/lib/types/Expression.d.ts +++ b/lib/types/Expression.d.ts @@ -111,6 +111,10 @@ interface DateFloor { $dateFloor: [RefOrExpression | Date | number, 'y' | 'M' | 'd' | 'h' | 'm' | 's']; } declare type DateExpression = DateYear | DateMonth | DateWeekday | DateWeekOfYear | DateDay | DateDayOfYear | DateDayOfMonth | DateDayOfWeek | DateDiff | DateCeiling | DateFloor; +interface StringConcat { + $concat: StringType[]; +} +declare type StringExpression = StringConcat; interface GeoContains { $contains: [RefOrExpression | Geo, RefOrExpression | Geo]; } @@ -118,7 +122,7 @@ interface GeoDistance { $distance: [RefOrExpression | Geo, RefOrExpression | Geo]; } declare type GeoExpression = GeoContains | GeoDistance; -export declare type Expression = GeoExpression | DateExpression | LogicExpression | BoolExpression | CompareExpression | MathExpression; +export declare type Expression = GeoExpression | DateExpression | LogicExpression | BoolExpression | CompareExpression | MathExpression | StringExpression; export declare type ExpressionConstant = Geo | number | Date | string | boolean; export declare function isGeoExpression(expression: any): expression is GeoExpression; export declare function isDateExpression(expression: any): expression is DateExpression; @@ -126,6 +130,7 @@ export declare function isLogicExpression(expression: any): expression is Log export declare function isBoolExpression(expression: any): expression is BoolExpression; export declare function isCompareExpression(expression: any): expression is CompareExpression; export declare function isMathExpression(expression: any): expression is MathExpression; +export declare function isStringExpression(expression: any): expression is StringExpression; export declare function isExpression(expression: any): expression is Expression; export declare function opMultipleParams(op: string): boolean; export declare function execOp(op: string, params: any, obscure?: boolean): ExpressionConstant; diff --git a/lib/types/Expression.js b/lib/types/Expression.js index ade7d9f..96fc684 100644 --- a/lib/types/Expression.js +++ b/lib/types/Expression.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.getAttrRefInExpression = exports.execOp = exports.opMultipleParams = exports.isExpression = exports.isMathExpression = exports.isCompareExpression = exports.isBoolExpression = exports.isLogicExpression = exports.isDateExpression = exports.isGeoExpression = void 0; +exports.getAttrRefInExpression = exports.execOp = exports.opMultipleParams = exports.isExpression = exports.isStringExpression = exports.isMathExpression = exports.isCompareExpression = exports.isBoolExpression = exports.isLogicExpression = exports.isDateExpression = exports.isGeoExpression = void 0; var tslib_1 = require("tslib"); var assert_1 = tslib_1.__importDefault(require("assert")); var dayjs_1 = tslib_1.__importDefault(require("dayjs")); @@ -105,13 +105,24 @@ function isMathExpression(expression) { return false; } exports.isMathExpression = isMathExpression; +function isStringExpression(expression) { + if (Object.keys(expression).length == 1) { + var op = Object.keys(expression)[0]; + if (['$concat'].includes(op)) { + return true; + } + } + return false; +} +exports.isStringExpression = isStringExpression; function isExpression(expression) { return typeof expression === 'object' && Object.keys(expression).length === 1 && Object.keys(expression)[0].startsWith('$'); } exports.isExpression = isExpression; function opMultipleParams(op) { return !['$year', '$month', '$weekday', '$weekOfYear', '$day', '$dayOfMonth', - '$dayOfWeek', '$dayOfYear', '$not', '$true', '$false', '$abs', '$round', '$floor', '$ceil'].includes(op); + '$dayOfWeek', '$dayOfYear', '$not', '$true', '$false', '$abs', + '$round', '$floor', '$ceil', '$concat'].includes(op); } exports.opMultipleParams = opMultipleParams; function execOp(op, params, obscure) { @@ -341,6 +352,9 @@ function execOp(op, params, obscure) { case '$contains': { throw new Error('$contains类型未实现'); } + case '$concat': { + return params.join(''); + } default: { (0, assert_1.default)(false, "\u4E0D\u80FD\u8BC6\u522B\u7684expression\u8FD0\u7B97\u7B26\uFF1A".concat(op)); } diff --git a/src/types/Expression.ts b/src/types/Expression.ts index 1657d80..3ee3c86 100644 --- a/src/types/Expression.ts +++ b/src/types/Expression.ts @@ -135,6 +135,15 @@ interface DateFloor { type DateExpression = DateYear | DateMonth | DateWeekday | DateWeekOfYear | DateDay | DateDayOfYear | DateDayOfMonth | DateDayOfWeek | DateDiff | DateCeiling | DateFloor; +// String +interface StringConcat { + $concat: StringType[]; +} + +type StringExpression = StringConcat; + + + //// Geo interface GeoContains { $contains: [RefOrExpression | Geo, RefOrExpression | Geo]; @@ -145,7 +154,8 @@ interface GeoDistance { type GeoExpression = GeoContains | GeoDistance; -export type Expression = GeoExpression | DateExpression | LogicExpression | BoolExpression | CompareExpression | MathExpression; +export type Expression = GeoExpression | DateExpression | LogicExpression + | BoolExpression | CompareExpression | MathExpression | StringExpression; export type ExpressionConstant = Geo | number | Date | string | boolean; @@ -212,13 +222,25 @@ export function isMathExpression(expression: any): expression is MathExpressi return false; } + +export function isStringExpression(expression: any): expression is StringExpression { + if (Object.keys(expression).length == 1) { + const op = Object.keys(expression)[0]; + if (['$concat'].includes(op)) { + return true; + } + } + return false; +} + export function isExpression(expression: any): expression is Expression { return typeof expression === 'object' && Object.keys(expression).length === 1 && Object.keys(expression)[0].startsWith('$'); } export function opMultipleParams(op: string) { return !['$year', '$month', '$weekday', '$weekOfYear', '$day', '$dayOfMonth', - '$dayOfWeek', '$dayOfYear', '$not', '$true', '$false', '$abs', '$round', '$floor', '$ceil'].includes(op); + '$dayOfWeek', '$dayOfYear', '$not', '$true', '$false', '$abs', + '$round', '$floor', '$ceil', '$concat'].includes(op); } export function execOp(op: string, params: any, obscure?: boolean): ExpressionConstant { @@ -435,6 +457,9 @@ export function execOp(op: string, params: any, obscure?: boolean): ExpressionCo case '$contains': { throw new Error('$contains类型未实现'); } + case '$concat': { + return params.join(''); + } default: { assert(false, `不能识别的expression运算符:${op}`); } From 5794efe2c6ff2496afd735cc020fbda44270cbf9 Mon Sep 17 00:00:00 2001 From: Xc Date: Thu, 12 Jan 2023 22:25:58 +0800 Subject: [PATCH 03/19] =?UTF-8?q?=E6=9C=89=E4=B8=AA=E5=B0=8F=E7=AC=94?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/types/Expression.js | 2 +- src/types/Expression.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/types/Expression.js b/lib/types/Expression.js index 96fc684..463f906 100644 --- a/lib/types/Expression.js +++ b/lib/types/Expression.js @@ -122,7 +122,7 @@ exports.isExpression = isExpression; function opMultipleParams(op) { return !['$year', '$month', '$weekday', '$weekOfYear', '$day', '$dayOfMonth', '$dayOfWeek', '$dayOfYear', '$not', '$true', '$false', '$abs', - '$round', '$floor', '$ceil', '$concat'].includes(op); + '$round', '$floor', '$ceil'].includes(op); } exports.opMultipleParams = opMultipleParams; function execOp(op, params, obscure) { diff --git a/src/types/Expression.ts b/src/types/Expression.ts index 3ee3c86..654f35e 100644 --- a/src/types/Expression.ts +++ b/src/types/Expression.ts @@ -240,7 +240,7 @@ export function isExpression(expression: any): expression is Expression { export function opMultipleParams(op: string) { return !['$year', '$month', '$weekday', '$weekOfYear', '$day', '$dayOfMonth', '$dayOfWeek', '$dayOfYear', '$not', '$true', '$false', '$abs', - '$round', '$floor', '$ceil', '$concat'].includes(op); + '$round', '$floor', '$ceil'].includes(op); } export function execOp(op: string, params: any, obscure?: boolean): ExpressionConstant { From c65d4ade3197d20c4e3157d6ec800357a8747e3f Mon Sep 17 00:00:00 2001 From: "Xc@centOs" Date: Fri, 13 Jan 2023 01:32:30 +0800 Subject: [PATCH 04/19] =?UTF-8?q?modi=E5=9C=A8abandon=E6=97=B6=E5=A4=9A?= =?UTF-8?q?=E4=BD=99=E7=9A=84filter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/store/modi.js | 8 -------- lib/types/Expression.d.ts | 2 +- src/store/modi.ts | 4 ++-- src/types/Expression.ts | 2 +- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/lib/store/modi.js b/lib/store/modi.js index 4dc3d91..3cc1f0a 100644 --- a/lib/store/modi.js +++ b/lib/store/modi.js @@ -58,14 +58,6 @@ function abandonModis(filter, context, option) { _d.action = 'abandon', _d.data = {}, _d.filter = filter, - _d.sorter = [ - { - $attr: { - $$createAt$$: 1, - }, - $direction: 'asc', - } - ], _d), Object.assign({}, option, { blockTrigger: false, })]))]; diff --git a/lib/types/Expression.d.ts b/lib/types/Expression.d.ts index 7cc62ef..8cf41b3 100644 --- a/lib/types/Expression.d.ts +++ b/lib/types/Expression.d.ts @@ -4,7 +4,7 @@ export declare type RefOrExpression = RefAttr | Expression; declare type MathType = RefOrExpression | number; declare type StringType = RefOrExpression | string; interface Add { - $add: (MathType | StringType)[]; + $add: (MathType)[]; } interface Subtract { $subtract: [MathType, MathType]; diff --git a/src/store/modi.ts b/src/store/modi.ts index 4a39e25..a2ac21d 100644 --- a/src/store/modi.ts +++ b/src/store/modi.ts @@ -52,14 +52,14 @@ export async function abandonModis = RefAttr | Expression; type MathType = RefOrExpression | number; type StringType = RefOrExpression | string interface Add { - $add: (MathType | StringType)[]; + $add: (MathType)[]; }; interface Subtract { $subtract: [MathType, MathType]; From b617706cec8a9eef82e9b9ec9bcdf44fea5ef0cb Mon Sep 17 00:00:00 2001 From: "Xc@centOs" Date: Sun, 15 Jan 2023 12:43:20 +0800 Subject: [PATCH 05/19] =?UTF-8?q?=E6=94=B9=E9=80=A0=E4=BA=86trigger?= =?UTF-8?q?=E5=92=8Cauth=E4=B8=AD=E7=9A=84conditionalFilter,=E5=85=81?= =?UTF-8?q?=E8=AE=B8=E8=BF=94=E5=9B=9Epromise?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/store/TriggerExecutor.js | 63 ++++++++---- lib/store/checker.js | 192 ++++++++++++++++++++++------------- lib/store/filter.d.ts | 13 ++- lib/store/filter.js | 65 +++++++----- lib/types/Auth.d.ts | 30 +++--- lib/types/Trigger.d.ts | 4 +- src/store/TriggerExecutor.ts | 5 +- src/store/checker.ts | 97 ++++++++++++------ src/store/filter.ts | 76 ++++++++------ src/types/Auth.ts | 47 +++++---- src/types/Trigger.ts | 4 +- 11 files changed, 379 insertions(+), 217 deletions(-) diff --git a/lib/store/TriggerExecutor.js b/lib/store/TriggerExecutor.js index 5971219..a99564a 100644 --- a/lib/store/TriggerExecutor.js +++ b/lib/store/TriggerExecutor.js @@ -205,6 +205,7 @@ var TriggerExecutor = /** @class */ (function () { (0, assert_1.default)(operation.action !== 'create'); var filter = trigger.filter; var filterr = typeof filter === 'function' ? filter(operation, context, option) : filter; + (0, assert_1.default)(!(filterr instanceof Promise)); var filterRepelled = (0, filter_1.checkFilterRepel)(entity, context, filterr, operation.filter); if (filterRepelled) { continue; @@ -228,28 +229,37 @@ var TriggerExecutor = /** @class */ (function () { else { // 异步context var execPreTrigger_1 = function (idx) { return tslib_1.__awaiter(_this, void 0, void 0, function () { - var trigger, filter, filterr, filterRepelled, number; - return tslib_1.__generator(this, function (_a) { - switch (_a.label) { + var trigger, filter, filterr, _a, filterRepelled, number; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { case 0: if (idx >= preTriggers_2.length) { return [2 /*return*/]; } trigger = preTriggers_2[idx]; - if (!trigger.filter) return [3 /*break*/, 2]; + if (!trigger.filter) return [3 /*break*/, 5]; (0, assert_1.default)(operation.action !== 'create'); filter = trigger.filter; - filterr = typeof filter === 'function' ? filter(operation, context, option) : filter; - return [4 /*yield*/, (0, filter_1.checkFilterRepel)(entity, context, filterr, operation.filter)]; + if (!(typeof filter === 'function')) return [3 /*break*/, 2]; + return [4 /*yield*/, filter(operation, context, option)]; case 1: - filterRepelled = _a.sent(); + _a = _b.sent(); + return [3 /*break*/, 3]; + case 2: + _a = filter; + _b.label = 3; + case 3: + filterr = _a; + return [4 /*yield*/, (0, filter_1.checkFilterRepel)(entity, context, filterr, operation.filter)]; + case 4: + filterRepelled = _b.sent(); if (filterRepelled) { return [2 /*return*/, execPreTrigger_1(idx + 1)]; } - _a.label = 2; - case 2: return [4 /*yield*/, trigger.fn({ operation: operation }, context, option)]; - case 3: - number = _a.sent(); + _b.label = 5; + case 5: return [4 /*yield*/, trigger.fn({ operation: operation }, context, option)]; + case 6: + number = _b.sent(); if (number > 0) { this.logger.info("\u89E6\u53D1\u5668\u300C".concat(trigger.name, "\u300D\u6210\u529F\u89E6\u53D1\u4E86\u300C").concat(number, "\u300D\u884C\u6570\u636E\u66F4\u6539")); } @@ -258,28 +268,37 @@ var TriggerExecutor = /** @class */ (function () { }); }); }; var execCommitTrigger_1 = function (idx) { return tslib_1.__awaiter(_this, void 0, void 0, function () { - var trigger, filter, filterr, filterRepelled; - return tslib_1.__generator(this, function (_a) { - switch (_a.label) { + var trigger, filter, filterr, _a, filterRepelled; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { case 0: if (idx >= commitTriggers_1.length) { return [2 /*return*/]; } trigger = commitTriggers_1[idx]; - if (!trigger.filter) return [3 /*break*/, 2]; + if (!trigger.filter) return [3 /*break*/, 5]; (0, assert_1.default)(operation.action !== 'create'); filter = trigger.filter; - filterr = typeof filter === 'function' ? filter(operation, context, option) : filter; - return [4 /*yield*/, (0, filter_1.checkFilterRepel)(entity, context, filterr, operation.filter)]; + if (!(typeof filter === 'function')) return [3 /*break*/, 2]; + return [4 /*yield*/, filter(operation, context, option)]; case 1: - filterRepelled = _a.sent(); + _a = _b.sent(); + return [3 /*break*/, 3]; + case 2: + _a = filter; + _b.label = 3; + case 3: + filterr = _a; + return [4 /*yield*/, (0, filter_1.checkFilterRepel)(entity, context, filterr, operation.filter)]; + case 4: + filterRepelled = _b.sent(); if (filterRepelled) { return [2 /*return*/, execCommitTrigger_1(idx + 1)]; } - _a.label = 2; - case 2: return [4 /*yield*/, this.preCommitTrigger(entity, operation, trigger, context, option)]; - case 3: - _a.sent(); + _b.label = 5; + case 5: return [4 /*yield*/, this.preCommitTrigger(entity, operation, trigger, context, option)]; + case 6: + _b.sent(); return [2 /*return*/, execCommitTrigger_1(idx + 1)]; } }); diff --git a/lib/store/checker.js b/lib/store/checker.js index 27c3aff..9cd5160 100644 --- a/lib/store/checker.js +++ b/lib/store/checker.js @@ -7,6 +7,7 @@ var filter_1 = require("../store/filter"); var Exception_1 = require("../types/Exception"); var actionDef_1 = require("./actionDef"); var string_1 = require("../utils/string"); +var lodash_1 = require("../utils/lodash"); function translateCheckerInAsyncContext(checker) { var _this = this; var entity = checker.entity, type = checker.type; @@ -18,9 +19,14 @@ function translateCheckerInAsyncContext(checker) { return tslib_1.__awaiter(_this, void 0, void 0, function () { var data; return tslib_1.__generator(this, function (_b) { - data = operation.data; - checkerFn_1(data, context); - return [2 /*return*/, 0]; + switch (_b.label) { + case 0: + data = operation.data; + return [4 /*yield*/, checkerFn_1(data, context)]; + case 1: + _b.sent(); + return [2 /*return*/, 0]; + } }); }); }); @@ -30,29 +36,38 @@ function translateCheckerInAsyncContext(checker) { return (function (_a, context, option) { var operation = _a.operation; return tslib_1.__awaiter(_this, void 0, void 0, function () { - var operationFilter, action, filter2, entity2, selection2, rows2, data_1, rows2, data_2; - var _b, _c; - return tslib_1.__generator(this, function (_d) { - switch (_d.label) { + var operationFilter, action, filter2, _b, entity2, selection2, rows2, data_1, rows2, data_2; + var _c, _d; + return tslib_1.__generator(this, function (_e) { + switch (_e.label) { case 0: operationFilter = operation.filter, action = operation.action; - filter2 = typeof filter_2 === 'function' ? filter_2(operation, context, option) : filter_2; - if (!['select', 'count', 'stat'].includes(action)) return [3 /*break*/, 1]; + if (!(typeof filter_2 === 'function')) return [3 /*break*/, 2]; + return [4 /*yield*/, filter_2(operation, context, option)]; + case 1: + _b = _e.sent(); + return [3 /*break*/, 3]; + case 2: + _b = filter_2; + _e.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 1: return [4 /*yield*/, (0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter || {})]; - case 2: - if (_d.sent()) { + case 4: return [4 /*yield*/, (0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter || {}, true)]; + case 5: + if (_e.sent()) { return [2 /*return*/, 0]; } - if (!inconsistentRows_1) return [3 /*break*/, 4]; + 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 3: - rows2 = _d.sent(); + case 6: + rows2 = _e.sent(); data_1 = {}; rows2.forEach(function (ele) { var _a; @@ -62,11 +77,11 @@ function translateCheckerInAsyncContext(checker) { }); throw new Exception_1.OakRowInconsistencyException({ a: 's', - d: (_b = {}, - _b[entity2] = data_1, - _b) + d: (_c = {}, + _c[entity2] = data_1, + _c) }, errMsg_1); - case 4: return [4 /*yield*/, context.select(entity, { + case 7: return [4 /*yield*/, context.select(entity, { data: (0, actionDef_1.getFullProjection)(entity, context.getSchema()), filter: Object.assign({}, operationFilter, { $not: filter2, @@ -75,8 +90,8 @@ function translateCheckerInAsyncContext(checker) { dontCollect: true, blockTrigger: true, })]; - case 5: - rows2 = _d.sent(); + case 8: + rows2 = _e.sent(); data_2 = {}; rows2.forEach(function (ele) { var _a; @@ -86,9 +101,9 @@ function translateCheckerInAsyncContext(checker) { }); throw new Exception_1.OakRowInconsistencyException({ a: 's', - d: (_c = {}, - _c[entity] = data_2, - _c) + d: (_d = {}, + _d[entity] = data_2, + _d) }, errMsg_1); } }); @@ -100,13 +115,23 @@ function translateCheckerInAsyncContext(checker) { return (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) { - if (context.isRoot()) { - return [2 /*return*/, 0]; + var _b, _c, _d; + return tslib_1.__generator(this, function (_e) { + switch (_e.label) { + case 0: + if (context.isRoot()) { + return [2 /*return*/, 0]; + } + // 对后台而言,将生成的relationFilter加到filter之上(select可以在此加以权限的过滤) + _b = operation; + _c = filter_1.combineFilters; + _d = [operation.filter]; + return [4 /*yield*/, relationFilter_1(operation, context, option)]; + case 1: + // 对后台而言,将生成的relationFilter加到filter之上(select可以在此加以权限的过滤) + _b.filter = _c.apply(void 0, [_d.concat([_e.sent()])]); + return [2 /*return*/, 0]; } - // 对后台而言,将生成的relationFilter加到filter之上(select可以在此加以权限的过滤) - operation.filter = (0, filter_1.combineFilters)([operation.filter, relationFilter_1(operation, context, option)]); - return [2 /*return*/, 0]; }); }); }); @@ -124,13 +149,15 @@ function translateCheckerInAsyncContext(checker) { if (context.isRoot() && type === 'expressionRelation') { return [2 /*return*/, 0]; } - exprResult = expression_1(operation, context, option); - if (!(typeof exprResult === 'string')) return [3 /*break*/, 1]; - throw new Exception_1.OakUserUnpermittedException(exprResult || errMsg_2); + return [4 /*yield*/, expression_1(operation, context, option)]; case 1: - if (!(exprResult === undefined)) return [3 /*break*/, 2]; - return [2 /*return*/, 0]; + exprResult = _c.sent(); + if (!(typeof exprResult === 'string')) return [3 /*break*/, 2]; + throw new Exception_1.OakUserUnpermittedException(exprResult || errMsg_2); case 2: + if (!(exprResult === undefined)) return [3 /*break*/, 3]; + return [2 /*return*/, 0]; + case 3: expressionEntity = exprResult.entity, expr = exprResult.expr, expressionFilter = exprResult.filter; return [4 /*yield*/, context.select(expressionEntity, { data: { @@ -138,14 +165,19 @@ function translateCheckerInAsyncContext(checker) { }, filter: expressionFilter, }, Object.assign({}, option, { dontCollect: true }))]; - case 3: + case 4: _b = tslib_1.__read.apply(void 0, [_c.sent(), 1]), result = _b[0]; if (!result) { // 条件判定为假,抛异常 - throw new Exception_1.OakUserUnpermittedException(errMsg_2); + if (type === 'expression') { + throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_2); + } + else { + throw new Exception_1.OakUserUnpermittedException(errMsg_2); + } } - _c.label = 4; - case 4: return [2 /*return*/, 0]; + _c.label = 5; + case 5: return [2 /*return*/, 0]; } }); }); @@ -175,7 +207,8 @@ function translateCheckerInSyncContext(checker) { return 0; } else { - if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter)) { + (0, assert_1.default)(!(filter2 instanceof Promise)); + if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter, true)) { return; } throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_3); @@ -191,7 +224,8 @@ function translateCheckerInSyncContext(checker) { var filter2 = typeof filter_4 === 'function' ? filter_4(operation, context, option) : filter_4; var operationFilter = operation.filter; (0, assert_1.default)(operationFilter); - if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter)) { + (0, assert_1.default)(!(filter2 instanceof Promise)); + if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter, true)) { return; } throw new Exception_1.OakUserUnpermittedException(errMsg_4); @@ -212,6 +246,7 @@ function translateCheckerInSyncContext(checker) { return 0; } else { + (0, assert_1.default)(!(exprResult instanceof Promise)); var expressionEntity = exprResult.entity, expr = exprResult.expr, expressionFilter = exprResult.filter; var _a = tslib_1.__read(context.select(expressionEntity, { data: { @@ -221,7 +256,12 @@ function translateCheckerInSyncContext(checker) { }, Object.assign({}, option, { dontCollect: true })), 1), result = _a[0]; if (!result.$expr) { // 条件判定为假,抛异常 - throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_5); + if (type === 'expression') { + throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_5); + } + else { + throw new Exception_1.OakUserUnpermittedException(errMsg_5); + } } return; } @@ -304,41 +344,57 @@ function createRelationHierarchyCheckers(schema) { entity: userEntityName_1, action: 'remove', type: 'expressionRelation', - conditionalFilter: { - relation: r, - }, expression: function (operation, context) { - var _a, _b; + var _a; var userId = context.getCurrentUserId(); var filter = operation.filter; var legalRelations = reverseHierarchy_1[r]; if (legalRelations.length === 0) { return '这是不应该跑出来的情况,请杀程序员祭天'; } - return { - entity: userEntityName_1, - expr: { - $gt: [{ - '#attr': '$$createAt$$', - }, 0] - }, - filter: (_a = { - userId: userId + var makeFilterFromRows = function (rows) { + var _a; + var relations = (0, lodash_1.uniq)(rows.map(function (ele) { return ele.relation; })); + var entityIds = (0, lodash_1.uniq)(rows.map(function (ele) { return ele[entityIdAttr_1]; })); + (0, assert_1.default)(entityIds.length === 1, "\u5728\u56DE\u6536".concat(userEntityName_1, "\u4E0A\u6743\u9650\u65F6\uFF0C\u5355\u6B21\u56DE\u6536\u6D89\u53CA\u5230\u4E86\u4E0D\u540C\u7684\u5BF9\u8C61\uFF0C\u6B64\u64CD\u4F5C\u4E0D\u88AB\u5141\u8BB8")); + var legalRelationss = relations.map(function (ele) { + if (reverseHierarchy_1[ele]) { + return reverseHierarchy_1[ele]; + } + (0, assert_1.default)(false, "\u5728\u56DE\u6536".concat(userEntityName_1, "\u4E0A\u7C7B\u578B\u4E3A").concat(ele, "\u7684\u6743\u9650\u65F6\uFF0C\u627E\u4E0D\u5230\u5BF9\u5E94\u7684\u5B9A\u4E49\uFF0C\u4E0D\u5E94\u8BE5\u51FA\u73B0\u7684\u60C5\u51B5")); + }); + // 如果要删除多个不同的权限,这里必须要有它们共同的上级权限 + var legaRelations = (0, lodash_1.intersection)(legalRelationss); + return { + entity: userEntityName_1, + expr: { + $gt: [{ + '#attr': '$$createAt$$', + }, 0] }, - _a[entityIdAttr_1] = { - $in: { - entity: userEntityName_1, - data: (_b = {}, - _b[entityIdAttr_1] = 1, - _b), - filter: filter, - } - }, - _a.relation = { - $in: legalRelations, - }, - _a), + filter: (_a = { + userId: userId + }, + _a[entityIdAttr_1] = entityIds[0], + _a.relation = { + $in: legaRelations, + }, + _a), + }; }; + var toBeRemoved = context.select(userEntityName_1, { + data: (_a = { + id: 1, + relation: 1 + }, + _a[entityIdAttr_1] = 1, + _a), + filter: filter, + }, { dontCollect: true }); + if (toBeRemoved instanceof Promise) { + return toBeRemoved.then(function (rows) { return makeFilterFromRows(rows); }); + } + return makeFilterFromRows(toBeRemoved); }, errMsg: '越权操作', }); diff --git a/lib/store/filter.d.ts b/lib/store/filter.d.ts index 364cf90..6f7c213 100644 --- a/lib/store/filter.d.ts +++ b/lib/store/filter.d.ts @@ -96,5 +96,14 @@ export declare function makeTreeAncestorFilter(entity: T, parentKey: string, filter: ED[T]['Selection']['filter'], level?: number, includeAll?: boolean, includeSelf?: boolean): ED[T]['Selection']['filter']; -export declare function checkFilterContains | AsyncContext>(entity: T, context: Cxt, contained: ED[T]['Selection']['filter'], filter?: ED[T]['Selection']['filter']): boolean | Promise; -export declare function checkFilterRepel | AsyncContext>(entity: T, context: Cxt, filter1: ED[T]['Selection']['filter'], filter2: ED[T]['Selection']['filter']): boolean | Promise; +/** + * 检查filter是否包含contained(filter查询的数据一定满足contained) + * @param entity + * @param context + * @param contained + * @param filter + * @param dataCompare + * @returns + */ +export declare function checkFilterContains | 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; diff --git a/lib/store/filter.js b/lib/store/filter.js index 4d2edfd..17099ed 100644 --- a/lib/store/filter.js +++ b/lib/store/filter.js @@ -828,7 +828,16 @@ function makeTreeDescendantFilter(entity, parentKey, filter, level, includeAll, return currentLevelInFilter; } exports.makeTreeDescendantFilter = makeTreeDescendantFilter; -function checkFilterContains(entity, context, contained, filter) { +/** + * 检查filter是否包含contained(filter查询的数据一定满足contained) + * @param entity + * @param context + * @param contained + * @param filter + * @param dataCompare + * @returns + */ +function checkFilterContains(entity, context, contained, filter, dataCompare) { if (!filter) { throw new types_1.OakRowInconsistencyException(); } @@ -837,23 +846,26 @@ function checkFilterContains(entity, context, contained, filter) { if (contains(entity, schema, filter, contained)) { return true; } - // 再判断加上了conditionalFilter后取得的行数是否缩减 - var filter2 = combineFilters([filter, { - $not: contained, - }]); - var count = context.count(entity, { - filter: filter2, - }, { - dontCollect: true, - blockTrigger: true, - }); - if (count instanceof Promise) { - return count.then(function (count2) { return count2 === 0; }); + if (dataCompare) { + // 再判断加上了conditionalFilter后取得的行数是否缩减 + var filter2 = combineFilters([filter, { + $not: contained, + }]); + var count = context.count(entity, { + filter: filter2, + }, { + dontCollect: true, + blockTrigger: true, + }); + if (count instanceof Promise) { + return count.then(function (count2) { return count2 === 0; }); + } + return count === 0; } - return count === 0; + return false; } exports.checkFilterContains = checkFilterContains; -function checkFilterRepel(entity, context, filter1, filter2) { +function checkFilterRepel(entity, context, filter1, filter2, dataCompare) { if (!filter2) { throw new types_1.OakRowInconsistencyException(); } @@ -863,16 +875,19 @@ function checkFilterRepel(entity, context, filter1, filter2) { return true; } // 再判断两者同时成立时取得的行数是否为0 - var filter3 = combineFilters([filter2, filter1]); - var count = context.count(entity, { - filter: filter3, - }, { - dontCollect: true, - blockTrigger: true, - }); - if (count instanceof Promise) { - return count.then(function (count2) { return count2 === 0; }); + if (dataCompare) { + var filter3 = combineFilters([filter2, filter1]); + var count = context.count(entity, { + filter: filter3, + }, { + dontCollect: true, + blockTrigger: true, + }); + if (count instanceof Promise) { + return count.then(function (count2) { return count2 === 0; }); + } + return count === 0; } - return count === 0; + return false; } exports.checkFilterRepel = checkFilterRepel; diff --git a/lib/types/Auth.d.ts b/lib/types/Auth.d.ts index 28a9536..d43e665 100644 --- a/lib/types/Auth.d.ts +++ b/lib/types/Auth.d.ts @@ -12,41 +12,42 @@ export declare type DataChecker | Array>; - checker: (data: ED[T]['Create']['data'] | ED[T]['Update']['data'], context: Cxt) => void; - conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); + checker: (data: ED[T]['Create']['data'] | ED[T]['Update']['data'], context: Cxt) => void | Promise; + conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter'] | Promise); }; export declare type RowChecker | SyncContext> = { priority?: number; type: 'row'; entity: T; action: Omit | Array>; - filter: ED[T]['Selection']['filter'] | ((operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ED[T]['Selection']['filter']); + filter: ED[T]['Selection']['filter'] | ((operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ED[T]['Selection']['filter'] | Promise); errMsg?: string; inconsistentRows?: { entity: keyof ED; selection: (filter?: ED[T]['Selection']['filter']) => ED[keyof ED]['Selection']; }; - conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); + conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter'] | Promise); }; export declare type RelationChecker | SyncContext> = { priority?: number; type: 'relation'; entity: T; action: Omit | Array>; - relationFilter: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ED[T]['Selection']['filter']; + relationFilter: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ED[T]['Selection']['filter'] | Promise; errMsg: string; - conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); + conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter'] | Promise); +}; +declare type ExpressionResult = { + entity: T; + expr: RefOrExpression; + filter: ED[T]['Selection']['filter']; }; export declare type ExpressionChecker | SyncContext> = { priority?: number; type: 'expression'; entity: T; action: ED[T]['Action'] | Array; - expression: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => { - entity: T2; - expr: RefOrExpression; - filter: ED[T2]['Selection']['filter']; - } | undefined | string; + expression: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ExpressionResult | Promise> | undefined | string; errMsg: string; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); }; @@ -55,12 +56,9 @@ export declare type ExpressionRelationChecker; - expression: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => { - entity: T2; - expr: RefOrExpression; - filter: ED[T2]['Selection']['filter']; - } | undefined | string; + expression: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ExpressionResult | Promise> | undefined | string; errMsg: string; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); }; export declare type Checker | SyncContext> = DataChecker | RowChecker | RelationChecker | ExpressionChecker | ExpressionRelationChecker; +export {}; diff --git a/lib/types/Trigger.d.ts b/lib/types/Trigger.d.ts index 128e85c..0015048 100644 --- a/lib/types/Trigger.d.ts +++ b/lib/types/Trigger.d.ts @@ -37,7 +37,7 @@ export interface UpdateTriggerBase Promise | number; - filter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Update'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); + filter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Update'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter'] | Promise); } export interface UpdateTriggerInTxn | SyncContext> extends UpdateTriggerBase { when: 'before' | 'after'; @@ -58,7 +58,7 @@ export interface RemoveTriggerBase Promise | number; - filter?: ED[T]['Remove']['filter'] | ((operation: ED[T]['Remove'], context: Cxt, option: OperateOption) => ED[T]['Remove']['filter']); + filter?: ED[T]['Remove']['filter'] | ((operation: ED[T]['Remove'], context: Cxt, option: OperateOption) => ED[T]['Remove']['filter'] | Promise); } export interface RemoveTriggerInTxn | SyncContext> extends RemoveTriggerBase { when: 'before' | 'after'; diff --git a/src/store/TriggerExecutor.ts b/src/store/TriggerExecutor.ts index 9024c9b..1b6f1b9 100644 --- a/src/store/TriggerExecutor.ts +++ b/src/store/TriggerExecutor.ts @@ -230,6 +230,7 @@ export class TriggerExecutor { assert(operation.action !== 'create'); const { filter } = trigger as UpdateTrigger; const filterr = typeof filter === 'function' ? filter(operation, context, option) : filter; + assert(!(filterr instanceof Promise)); const filterRepelled = checkFilterRepel(entity, context, filterr, operation.filter) as boolean if (filterRepelled) { continue; @@ -252,7 +253,7 @@ export class TriggerExecutor { if ((trigger as UpdateTrigger).filter) { assert(operation.action !== 'create'); const { filter } = trigger as UpdateTrigger; - const filterr = typeof filter === 'function' ? filter(operation, context, option) : filter; + const filterr = typeof filter === 'function' ? await filter(operation, context, option) : filter; const filterRepelled = await (checkFilterRepel(entity, context, filterr, operation.filter) as Promise); if (filterRepelled) { return execPreTrigger(idx + 1); @@ -272,7 +273,7 @@ export class TriggerExecutor { if ((trigger as UpdateTrigger).filter) { assert(operation.action !== 'create'); const { filter } = trigger as UpdateTrigger; - const filterr = typeof filter === 'function' ? filter(operation, context, option) : filter; + const filterr = typeof filter === 'function' ? await filter(operation, context, option) : filter; const filterRepelled = await (checkFilterRepel(entity, context, filterr, operation.filter) as Promise); if (filterRepelled) { return execCommitTrigger(idx + 1); diff --git a/src/store/checker.ts b/src/store/checker.ts index 3853c54..97c7609 100644 --- a/src/store/checker.ts +++ b/src/store/checker.ts @@ -1,12 +1,13 @@ import assert from 'assert'; import { addFilterSegment, checkFilterContains, combineFilters } from "../store/filter"; import { OakDataException, OakRowInconsistencyException, OakUserUnpermittedException } from '../types/Exception'; -import { Checker, CreateTriggerInTxn, EntityDict, ExpressionRelationChecker, OperateOption, SelectOption, StorageSchema, Trigger, UpdateTriggerInTxn } from "../types"; +import { Checker, CreateTriggerInTxn, EntityDict, ExpressionRelationChecker, OperateOption, RefOrExpression, SelectOption, StorageSchema, Trigger, UpdateTriggerInTxn } from "../types"; import { EntityDict as BaseEntityDict } from '../base-app-domain'; import { AsyncContext } from "./AsyncRowStore"; import { getFullProjection } from './actionDef'; import { SyncContext } from './SyncRowStore'; import { firstLetterUpperCase } from '../utils/string'; +import { intersection, uniq } from '../utils/lodash'; export function translateCheckerInAsyncContext< ED extends EntityDict & BaseEntityDict, @@ -18,7 +19,7 @@ export function translateCheckerInAsyncContext< const { checker: checkerFn } = checker; return (async ({ operation }, context) => { const { data } = operation; - checkerFn(data, context); + await checkerFn(data, context); return 0; }) as CreateTriggerInTxn['fn']; } @@ -26,13 +27,13 @@ export function translateCheckerInAsyncContext< const { filter, errMsg, inconsistentRows } = checker; return (async ({ operation }, context, option) => { const { filter: operationFilter, action } = operation; - const filter2 = typeof filter === 'function' ? filter(operation, context, option) : filter; + const filter2 = typeof filter === 'function' ? await filter(operation, context, option) : filter; if (['select', 'count', 'stat'].includes(action)) { operation.filter = addFilterSegment(operationFilter || {}, filter2); return 0; } else { - if (await checkFilterContains(entity, context, filter2, operationFilter || {})) { + if (await checkFilterContains(entity, context, filter2, operationFilter || {}, true)) { return 0; } if (inconsistentRows) { @@ -89,7 +90,7 @@ export function translateCheckerInAsyncContext< return 0; } // 对后台而言,将生成的relationFilter加到filter之上(select可以在此加以权限的过滤) - operation.filter = combineFilters([operation.filter, relationFilter(operation, context, option)]); + operation.filter = combineFilters([operation.filter, await relationFilter(operation, context, option)]); return 0; }) as UpdateTriggerInTxn['fn']; } @@ -100,7 +101,7 @@ export function translateCheckerInAsyncContext< if (context.isRoot() && type === 'expressionRelation') { return 0; } - const exprResult = expression(operation, context, option); + const exprResult = await expression(operation, context, option); if (typeof exprResult === 'string') { throw new OakUserUnpermittedException(exprResult || errMsg); } @@ -117,7 +118,12 @@ export function translateCheckerInAsyncContext< }, Object.assign({}, option, { dontCollect: true })); if (!result) { // 条件判定为假,抛异常 - throw new OakUserUnpermittedException(errMsg); + if (type === 'expression') { + throw new OakRowInconsistencyException(undefined, errMsg); + } + else { + throw new OakUserUnpermittedException(errMsg); + } } } return 0; @@ -151,7 +157,8 @@ export function translateCheckerInSyncContext< return 0; } else { - if (checkFilterContains(entity, context, filter2, operationFilter)) { + assert(!(filter2 instanceof Promise)); + if (checkFilterContains(entity, context, filter2, operationFilter, true)) { return; } throw new OakRowInconsistencyException(undefined, errMsg); @@ -167,7 +174,8 @@ export function translateCheckerInSyncContext< const filter2 = typeof filter === 'function' ? filter(operation, context, option) : filter; const { filter: operationFilter } = operation; assert(operationFilter); - if (checkFilterContains(entity, context, filter2, operationFilter)) { + assert(!(filter2 instanceof Promise)); + if (checkFilterContains(entity, context, filter2, operationFilter, true)) { return; } throw new OakUserUnpermittedException(errMsg); @@ -188,6 +196,7 @@ export function translateCheckerInSyncContext< return 0; } else { + assert(!(exprResult instanceof Promise)); const { entity: expressionEntity, expr, filter: expressionFilter } = exprResult; const [result] = context.select(expressionEntity, { data: { @@ -197,7 +206,12 @@ export function translateCheckerInSyncContext< }, Object.assign({}, option, { dontCollect: true })) as any[]; if (!result.$expr) { // 条件判定为假,抛异常 - throw new OakRowInconsistencyException(undefined, errMsg); + if (type === 'expression') { + throw new OakRowInconsistencyException(undefined, errMsg); + } + else { + throw new OakUserUnpermittedException(errMsg); + } } return; } @@ -270,9 +284,6 @@ export function createRelationHierarchyCheckers(operation: any, context: Cxt) => { const userId = context.getCurrentUserId(); const { filter } = operation as ED[keyof ED]['Remove']; @@ -280,29 +291,51 @@ export function createRelationHierarchyCheckers[]) => { + const relations = uniq(rows.map(ele => ele.relation)); + const entityIds = uniq(rows.map(ele => ele[entityIdAttr])); + assert(entityIds.length === 1, `在回收${userEntityName}上权限时,单次回收涉及到了不同的对象,此操作不被允许`); + const legalRelationss = relations.map( + ele => { + if (reverseHierarchy[ele!]) { + return reverseHierarchy[ele!]; + } + assert(false, `在回收${userEntityName}上类型为${ele}的权限时,找不到对应的定义,不应该出现的情况`); + } + ); + // 如果要删除多个不同的权限,这里必须要有它们共同的上级权限 + const legaRelations = intersection(legalRelationss); + return { + entity: userEntityName as T2, + expr: { + $gt: [{ + '#attr': '$$createAt$$', + }, 0] + } as RefOrExpression, + filter: { + userId, + [entityIdAttr]: entityIds[0], + relation: { + $in: legaRelations, } }, - relation: { - $in: legalRelations, - } + } + }; + + 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: '越权操作', }); diff --git a/src/store/filter.ts b/src/store/filter.ts index 2e296f4..fdc672d 100644 --- a/src/store/filter.ts +++ b/src/store/filter.ts @@ -879,11 +879,21 @@ export function makeTreeDescendantFilter | AsyncContext>( entity: T, context: Cxt, contained: ED[T]['Selection']['filter'], - filter?: ED[T]['Selection']['filter']): boolean | Promise { + filter?: ED[T]['Selection']['filter'], + dataCompare?: true): boolean | Promise { if (!filter) { throw new OakRowInconsistencyException(); } @@ -892,29 +902,34 @@ export function checkFilterContains count2 === 0 - ); + if (dataCompare) { + // 再判断加上了conditionalFilter后取得的行数是否缩减 + const filter2 = combineFilters([filter, { + $not: contained, + }]); + const count = context.count(entity, { + filter: filter2, + }, { + dontCollect: true, + blockTrigger: true, + }); + if (count instanceof Promise) { + return count.then( + (count2) => count2 === 0 + ); + } + return count === 0; } - return count === 0; + return false; } export function checkFilterRepel | AsyncContext>( entity: T, context: Cxt, filter1: ED[T]['Selection']['filter'], - filter2: ED[T]['Selection']['filter']): boolean | Promise { + filter2: ED[T]['Selection']['filter'], + dataCompare?: true +): boolean | Promise { if (!filter2) { throw new OakRowInconsistencyException(); } @@ -924,17 +939,20 @@ export function checkFilterRepel count2 === 0 - ); + if (dataCompare) { + const filter3 = combineFilters([filter2, filter1]); + const count = context.count(entity, { + filter: filter3, + }, { + dontCollect: true, + blockTrigger: true, + }); + if (count instanceof Promise) { + return count.then( + (count2) => count2 === 0 + ); + } + return count === 0; } - return count === 0; + return false; } \ No newline at end of file diff --git a/src/types/Auth.ts b/src/types/Auth.ts index 887ab3a..a74a15b 100644 --- a/src/types/Auth.ts +++ b/src/types/Auth.ts @@ -14,8 +14,10 @@ export type DataChecker | Array>; - checker: (data: ED[T]['Create']['data'] | ED[T]['Update']['data'], context: Cxt) => void; - conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); + checker: (data: ED[T]['Create']['data'] | ED[T]['Update']['data'], context: Cxt) => void | Promise; + conditionalFilter?: ED[T]['Update']['filter'] | ( + (operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter'] | Promise + ); }; export type RowChecker | SyncContext> = { @@ -23,13 +25,17 @@ export type RowChecker | Array>; - filter: ED[T]['Selection']['filter'] | ((operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ED[T]['Selection']['filter']); // 对行的额外检查条件 + filter: ED[T]['Selection']['filter'] | ( + (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ED[T]['Selection']['filter'] | Promise + ); // 对行的额外检查条件 errMsg?: string; inconsistentRows?: { // 因为这里的限制不一定在本row上,如果不传这个exception,则默认返回本row上的exception entity: keyof ED; selection: (filter?: ED[T]['Selection']['filter']) => ED[keyof ED]['Selection']; }; - conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); + conditionalFilter?: ED[T]['Update']['filter'] | ( + (operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter'] | Promise + ); }; export type RelationChecker | SyncContext> = { @@ -37,9 +43,17 @@ export type RelationChecker | Array>; - relationFilter: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ED[T]['Selection']['filter']; // 生成一个额外的relation相关的filter,加在原先的filter上 + relationFilter: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ED[T]['Selection']['filter'] | Promise; // 生成一个额外的relation相关的filter,加在原先的filter上 errMsg: string; - conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); + conditionalFilter?: ED[T]['Update']['filter'] | ( + (operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter'] | Promise + ); +}; + +type ExpressionResult = { + entity: T; + expr: RefOrExpression; + filter: ED[T]['Selection']['filter']; }; export type ExpressionChecker | SyncContext> = { @@ -47,26 +61,25 @@ export type ExpressionChecker; - expression: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => { - entity: T2; - expr: RefOrExpression; - filter: ED[T2]['Selection']['filter']; - } | undefined | string; // 生成一个带表达式的查询任务,结果为true代表可以过,为false不可以。如果返回undefined直接过,返回string直接挂 + expression: ( + operation: ED[T]['Operation'] | ED[T]['Selection'], + context: Cxt, + option: OperateOption | SelectOption + ) => ExpressionResult | Promise> | undefined | string; // 生成一个带表达式的查询任务,结果为true代表可以过,为false不可以。如果返回undefined直接过,返回string直接挂 errMsg: string; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); }; - export type ExpressionRelationChecker | SyncContext> = { priority?: number; type: 'expressionRelation'; entity: T; action: ED[T]['Action'] | Array; - expression: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => { - entity: T2; - expr: RefOrExpression; - filter: ED[T2]['Selection']['filter']; - } | undefined | string; // 生成一个带表达式的查询任务,结果为true代表可以过。如果返回undefined直接过,返回string直接挂 + expression: ( + operation: ED[T]['Operation'] | ED[T]['Selection'], + context: Cxt, + option: OperateOption | SelectOption + ) => ExpressionResult | Promise> | undefined | string; // 生成一个带表达式的查询任务,结果为true代表可以过。如果返回undefined直接过,返回string直接挂 errMsg: string; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); }; diff --git a/src/types/Trigger.ts b/src/types/Trigger.ts index de16e0d..8cae331 100644 --- a/src/types/Trigger.ts +++ b/src/types/Trigger.ts @@ -39,7 +39,7 @@ export interface UpdateTriggerBase; check?: (operation: ED[T]['Update']) => boolean; fn: (event: { operation: ED[T]['Update'] }, context: Cxt, option: OperateOption) => Promise | number; - filter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Update'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); + filter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Update'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter'] | Promise); }; export interface UpdateTriggerInTxn | SyncContext> extends UpdateTriggerBase { @@ -63,7 +63,7 @@ export interface RemoveTriggerBase boolean; fn: (event: { operation: ED[T]['Remove'] }, context: Cxt, option: OperateOption) => Promise | number; - filter?: ED[T]['Remove']['filter'] | ((operation: ED[T]['Remove'], context: Cxt, option: OperateOption) => ED[T]['Remove']['filter']); + filter?: ED[T]['Remove']['filter'] | ((operation: ED[T]['Remove'], context: Cxt, option: OperateOption) => ED[T]['Remove']['filter'] | Promise); }; export interface RemoveTriggerInTxn | SyncContext> extends RemoveTriggerBase { From 9034ba076a5708b1b865652a0a0faf9992968487 Mon Sep 17 00:00:00 2001 From: "Xc@centOs" Date: Mon, 16 Jan 2023 19:38:44 +0800 Subject: [PATCH 06/19] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E5=AF=B9casca?= =?UTF-8?q?deRelationHierarchy=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/compiler/schemalBuilder.js | 44 +++- lib/store/checker.js | 395 ++++++++++++++++++++------------ lib/types/Auth.d.ts | 8 +- lib/types/Entity.d.ts | 7 + lib/types/Storage.d.ts | 3 +- src/compiler/schemalBuilder.ts | 50 +++- src/store/checker.ts | 401 +++++++++++++++++++++++---------- src/types/Auth.ts | 8 +- src/types/Entity.ts | 9 + src/types/Storage.ts | 3 +- 10 files changed, 642 insertions(+), 286 deletions(-) diff --git a/lib/compiler/schemalBuilder.js b/lib/compiler/schemalBuilder.js index 42402a4..e9b1b10 100644 --- a/lib/compiler/schemalBuilder.js +++ b/lib/compiler/schemalBuilder.js @@ -338,6 +338,7 @@ function analyzeEntity(filename, path, program, relativePath) { var additionalImports = []; var localeDef = undefined; var relationHierarchy = undefined; + var reverseCascadeRelationHierarchy = undefined; ts.forEachChild(sourceFile, function (node) { var _a, _b, _c, _d; if (ts.isImportDeclaration(node)) { @@ -802,6 +803,13 @@ function analyzeEntity(filename, path, program, relativePath) { (0, assert_1.default)(ts.isObjectLiteralExpression(initializer), "".concat(moduleName, "\u4E2D\u7684RelationHierarchy\u7684\u5B9A\u4E49\u5FC5\u987B\u662F\u521D\u59CB\u5316\u4E3AObjectLiteralExpress")); relationHierarchy = initializer; } + else if (ts.isTypeReferenceNode(declaration.type) && ts.isIdentifier(declaration.type.typeName) && declaration.type.typeName.text === 'ReverseCascadeRelationHierarchy') { + // ReverseCascadeRelationHierarchy + (0, assert_1.default)(hasRelationDef, "".concat(moduleName, "\u4E2D\u7684Relation\u5B9A\u4E49\u5728ReverseCascadeRelationHierarchy\u4E4B\u540E")); + var initializer = declaration.initializer; + (0, assert_1.default)(ts.isObjectLiteralExpression(initializer), "".concat(moduleName, "\u4E2D\u7684RelationHierarchy\u7684\u5B9A\u4E49\u5FC5\u987B\u662F\u521D\u59CB\u5316\u4E3AObjectLiteralExpress")); + reverseCascadeRelationHierarchy = initializer; + } else { throw new Error("".concat(moduleName, "\uFF1A\u4E0D\u80FD\u7406\u89E3\u7684\u5B9A\u4E49\u5185\u5BB9").concat(declaration.name.getText())); } @@ -844,13 +852,23 @@ function analyzeEntity(filename, path, program, relativePath) { }); } if (hasRelationDef) { - (0, assert_1.default)(relationHierarchy, "".concat(filename, "\u4E2D\u7F3A\u5C11\u4E86relationHierarchy\u5B9A\u4E49")); - (0, lodash_1.assign)(schema, { - relationHierarchy: relationHierarchy, - }); + if (!relationHierarchy && !reverseCascadeRelationHierarchy) { + console.warn("".concat(filename, "\u4E2D\u5B9A\u4E49\u4E86Relation,\u4F46\u5E76\u6CA1\u6709relationHierarchy\u6216reverseCascadeRelationHierarchy\u7684\u5B9A\u4E49\uFF0C\u8BF7\u6CE8\u610F\u81EA\u4E3B\u7F16\u5199\u6743\u9650\u5206\u914D\u7684checker")); + } + if (relationHierarchy) { + (0, lodash_1.assign)(schema, { + relationHierarchy: relationHierarchy, + }); + } + if (reverseCascadeRelationHierarchy) { + (0, lodash_1.assign)(schema, { + reverseCascadeRelationHierarchy: reverseCascadeRelationHierarchy, + }); + } } else { (0, assert_1.default)(!relationHierarchy, "".concat(filename, "\u4E2D\u5177\u6709relationHierarchy\u5B9A\u4E49\u4F46\u6CA1\u6709Relation\u5B9A\u4E49")); + (0, assert_1.default)(!reverseCascadeRelationHierarchy, "".concat(filename, "\u4E2D\u5177\u6709reverseCascadeRelationHierarchy\u5B9A\u4E49\u4F46\u6CA1\u6709Relation\u5B9A\u4E49")); } (0, lodash_1.assign)(Schema, (_a = {}, _a[moduleName] = schema, @@ -1939,6 +1957,11 @@ function constructActions(statements, entity) { var reverseOneNodes = []; if (ReversePointerEntities[entity]) { if (ReversePointerRelations[entity]) { + var schemaAttrs = Schema[entity].schemaAttrs; + var questionToken = schemaAttrs.find(function (ele) { + var name = ele.name; + return name.text === 'entity'; + }).questionToken; try { for (var _q = tslib_1.__values(ReversePointerRelations[entity]), _r = _q.next(); !_r.done; _r = _q.next()) { var one = _r.value; @@ -1956,10 +1979,8 @@ function constructActions(statements, entity) { factory.createPropertySignature(undefined, factory.createIdentifier((0, string_1.firstLetterLowerCase)(one)), undefined, factory.createTypeReferenceNode(createForeignRef(entity, one, 'UpdateOperation'))) ]); var noCascadeNode = factory.createTypeLiteralNode([ - factory.createPropertySignature(undefined, factory.createIdentifier('entity'), undefined, // 反向指针好像不能为空,以后或许会有特例 by Xc - factory.createLiteralTypeNode(factory.createStringLiteral("".concat((0, string_1.firstLetterLowerCase)(one))))), - factory.createPropertySignature(undefined, factory.createIdentifier('entityId'), undefined, // 反向指针好像不能为空,以后或许会有特例 by Xc - factory.createTypeReferenceNode(factory.createIdentifier("String"), [factory.createLiteralTypeNode(factory.createNumericLiteral("64"))])) + factory.createPropertySignature(undefined, factory.createIdentifier('entity'), questionToken, factory.createLiteralTypeNode(factory.createStringLiteral("".concat((0, string_1.firstLetterLowerCase)(one))))), + factory.createPropertySignature(undefined, factory.createIdentifier('entityId'), questionToken, factory.createTypeReferenceNode(factory.createIdentifier("String"), [factory.createLiteralTypeNode(factory.createNumericLiteral("64"))])) ]); if (Schema[one].static) { reverseOneNodes.push(noCascadeNode); @@ -3045,11 +3066,11 @@ function outputStorage(outputDir, printer) { var entityAssignments = []; for (var entity in Schema) { var indexExpressions = []; - var _a = Schema[entity], sourceFile = _a.sourceFile, inModi = _a.inModi, indexes = _a.indexes, toModi = _a.toModi, actionType = _a.actionType, _static = _a.static, relationHierarchy = _a.relationHierarchy; + var _a = Schema[entity], sourceFile = _a.sourceFile, inModi = _a.inModi, indexes = _a.indexes, toModi = _a.toModi, actionType = _a.actionType, _static = _a.static, relationHierarchy = _a.relationHierarchy, reverseCascadeRelationHierarchy = _a.reverseCascadeRelationHierarchy; var fromSchemaSpecifiers = [ factory.createImportSpecifier(false, undefined, factory.createIdentifier("OpSchema")) ]; - if (relationHierarchy) { + if (relationHierarchy || reverseCascadeRelationHierarchy) { fromSchemaSpecifiers.push(factory.createImportSpecifier(false, undefined, factory.createIdentifier("Relation"))); } var statements = [ @@ -3113,6 +3134,9 @@ function outputStorage(outputDir, printer) { if (relationHierarchy) { propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("relationHierarchy"), relationHierarchy)); } + if (reverseCascadeRelationHierarchy) { + propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("reverseCascadeRelationHierarchy"), reverseCascadeRelationHierarchy)); + } var sdTypeArguments = [ factory.createTypeReferenceNode(factory.createIdentifier("OpSchema"), undefined) ]; diff --git a/lib/store/checker.js b/lib/store/checker.js index 9cd5160..90c533f 100644 --- a/lib/store/checker.js +++ b/lib/store/checker.js @@ -8,6 +8,7 @@ var Exception_1 = require("../types/Exception"); var actionDef_1 = require("./actionDef"); var string_1 = require("../utils/string"); var lodash_1 = require("../utils/lodash"); +var relation_1 = require("./relation"); function translateCheckerInAsyncContext(checker) { var _this = this; var entity = checker.entity, type = checker.type; @@ -142,32 +143,44 @@ function translateCheckerInAsyncContext(checker) { return (function (_a, context, option) { var operation = _a.operation; return tslib_1.__awaiter(_this, void 0, void 0, function () { - var exprResult, expressionEntity, expr, expressionFilter, _b, result; - return tslib_1.__generator(this, function (_c) { - switch (_c.label) { + var exprResult, result2, isLegal; + var _this = this; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { case 0: if (context.isRoot() && type === 'expressionRelation') { return [2 /*return*/, 0]; } return [4 /*yield*/, expression_1(operation, context, option)]; case 1: - exprResult = _c.sent(); + exprResult = _b.sent(); if (!(typeof exprResult === 'string')) return [3 /*break*/, 2]; throw new Exception_1.OakUserUnpermittedException(exprResult || errMsg_2); case 2: if (!(exprResult === undefined)) return [3 /*break*/, 3]; return [2 /*return*/, 0]; - case 3: - expressionEntity = exprResult.entity, expr = exprResult.expr, expressionFilter = exprResult.filter; - return [4 /*yield*/, context.select(expressionEntity, { - data: { - $expr: expr, - }, - filter: expressionFilter, - }, Object.assign({}, option, { dontCollect: true }))]; + case 3: return [4 /*yield*/, Promise.all(exprResult.map(function (e1) { return Promise.all(e1.map(function (e2) { return tslib_1.__awaiter(_this, void 0, void 0, function () { + var expressionEntity, expr, expressionFilter, _a, result; + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { + case 0: + expressionEntity = e2.entity, expr = e2.expr, expressionFilter = e2.filter; + return [4 /*yield*/, context.select(expressionEntity, { + data: { + $expr: expr, + }, + filter: expressionFilter, + }, Object.assign({}, option, { dontCollect: true }))]; + case 1: + _a = tslib_1.__read.apply(void 0, [_b.sent(), 1]), result = _a[0]; + return [2 /*return*/, result ? result.$expr : false]; + } + }); + }); })); }))]; case 4: - _b = tslib_1.__read.apply(void 0, [_c.sent(), 1]), result = _b[0]; - if (!result) { + result2 = _b.sent(); + isLegal = result2.find(function (r1) { return r1.every(function (r2) { return r2 === true; }); }); + if (!isLegal) { // 条件判定为假,抛异常 if (type === 'expression') { throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_2); @@ -176,7 +189,7 @@ function translateCheckerInAsyncContext(checker) { throw new Exception_1.OakUserUnpermittedException(errMsg_2); } } - _c.label = 5; + _b.label = 5; case 5: return [2 /*return*/, 0]; } }); @@ -247,14 +260,19 @@ function translateCheckerInSyncContext(checker) { } else { (0, assert_1.default)(!(exprResult instanceof Promise)); - var expressionEntity = exprResult.entity, expr = exprResult.expr, expressionFilter = exprResult.filter; - var _a = tslib_1.__read(context.select(expressionEntity, { - data: { - $expr: expr, - }, - filter: expressionFilter, - }, Object.assign({}, option, { dontCollect: true })), 1), result = _a[0]; - if (!result.$expr) { + var result2 = exprResult.map(function (e1) { return e1.map(function (e2) { + var expressionEntity = e2.entity, expr = e2.expr, expressionFilter = e2.filter; + var _a = tslib_1.__read(context.select(expressionEntity, { + data: { + $expr: expr, + }, + filter: expressionFilter, + }, Object.assign({}, option, { dontCollect: true })), 1), result = _a[0]; + return result ? result.$expr : false; + }); }); + // exprResult外层是or,里层是and关系 + var isLegal = result2.find(function (r1) { return r1.every(function (r2) { return r2 === true; }); }); + if (!isLegal) { // 条件判定为假,抛异常 if (type === 'expression') { throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_5); @@ -263,7 +281,6 @@ function translateCheckerInSyncContext(checker) { throw new Exception_1.OakUserUnpermittedException(errMsg_5); } } - return; } }; } @@ -273,35 +290,154 @@ function translateCheckerInSyncContext(checker) { } } exports.translateCheckerInSyncContext = translateCheckerInSyncContext; +function buildReverseHierarchyMap(relationHierarchy) { + var e_1, _a; + var reverseHierarchy = {}; + for (var r in relationHierarchy) { + try { + for (var _b = (e_1 = void 0, tslib_1.__values(relationHierarchy[r])), _c = _b.next(); !_c.done; _c = _b.next()) { + var r2 = _c.value; + if (!reverseHierarchy[r2]) { + reverseHierarchy[r2] = [r]; + } + else { + reverseHierarchy[r2].push(r); + } + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (_c && !_c.done && (_a = _b.return)) _a.call(_b); + } + finally { if (e_1) throw e_1.error; } + } + } + return reverseHierarchy; +} +function translateSingleCascadeRelationItem(schema, lch, entity2, entityId, userId) { + var cascadePath = lch.cascadePath, relations = lch.relations; + var paths = cascadePath.split('.'); + var translateFilterIter = function (entity, iter) { + var _a, _b, _c, _d, _e; + var relation = (0, relation_1.judgeRelation)(schema, entity, paths[iter]); + if (iter === paths.length - 1) { + if (relation === 2) { + return { + entity: paths[iter], + entityId: { + $in: { + entity: "user".concat((0, string_1.firstLetterUpperCase)(paths[iter])), + data: (_a = {}, + _a["".concat(paths[iter], "Id")] = 1, + _a), + filter: { + userId: userId, + relation: { + $in: relations, + }, + }, + }, + } + }; + } + (0, assert_1.default)(typeof relation === 'string'); + return _b = {}, + _b["".concat(paths[iter], "Id")] = { + $in: { + entity: "user".concat((0, string_1.firstLetterUpperCase)(relation)), + data: (_c = {}, + _c["".concat(relation, "Id")] = 1, + _c), + filter: { + userId: userId, + relation: { + $in: relations, + }, + }, + }, + }, + _b; + } + else { + var subFilter = translateFilterIter(paths[iter], iter + 1); + if (iter === 0) { + return _d = {}, + _d[paths[iter]] = subFilter, + _d.id = entityId, + _d; + } + return _e = {}, + _e[paths[iter]] = subFilter, + _e; + } + }; + var filter = translateFilterIter(entity2, 0); + return { + entity: entity2, + filter: filter, + expr: { + $gt: [{ + '#attr': '$$createAt$$', + }, 0] + }, + }; +} +function translateFromCascadeRelationHierarchy(schema, legalCascadeHierarchies, entity, entityId, userId) { + if (legalCascadeHierarchies instanceof Array) { + return legalCascadeHierarchies.map(function (ele) { + if (ele instanceof Array) { + return ele.map(function (ele2) { return translateSingleCascadeRelationItem(schema, ele2, entity, entityId, userId); }); + } + return [translateSingleCascadeRelationItem(schema, ele, entity, entityId, userId)]; + }); + } + else { + return [[translateSingleCascadeRelationItem(schema, legalCascadeHierarchies, entity, entityId, userId)]]; + } +} +function makeRelationExpressionCombination(schema, entity, entityId, userId, relation, reverseHierarchy, reverseCascadeRelationHierarchy) { + var _a; + var userEntityName = "user".concat((0, string_1.firstLetterUpperCase)(entity)); + var entityIdAttr = "".concat(entity, "Id"); + var legalRelations = reverseHierarchy && reverseHierarchy[relation]; + var legalCascadeHierarchies = reverseCascadeRelationHierarchy && reverseCascadeRelationHierarchy[relation]; + if (!legalRelations && !legalCascadeHierarchies) { + return undefined; + } + if ((legalRelations === null || legalRelations === void 0 ? void 0 : legalRelations.length) === 0) { + throw new Error('这是不应该跑出来的情况,请杀程序员祭天'); + } + var expressionCombination = []; + if (legalRelations && legalRelations.length > 0) { + expressionCombination.push([{ + entity: userEntityName, + expr: { + $gt: [{ + '#attr': '$$createAt$$', + }, 0] + }, + filter: (_a = { + userId: userId + }, + _a[entityIdAttr] = entityId, + _a.relation = { + $in: legalRelations, + }, + _a) + }]); + } + if (legalCascadeHierarchies) { + expressionCombination.push.apply(expressionCombination, tslib_1.__spreadArray([], tslib_1.__read(translateFromCascadeRelationHierarchy(schema, legalCascadeHierarchies, entity, entityId, userId)), false)); + } + return expressionCombination; +} function createRelationHierarchyCheckers(schema) { var checkers = []; var _loop_1 = function (entity) { - var e_1, _a; - var relationHierarchy = schema[entity].relationHierarchy; - if (relationHierarchy) { - // 先build反向hierarchy的map - var reverseHierarchy_1 = {}; - for (var r in relationHierarchy) { - try { - for (var _b = (e_1 = void 0, tslib_1.__values(relationHierarchy[r])), _c = _b.next(); !_c.done; _c = _b.next()) { - var r2 = _c.value; - if (!reverseHierarchy_1[r2]) { - reverseHierarchy_1[r2] = [r]; - } - else { - reverseHierarchy_1[r2].push(r); - } - } - } - catch (e_1_1) { e_1 = { error: e_1_1 }; } - finally { - try { - if (_c && !_c.done && (_a = _b.return)) _a.call(_b); - } - finally { if (e_1) throw e_1.error; } - } - } - // 对userEntity对象的授权和回收建立checker + var _a = schema[entity], relationHierarchy = _a.relationHierarchy, reverseCascadeRelationHierarchy = _a.reverseCascadeRelationHierarchy; + if (relationHierarchy || reverseCascadeRelationHierarchy) { + var reverseHierarchy_1 = relationHierarchy && buildReverseHierarchyMap(relationHierarchy); var userEntityName_1 = "user".concat((0, string_1.firstLetterUpperCase)(entity)); var entityIdAttr_1 = "".concat(entity, "Id"); checkers.push({ @@ -309,99 +445,82 @@ function createRelationHierarchyCheckers(schema) { action: 'create', type: 'expressionRelation', expression: function (operation, context) { - var _a; var data = operation.data; - var _b = data, relation = _b.relation, _c = entityIdAttr_1, entityId = _b[_c]; - var legalRelations = reverseHierarchy_1[relation]; - if (!legalRelations) { - return undefined; - } - if (legalRelations.length === 0) { - return '这是不应该跑出来的情况,请杀程序员祭天'; - } + (0, assert_1.default)(!(data instanceof Array)); + var _a = data, relation = _a.relation, _b = entityIdAttr_1, entityId = _a[_b]; var userId = context.getCurrentUserId(); - return { - entity: userEntityName_1, - expr: { - $gt: [{ - '#attr': '$$createAt$$', - }, 0] - }, - filter: (_a = { - userId: userId - }, - _a[entityIdAttr_1] = entityId, - _a.relation = { - $in: legalRelations, - }, - _a) - }; + var schema = context.getSchema(); + return makeRelationExpressionCombination(schema, entity, entityId, userId, relation, reverseHierarchy_1, reverseCascadeRelationHierarchy); }, errMsg: '越权操作', }); - var _loop_2 = function (r) { - checkers.push({ - entity: userEntityName_1, - action: 'remove', - type: 'expressionRelation', - expression: function (operation, context) { - var _a; - var userId = context.getCurrentUserId(); - var filter = operation.filter; - var legalRelations = reverseHierarchy_1[r]; - if (legalRelations.length === 0) { - return '这是不应该跑出来的情况,请杀程序员祭天'; - } - var makeFilterFromRows = function (rows) { - var _a; - var relations = (0, lodash_1.uniq)(rows.map(function (ele) { return ele.relation; })); - var entityIds = (0, lodash_1.uniq)(rows.map(function (ele) { return ele[entityIdAttr_1]; })); - (0, assert_1.default)(entityIds.length === 1, "\u5728\u56DE\u6536".concat(userEntityName_1, "\u4E0A\u6743\u9650\u65F6\uFF0C\u5355\u6B21\u56DE\u6536\u6D89\u53CA\u5230\u4E86\u4E0D\u540C\u7684\u5BF9\u8C61\uFF0C\u6B64\u64CD\u4F5C\u4E0D\u88AB\u5141\u8BB8")); - var legalRelationss = relations.map(function (ele) { - if (reverseHierarchy_1[ele]) { - return reverseHierarchy_1[ele]; + checkers.push({ + entity: userEntityName_1, + action: 'remove', + type: 'expressionRelation', + expression: function (operation, context) { + var _a; + var userId = context.getCurrentUserId(); + var filter = operation.filter; + var makeFilterFromRows = function (rows) { + var relations = (0, lodash_1.uniq)(rows.map(function (ele) { return ele.relation; })); + var entityIds = (0, lodash_1.uniq)(rows.map(function (ele) { return ele[entityIdAttr_1]; })); + (0, assert_1.default)(entityIds.length === 1, "\u5728\u56DE\u6536".concat(userEntityName_1, "\u4E0A\u6743\u9650\u65F6\uFF0C\u5355\u6B21\u56DE\u6536\u6D89\u53CA\u5230\u4E86\u4E0D\u540C\u7684\u5BF9\u8C61\uFF0C\u6B64\u64CD\u4F5C\u4E0D\u88AB\u5141\u8BB8")); + var entityId = entityIds[0]; + var schema = context.getSchema(); + var exprComb = relations.map(function (relation) { return makeRelationExpressionCombination(schema, entity, entityId, userId, relation, reverseHierarchy_1, reverseCascadeRelationHierarchy); }); + // 对每个relation求出其相应的exprComb,此操作对多行进行expr,需要对之进行类似于笛卡尔积的相乘 + var result = exprComb.reduce(function (accu, current) { + var e_2, _a, e_3, _b; + if (!current) { + return accu; + } + var result2 = []; + try { + for (var current_1 = (e_2 = void 0, tslib_1.__values(current)), current_1_1 = current_1.next(); !current_1_1.done; current_1_1 = current_1.next()) { + var c = current_1_1.value; + try { + for (var _c = (e_3 = void 0, tslib_1.__values(accu)), _d = _c.next(); !_d.done; _d = _c.next()) { + var a = _d.value; + result2.push(a.concat(c)); + } + } + catch (e_3_1) { e_3 = { error: e_3_1 }; } + finally { + try { + if (_d && !_d.done && (_b = _c.return)) _b.call(_c); + } + finally { if (e_3) throw e_3.error; } + } } - (0, assert_1.default)(false, "\u5728\u56DE\u6536".concat(userEntityName_1, "\u4E0A\u7C7B\u578B\u4E3A").concat(ele, "\u7684\u6743\u9650\u65F6\uFF0C\u627E\u4E0D\u5230\u5BF9\u5E94\u7684\u5B9A\u4E49\uFF0C\u4E0D\u5E94\u8BE5\u51FA\u73B0\u7684\u60C5\u51B5")); - }); - // 如果要删除多个不同的权限,这里必须要有它们共同的上级权限 - var legaRelations = (0, lodash_1.intersection)(legalRelationss); - return { - entity: userEntityName_1, - expr: { - $gt: [{ - '#attr': '$$createAt$$', - }, 0] - }, - filter: (_a = { - userId: userId - }, - _a[entityIdAttr_1] = entityIds[0], - _a.relation = { - $in: legaRelations, - }, - _a), - }; - }; - var toBeRemoved = context.select(userEntityName_1, { - data: (_a = { - id: 1, - relation: 1 - }, - _a[entityIdAttr_1] = 1, - _a), - filter: filter, - }, { dontCollect: true }); - if (toBeRemoved instanceof Promise) { - return toBeRemoved.then(function (rows) { return makeFilterFromRows(rows); }); - } - return makeFilterFromRows(toBeRemoved); - }, - errMsg: '越权操作', - }); - }; - for (var r in reverseHierarchy_1) { - _loop_2(r); - } + } + catch (e_2_1) { e_2 = { error: e_2_1 }; } + finally { + try { + if (current_1_1 && !current_1_1.done && (_a = current_1.return)) _a.call(current_1); + } + finally { if (e_2) throw e_2.error; } + } + return result2; + }, [[]]); + return result && result.length > 0 ? result : undefined; + }; + var toBeRemoved = context.select(userEntityName_1, { + data: (_a = { + id: 1, + relation: 1 + }, + _a[entityIdAttr_1] = 1, + _a), + filter: filter, + }, { dontCollect: true }); + if (toBeRemoved instanceof Promise) { + return toBeRemoved.then(function (rows) { return makeFilterFromRows(rows); }); + } + return makeFilterFromRows(toBeRemoved); + }, + errMsg: '越权操作', + }); /* // 一个人不能授权给自己,也不能删除自己的授权 checkers.push({ entity: userEntityName as keyof ED, @@ -416,7 +535,7 @@ function createRelationHierarchyCheckers(schema) { } } }); - + checkers.push({ entity: userEntityName as keyof ED, action: 'remove' as ED[keyof ED]['Action'], diff --git a/lib/types/Auth.d.ts b/lib/types/Auth.d.ts index d43e665..f76d0dc 100644 --- a/lib/types/Auth.d.ts +++ b/lib/types/Auth.d.ts @@ -37,17 +37,18 @@ export declare type RelationChecker ED[T]['Update']['filter'] | Promise); }; -declare type ExpressionResult = { +export declare type ExpressionTask = { entity: T; expr: RefOrExpression; filter: ED[T]['Selection']['filter']; }; +export declare type ExpressionTaskCombination = ExpressionTask[][]; export declare type ExpressionChecker | SyncContext> = { priority?: number; type: 'expression'; entity: T; action: ED[T]['Action'] | Array; - expression: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ExpressionResult | Promise> | undefined | string; + expression: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ExpressionTaskCombination | undefined | string | Promise | string | undefined>; errMsg: string; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); }; @@ -56,9 +57,8 @@ export declare type ExpressionRelationChecker; - expression: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ExpressionResult | Promise> | undefined | string; + expression: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ExpressionTaskCombination | undefined | string | Promise | string | undefined>; errMsg: string; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); }; export declare type Checker | SyncContext> = DataChecker | RowChecker | RelationChecker | ExpressionChecker | ExpressionRelationChecker; -export {}; diff --git a/lib/types/Entity.d.ts b/lib/types/Entity.d.ts index b49b463..a7a7df6 100644 --- a/lib/types/Entity.d.ts +++ b/lib/types/Entity.d.ts @@ -153,6 +153,13 @@ export declare type RemoveOpResult = export declare type RelationHierarchy = { [K in R]?: R[]; }; +export declare type CascadeRelationItem = { + cascadePath: string; + relations: string[]; +}; +export declare type ReverseCascadeRelationHierarchy = { + [K in R]?: CascadeRelationItem | (CascadeRelationItem | CascadeRelationItem[])[]; +}; export declare type SelectOpResult = { a: 's'; d: { diff --git a/lib/types/Storage.d.ts b/lib/types/Storage.d.ts index e082f77..854bfb6 100644 --- a/lib/types/Storage.d.ts +++ b/lib/types/Storage.d.ts @@ -1,5 +1,5 @@ import { ActionType } from '.'; -import { EntityDict, EntityShape, InstinctiveAttributes, RelationHierarchy } from './Entity'; +import { EntityDict, EntityShape, InstinctiveAttributes, RelationHierarchy, ReverseCascadeRelationHierarchy } from './Entity'; import { DataType, DataTypeParams } from './schema/DataTypes'; export declare type Ref = 'ref'; export interface Column { @@ -49,6 +49,7 @@ export interface StorageDesc, entity: string) { const reverseOneNodes: ts.TypeNode[] = []; if (ReversePointerEntities[entity]) { if (ReversePointerRelations[entity]) { + const { schemaAttrs } = Schema[entity]; + const { questionToken } = schemaAttrs.find( + ele => { + const { name } = ele; + return (name).text === 'entity' + } + )!; for (const one of ReversePointerRelations[entity]) { const cascadeCreateNode = factory.createTypeLiteralNode( [ @@ -3136,14 +3162,14 @@ function constructActions(statements: Array, entity: string) { factory.createPropertySignature( undefined, factory.createIdentifier('entity'), - undefined, // 反向指针好像不能为空,以后或许会有特例 by Xc + questionToken, factory.createLiteralTypeNode(factory.createStringLiteral(`${firstLetterLowerCase(one)}`) ) ), factory.createPropertySignature( undefined, factory.createIdentifier('entityId'), - undefined, // 反向指针好像不能为空,以后或许会有特例 by Xc + questionToken, factory.createTypeReferenceNode( factory.createIdentifier("String"), [factory.createLiteralTypeNode(factory.createNumericLiteral("64"))] @@ -5638,7 +5664,7 @@ function outputStorage(outputDir: string, printer: ts.Printer) { for (const entity in Schema) { const indexExpressions: ts.Expression[] = []; - const { sourceFile, inModi, indexes, toModi, actionType, static: _static, relationHierarchy } = Schema[entity]; + const { sourceFile, inModi, indexes, toModi, actionType, static: _static, relationHierarchy, reverseCascadeRelationHierarchy } = Schema[entity]; const fromSchemaSpecifiers = [ factory.createImportSpecifier( false, @@ -5646,7 +5672,7 @@ function outputStorage(outputDir: string, printer: ts.Printer) { factory.createIdentifier("OpSchema") ) ]; - if (relationHierarchy) { + if (relationHierarchy || reverseCascadeRelationHierarchy) { fromSchemaSpecifiers.push( factory.createImportSpecifier( false, @@ -5863,6 +5889,14 @@ function outputStorage(outputDir: string, printer: ts.Printer) { ) ); } + if (reverseCascadeRelationHierarchy) { + propertyAssignments.push( + factory.createPropertyAssignment( + factory.createIdentifier("reverseCascadeRelationHierarchy"), + reverseCascadeRelationHierarchy, + ) + ); + } const sdTypeArguments = [ factory.createTypeReferenceNode( factory.createIdentifier("OpSchema"), diff --git a/src/store/checker.ts b/src/store/checker.ts index 97c7609..2dfc7b2 100644 --- a/src/store/checker.ts +++ b/src/store/checker.ts @@ -1,13 +1,14 @@ import assert from 'assert'; import { addFilterSegment, checkFilterContains, combineFilters } from "../store/filter"; import { OakDataException, OakRowInconsistencyException, OakUserUnpermittedException } from '../types/Exception'; -import { Checker, CreateTriggerInTxn, EntityDict, ExpressionRelationChecker, OperateOption, RefOrExpression, SelectOption, StorageSchema, Trigger, UpdateTriggerInTxn } from "../types"; +import { CascadeRelationItem, Checker, CreateTriggerInTxn, EntityDict, ExpressionRelationChecker, ExpressionTask, ExpressionTaskCombination, OperateOption, RefOrExpression, RelationHierarchy, ReverseCascadeRelationHierarchy, SelectOption, StorageSchema, Trigger, UpdateTriggerInTxn } from "../types"; import { EntityDict as BaseEntityDict } from '../base-app-domain'; import { AsyncContext } from "./AsyncRowStore"; import { getFullProjection } from './actionDef'; import { SyncContext } from './SyncRowStore'; import { firstLetterUpperCase } from '../utils/string'; import { intersection, uniq } from '../utils/lodash'; +import { judgeRelation } from './relation'; export function translateCheckerInAsyncContext< ED extends EntityDict & BaseEntityDict, @@ -93,8 +94,8 @@ export function translateCheckerInAsyncContext< operation.filter = combineFilters([operation.filter, await relationFilter(operation, context, option)]); return 0; }) as UpdateTriggerInTxn['fn']; - } - case 'expression': + } + case 'expression': case 'expressionRelation': { const { expression, errMsg } = checker; return (async ({ operation }, context, option) => { @@ -109,14 +110,31 @@ export function translateCheckerInAsyncContext< return 0; } else { - const { entity: expressionEntity, expr, filter: expressionFilter } = exprResult; - const [result] = await context.select(expressionEntity, { - data: { - $expr: expr, - }, - filter: expressionFilter, - }, Object.assign({}, option, { dontCollect: true })); - if (!result) { + const result2 = await Promise.all( + exprResult.map( + (e1) => Promise.all( + e1.map( + async (e2) => { + const { entity: expressionEntity, expr, filter: expressionFilter } = e2; + const [result] = await context.select(expressionEntity, { + data: { + $expr: expr, + }, + filter: expressionFilter, + }, Object.assign({}, option, { dontCollect: true })); + return result ? result.$expr as boolean : false; + } + ) + ) + ) + ); + // exprResult外层是or,里层是and关系 + const isLegal = result2.find( + (r1) => r1.every( + (r2) => r2 === true + ) + ); + if (!isLegal) { // 条件判定为假,抛异常 if (type === 'expression') { throw new OakRowInconsistencyException(undefined, errMsg); @@ -180,8 +198,8 @@ export function translateCheckerInSyncContext< } throw new OakUserUnpermittedException(errMsg); }; - } - case 'expression': + } + case 'expression': case 'expressionRelation': { const { expression, errMsg } = checker; return (operation, context, option) => { @@ -197,14 +215,27 @@ export function translateCheckerInSyncContext< } else { assert(!(exprResult instanceof Promise)); - const { entity: expressionEntity, expr, filter: expressionFilter } = exprResult; - const [result] = context.select(expressionEntity, { - data: { - $expr: expr, - }, - filter: expressionFilter, - }, Object.assign({}, option, { dontCollect: true })) as any[]; - if (!result.$expr) { + const result2 = exprResult.map( + (e1) => e1.map( + (e2) => { + const { entity: expressionEntity, expr, filter: expressionFilter } = e2; + const [result] = context.select(expressionEntity, { + data: { + $expr: expr, + }, + filter: expressionFilter, + }, Object.assign({}, option, { dontCollect: true })); + return result ? result.$expr as boolean : false; + } + ) + ); + // exprResult外层是or,里层是and关系 + const isLegal = result2.find( + (r1) => r1.every( + (r2) => r2 === true + ) + ); + if (!isLegal) { // 条件判定为假,抛异常 if (type === 'expression') { throw new OakRowInconsistencyException(undefined, errMsg); @@ -213,7 +244,6 @@ export function translateCheckerInSyncContext< throw new OakUserUnpermittedException(errMsg); } } - return; } }; } @@ -224,26 +254,174 @@ export function translateCheckerInSyncContext< } +function buildReverseHierarchyMap(relationHierarchy: RelationHierarchy) { + const reverseHierarchy = {} as Record; + for (const r in relationHierarchy) { + for (const r2 of relationHierarchy[r]!) { + if (!reverseHierarchy[r2]) { + reverseHierarchy[r2] = [r]; + } + else { + reverseHierarchy[r2].push(r); + } + } + } + return reverseHierarchy; +} + +function translateSingleCascadeRelationItem( + schema: StorageSchema, + lch: CascadeRelationItem, + entity2: keyof ED, + entityId: string, + userId: string): ExpressionTask { + const { cascadePath, relations } = lch; + const paths = cascadePath.split('.'); + + const translateFilterIter = (entity: keyof ED, iter: number): ED[T]['Selection']['filter'] => { + const relation = judgeRelation(schema, entity, paths[iter]); + if (iter === paths.length - 1) { + if (relation === 2) { + return { + entity: paths[iter], + entityId: { + $in: { + entity: `user${firstLetterUpperCase(paths[iter])}`, + data: { + [`${paths[iter]}Id`]: 1, + }, + filter: { + userId, + relation: { + $in: relations, + }, + }, + }, + } + }; + } + assert(typeof relation === 'string'); + return { + [`${paths[iter]}Id`]: { + $in: { + entity: `user${firstLetterUpperCase(relation)}`, + data: { + [`${relation}Id`]: 1, + }, + filter: { + userId, + relation: { + $in: relations, + }, + }, + }, + } + }; + } + else { + const subFilter = translateFilterIter(paths[iter], iter + 1); + if (iter === 0) { + return { + [paths[iter]]: subFilter, + id: entityId, + }; + } + return { + [paths[iter]]: subFilter, + }; + } + }; + const filter = translateFilterIter(entity2, 0); + return { + entity: entity2, + filter, + expr: { + $gt: [{ + '#attr': '$$createAt$$', + }, 0] + }, + }; +} + +function translateFromCascadeRelationHierarchy( + schema: StorageSchema, + legalCascadeHierarchies: CascadeRelationItem | (CascadeRelationItem | CascadeRelationItem[])[], + entity: keyof ED, + entityId: string, + userId: string): ExpressionTaskCombination { + if (legalCascadeHierarchies instanceof Array) { + return legalCascadeHierarchies.map( + ele => { + if (ele instanceof Array) { + return ele.map( + ele2 => translateSingleCascadeRelationItem(schema, ele2, entity, entityId, userId) + ); + } + return [translateSingleCascadeRelationItem(schema, ele, entity, entityId, userId)]; + } + ) + } + else { + return [[translateSingleCascadeRelationItem(schema, legalCascadeHierarchies, entity, entityId, userId)]]; + } +} + +function makeRelationExpressionCombination( + schema: StorageSchema, + entity: keyof ED, + entityId: string, + userId: string, + relation: string, + reverseHierarchy?: Record, + reverseCascadeRelationHierarchy?: ReverseCascadeRelationHierarchy, +) { + const userEntityName = `user${firstLetterUpperCase(entity as string)}`; + const entityIdAttr = `${entity as string}Id`; + const legalRelations = reverseHierarchy && reverseHierarchy[relation]; + const legalCascadeHierarchies = reverseCascadeRelationHierarchy && reverseCascadeRelationHierarchy[relation]; + if (!legalRelations && !legalCascadeHierarchies) { + return undefined; + } + if (legalRelations?.length === 0) { + throw new Error('这是不应该跑出来的情况,请杀程序员祭天'); + } + const expressionCombination: ExpressionTaskCombination = []; + if (legalRelations && legalRelations.length > 0) { + expressionCombination.push([{ + entity: userEntityName as keyof ED, + expr: { + $gt: [{ + '#attr': '$$createAt$$', + }, 0] + }, + filter: { + userId, + [entityIdAttr]: entityId, + relation: { + $in: legalRelations, + } + } + }]); + } + if (legalCascadeHierarchies) { + expressionCombination.push(...translateFromCascadeRelationHierarchy( + schema, + legalCascadeHierarchies, + entity, + entityId, + userId! + )); + } + return expressionCombination; +} + export function createRelationHierarchyCheckers | SyncContext>(schema: StorageSchema) { const checkers: Checker[] = []; for (const entity in schema) { - const { relationHierarchy } = schema[entity]; - if (relationHierarchy) { - // 先build反向hierarchy的map - const reverseHierarchy = {} as Record; - for (const r in relationHierarchy) { - for (const r2 of relationHierarchy[r]!) { - if (!reverseHierarchy[r2]) { - reverseHierarchy[r2] = [r]; - } - else { - reverseHierarchy[r2].push(r); - } - } - } - - // 对userEntity对象的授权和回收建立checker + const { relationHierarchy, reverseCascadeRelationHierarchy } = schema[entity]; + if (relationHierarchy || reverseCascadeRelationHierarchy) { + const reverseHierarchy = relationHierarchy && buildReverseHierarchyMap(relationHierarchy); const userEntityName = `user${firstLetterUpperCase(entity)}`; const entityIdAttr = `${entity}Id`; checkers.push({ @@ -251,95 +429,76 @@ export function createRelationHierarchyCheckers(operation: any, context: Cxt) => { - const { data } = operation as ED[keyof ED]['Operation']; - const { relation, [entityIdAttr]: entityId } = data as Record; - const legalRelations = reverseHierarchy[relation]; - if (!legalRelations) { - return undefined; - } - if (legalRelations.length === 0) { - return '这是不应该跑出来的情况,请杀程序员祭天'; - } + const { data } = operation as ED[keyof ED]['Create']; + assert(!(data instanceof Array)); + const { relation, [entityIdAttr]: entityId } = data; const userId = context.getCurrentUserId(); - return { - entity: userEntityName as T2, - expr: { - $gt: [{ - '#attr': '$$createAt$$', - }, 0] - }, - filter: { - userId, - [entityIdAttr]: entityId, - relation: { - $in: legalRelations, - } - } - } + const schema = context.getSchema(); + return makeRelationExpressionCombination(schema, entity, entityId, userId!, relation, reverseHierarchy, reverseCascadeRelationHierarchy); }, errMsg: '越权操作', }); - for (const r in reverseHierarchy) { - checkers.push({ - entity: userEntityName as keyof ED, - action: 'remove', - type: 'expressionRelation', - expression: (operation: any, context: Cxt) => { - const userId = context.getCurrentUserId(); - const { filter } = operation as ED[keyof ED]['Remove']; - const legalRelations = reverseHierarchy[r]; - if (legalRelations.length === 0) { - return '这是不应该跑出来的情况,请杀程序员祭天'; - } - const makeFilterFromRows = (rows: Partial[]) => { - const relations = uniq(rows.map(ele => ele.relation)); - const entityIds = uniq(rows.map(ele => ele[entityIdAttr])); - assert(entityIds.length === 1, `在回收${userEntityName}上权限时,单次回收涉及到了不同的对象,此操作不被允许`); - const legalRelationss = relations.map( - ele => { - if (reverseHierarchy[ele!]) { - return reverseHierarchy[ele!]; - } - assert(false, `在回收${userEntityName}上类型为${ele}的权限时,找不到对应的定义,不应该出现的情况`); + checkers.push({ + entity: userEntityName as keyof ED, + action: 'remove', + type: 'expressionRelation', + expression: (operation: any, context: Cxt) => { + const userId = context.getCurrentUserId(); + const { filter } = operation as ED[keyof ED]['Remove']; + const makeFilterFromRows = (rows: Partial[]) => { + 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]!; + const schema = context.getSchema(); + const exprComb = relations.map( + (relation) => makeRelationExpressionCombination( + schema, + entity, + entityId, + userId!, + relation!, + reverseHierarchy, + reverseCascadeRelationHierarchy, + ) + ); + // 对每个relation求出其相应的exprComb,此操作对多行进行expr,需要对之进行类似于笛卡尔积的相乘 + const result = exprComb.reduce( + (accu, current) => { + if (!current) { + return accu; } - ); - // 如果要删除多个不同的权限,这里必须要有它们共同的上级权限 - const legaRelations = intersection(legalRelationss); - return { - entity: userEntityName as T2, - expr: { - $gt: [{ - '#attr': '$$createAt$$', - }, 0] - } as RefOrExpression, - filter: { - userId, - [entityIdAttr]: entityIds[0], - relation: { - $in: legaRelations, + const result2 = [] as ExpressionTaskCombination; + for (const c of current) { + for (const a of accu!) { + result2.push(a.concat(c)); } - }, - } - }; - - const toBeRemoved = context.select(userEntityName, { - data: { - id: 1, - relation: 1, - [entityIdAttr]: 1, + } + return result2; }, - filter, - }, { dontCollect: true }); - if (toBeRemoved instanceof Promise) { - return toBeRemoved.then( - (rows) => makeFilterFromRows(rows) - ); - } - return makeFilterFromRows(toBeRemoved); - }, - errMsg: '越权操作', - }); - } + [[]] as ExpressionTaskCombination, + ); + + return result && result.length > 0 ? result : undefined; + }; + + 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: '越权操作', + }); /* // 一个人不能授权给自己,也不能删除自己的授权 checkers.push({ @@ -355,7 +514,7 @@ export function createRelationHierarchyCheckers = { +export type ExpressionTask = { entity: T; expr: RefOrExpression; filter: ED[T]['Selection']['filter']; }; +export type ExpressionTaskCombination = ExpressionTask[][]; + export type ExpressionChecker | SyncContext> = { priority?: number; type: 'expression'; @@ -65,7 +67,7 @@ export type ExpressionChecker ExpressionResult | Promise> | undefined | string; // 生成一个带表达式的查询任务,结果为true代表可以过,为false不可以。如果返回undefined直接过,返回string直接挂 + ) => ExpressionTaskCombination | undefined | string | Promise | string | undefined> ; // 生成一个带表达式的查询任务数组,表达式结果为true代表可以过(or关系)。如果返回undefined直接过,返回string直接挂 errMsg: string; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); }; @@ -79,7 +81,7 @@ export type ExpressionRelationChecker ExpressionResult | Promise> | undefined | string; // 生成一个带表达式的查询任务,结果为true代表可以过。如果返回undefined直接过,返回string直接挂 + ) => ExpressionTaskCombination | undefined | string | Promise | string | undefined> ; // 生成一个带表达式的查询任务数组,表达式结果为true代表可以过(or关系)。如果返回undefined直接过,返回string直接挂 errMsg: string; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); }; diff --git a/src/types/Entity.ts b/src/types/Entity.ts index 1cff913..550603c 100644 --- a/src/types/Entity.ts +++ b/src/types/Entity.ts @@ -205,6 +205,15 @@ export type RelationHierarchy = { [K in R]?: R[]; }; +export type CascadeRelationItem = { + cascadePath: string; + relations: string[]; +}; + +export type ReverseCascadeRelationHierarchy = { + [K in R]?: CascadeRelationItem | (CascadeRelationItem | CascadeRelationItem[])[]; +}; + // Select的级联可以去重,压缩返回的数据大小 export type SelectOpResult = { a: 's', diff --git a/src/types/Storage.ts b/src/types/Storage.ts index 234253c..341b1c0 100644 --- a/src/types/Storage.ts +++ b/src/types/Storage.ts @@ -1,5 +1,5 @@ import { ActionType } from '.'; -import { EntityDict, EntityShape, InstinctiveAttributes, RelationHierarchy } from './Entity'; +import { EntityDict, EntityShape, InstinctiveAttributes, RelationHierarchy, ReverseCascadeRelationHierarchy } from './Entity'; import { DataType, DataTypeParams } from './schema/DataTypes'; export type Ref = 'ref'; @@ -60,6 +60,7 @@ export interface StorageDesc = { @@ -12,3 +13,10 @@ export declare type ActionDictOfEntityDict = { [A in keyof E[T]['OpSchema']]?: ActionDef; }; }; +export declare type CascadeActionItem = { + cascadePath: string; + relation: string[]; +}; +export declare type CascadeActionAuth = { + [K in A | GenericAction]?: CascadeActionItem | (CascadeActionItem | CascadeActionItem[])[]; +}; diff --git a/lib/types/Entity.d.ts b/lib/types/Entity.d.ts index a7a7df6..9c191cd 100644 --- a/lib/types/Entity.d.ts +++ b/lib/types/Entity.d.ts @@ -179,19 +179,4 @@ export declare type Configuration = { actionType?: ActionType; static?: boolean; }; -export declare type Exportation = { - name: string; - id: string; - entity: T; - projection: ED[T]['Selection']['data']; - headers: K[]; - fn: (data: ED[T]['Schema']) => Partial>; -}; -export declare type Importation = { - name: string; - id: string; - entity: T; - headers: K[]; - fn: (data: Partial>) => ED[T]['CreateSingle']['data']; -}; export {}; diff --git a/lib/types/Exception.d.ts b/lib/types/Exception.d.ts index 67eeb5e..13bdcb9 100644 --- a/lib/types/Exception.d.ts +++ b/lib/types/Exception.d.ts @@ -5,6 +5,11 @@ export declare class OakException extends Error { } export declare class OakDataException extends OakException { } +export declare class OakImportDataParseException extends OakException { + line: number; + header?: string; + constructor(message: string, line: number, header?: string); +} export declare class OakOperExistedException extends OakDataException { } export declare class OakRowUnexistedException extends OakDataException { diff --git a/lib/types/Exception.js b/lib/types/Exception.js index 6cceffc..33d3e27 100644 --- a/lib/types/Exception.js +++ b/lib/types/Exception.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.makeException = exports.OakDeadlock = exports.OakCongruentRowExists = exports.OakRowLockedException = exports.OakUnloggedInException = exports.OakUserUnpermittedException = exports.OakInputIllegalException = exports.OakRowInconsistencyException = exports.OakUserException = exports.OakExternalException = exports.OakRowUnexistedException = exports.OakOperExistedException = exports.OakDataException = exports.OakException = void 0; +exports.makeException = exports.OakDeadlock = exports.OakCongruentRowExists = exports.OakRowLockedException = exports.OakUnloggedInException = exports.OakUserUnpermittedException = exports.OakInputIllegalException = exports.OakRowInconsistencyException = exports.OakUserException = exports.OakExternalException = exports.OakRowUnexistedException = exports.OakOperExistedException = exports.OakImportDataParseException = exports.OakDataException = exports.OakException = void 0; var tslib_1 = require("tslib"); var OakException = /** @class */ (function (_super) { tslib_1.__extends(OakException, _super); @@ -36,6 +36,18 @@ var OakDataException = /** @class */ (function (_super) { return OakDataException; }(OakException)); exports.OakDataException = OakDataException; +var OakImportDataParseException = /** @class */ (function (_super) { + tslib_1.__extends(OakImportDataParseException, _super); + // message必传,描述具体错误的数据内容 + function OakImportDataParseException(message, line, header) { + var _this = _super.call(this, message) || this; + _this.line = line; + _this.header = header; + return _this; + } + return OakImportDataParseException; +}(OakException)); +exports.OakImportDataParseException = OakImportDataParseException; var OakOperExistedException = /** @class */ (function (_super) { tslib_1.__extends(OakOperExistedException, _super); function OakOperExistedException() { @@ -245,6 +257,9 @@ function makeException(data) { case 'OakDeadlock': { return new OakDeadlock(data.message); } + case 'OakImportDataParseException': { + return new OakImportDataParseException(data.message, data.line, data.header); + } default: return; } diff --git a/lib/types/Port.d.ts b/lib/types/Port.d.ts new file mode 100644 index 0000000..8e0519a --- /dev/null +++ b/lib/types/Port.d.ts @@ -0,0 +1,17 @@ +import { AsyncContext } from "../store/AsyncRowStore"; +import { EntityDict } from "./Entity"; +export declare type Exportation = { + name: string; + id: string; + entity: T; + projection: ED[T]['Selection']['data']; + headers: K[]; + fn: (data: ED[T]['Schema']) => Partial>; +}; +export declare type Importation = { + name: string; + id: string; + entity: T; + headers: K[]; + fn: (data: Partial>[], context: AsyncContext, option?: Record) => Promise; +}; diff --git a/lib/types/Port.js b/lib/types/Port.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/lib/types/Port.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/lib/types/index.d.ts b/lib/types/index.d.ts index bace749..99c3b3e 100644 --- a/lib/types/index.d.ts +++ b/lib/types/index.d.ts @@ -17,3 +17,4 @@ export * from './Watcher'; export * from './AppLoader'; export * from './Connector'; export * from './Timer'; +export * from './Port'; diff --git a/lib/types/index.js b/lib/types/index.js index 12853e8..3071cfa 100644 --- a/lib/types/index.js +++ b/lib/types/index.js @@ -20,3 +20,4 @@ tslib_1.__exportStar(require("./Watcher"), exports); tslib_1.__exportStar(require("./AppLoader"), exports); tslib_1.__exportStar(require("./Connector"), exports); tslib_1.__exportStar(require("./Timer"), exports); +tslib_1.__exportStar(require("./Port"), exports); diff --git a/src/types/Action.ts b/src/types/Action.ts index 8d2aa35..2a8d522 100644 --- a/src/types/Action.ts +++ b/src/types/Action.ts @@ -1,4 +1,5 @@ import { EntityDict } from "./Entity"; +import { GenericAction } from '../actions/action'; export type Action = string; export type State = string; @@ -14,4 +15,13 @@ export type ActionDictOfEntityDict = { [T in keyof E]?: { [A in keyof E[T]['OpSchema']]?: ActionDef; }; -}; \ No newline at end of file +}; + +export type CascadeActionItem = { + cascadePath: string; + relation: string[]; +} + +export type CascadeActionAuth = { + [K in A | GenericAction]?: CascadeActionItem | (CascadeActionItem | CascadeActionItem[])[]; +}; diff --git a/src/types/Entity.ts b/src/types/Entity.ts index 550603c..c756b73 100644 --- a/src/types/Entity.ts +++ b/src/types/Entity.ts @@ -259,20 +259,3 @@ export type Configuration = { actionType?: ActionType; static?: boolean; // 标识是维表(变动较小,相对独立) }; - -export type Exportation = { - name: string; - id: string; - entity: T; - projection: ED[T]['Selection']['data']; - headers: K[]; - fn: (data: ED[T]['Schema']) => Partial>; -}; - -export type Importation = { - name: string; - id: string; - entity: T; - headers: K[]; - fn: (data: Partial>) => ED[T]['CreateSingle']['data']; -}; \ No newline at end of file diff --git a/src/types/Exception.ts b/src/types/Exception.ts index b97fcbb..8ef5b78 100644 --- a/src/types/Exception.ts +++ b/src/types/Exception.ts @@ -26,6 +26,18 @@ export class OakDataException extends OakException { // 表示由数据层发现的异常 } +export class OakImportDataParseException extends OakException { + line: number; + header?: string; + + // message必传,描述具体错误的数据内容 + constructor(message: string, line: number, header?: string) { + super(message); + this.line = line; + this.header = header; + } +} + export class OakOperExistedException extends OakDataException { // 进行操作时发现同样id的Oper对象已经存在 } @@ -220,6 +232,9 @@ export function makeException(data: { case 'OakDeadlock': { return new OakDeadlock(data.message); } + case 'OakImportDataParseException': { + return new OakImportDataParseException(data.message!, data.line, data.header); + } default: return; } diff --git a/src/types/Port.ts b/src/types/Port.ts new file mode 100644 index 0000000..eef5054 --- /dev/null +++ b/src/types/Port.ts @@ -0,0 +1,20 @@ +import { AsyncContext } from "../store/AsyncRowStore"; +import { SyncContext } from "../store/SyncRowStore"; +import { EntityDict } from "./Entity"; + +export type Exportation = { + name: string; + id: string; + entity: T; + projection: ED[T]['Selection']['data']; + headers: K[]; + fn: (data: ED[T]['Schema']) => Partial>; +}; + +export type Importation = { + name: string; + id: string; + entity: T; + headers: K[]; + fn: (data: Partial>[], context: AsyncContext, option?: Record ) => Promise; +}; \ No newline at end of file diff --git a/src/types/index.ts b/src/types/index.ts index 6ff1a97..9d33733 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -16,4 +16,5 @@ export * from './Exception'; export * from './Watcher'; export * from './AppLoader'; export * from './Connector'; -export * from './Timer'; \ No newline at end of file +export * from './Timer'; +export * from './Port'; \ No newline at end of file From bd8fd47df52ca507801cb9f843021d68e4312920 Mon Sep 17 00:00:00 2001 From: "Xc@centOs" Date: Tue, 17 Jan 2023 19:09:57 +0800 Subject: [PATCH 08/19] =?UTF-8?q?checker=E4=B8=AD=E5=AF=B9actionAuth?= =?UTF-8?q?=E7=9A=84=E5=A4=84=E7=90=86,=E6=9C=AA=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/checkers/index.d.ts | 4 +- lib/checkers/index.js | 6 +- lib/compiler/schemalBuilder.js | 87 +++--- lib/store/checker.d.ts | 4 +- lib/store/checker.js | 475 +++++++++++++++---------------- lib/types/Action.d.ts | 8 +- lib/types/Auth.d.ts | 10 +- lib/types/Entity.d.ts | 7 +- lib/types/Storage.d.ts | 9 +- src/checkers/index.ts | 10 +- src/compiler/schemalBuilder.ts | 55 ++-- src/store/checker.ts | 501 +++++++++++++++------------------ src/types/Action.ts | 10 +- src/types/Auth.ts | 13 +- src/types/Entity.ts | 7 +- src/types/Port.ts | 1 + src/types/Storage.ts | 11 +- 17 files changed, 597 insertions(+), 621 deletions(-) diff --git a/lib/checkers/index.d.ts b/lib/checkers/index.d.ts index c5b376c..38ec478 100644 --- a/lib/checkers/index.d.ts +++ b/lib/checkers/index.d.ts @@ -1,5 +1,5 @@ import { EntityDict } from '../base-app-domain'; import { AsyncContext } from '../store/AsyncRowStore'; import { SyncContext } from '../store/SyncRowStore'; -import { StorageSchema, EntityDict as BaseEntityDict, Checker } from '../types'; -export declare function createDynamicCheckers | SyncContext>(schema: StorageSchema): Checker[]; +import { StorageSchema, EntityDict as BaseEntityDict, Checker, AuthDefDict } from '../types'; +export declare function createDynamicCheckers | SyncContext>(schema: StorageSchema, authDict?: AuthDefDict): Checker[]; diff --git a/lib/checkers/index.js b/lib/checkers/index.js index 428ed0d..3c7f105 100644 --- a/lib/checkers/index.js +++ b/lib/checkers/index.js @@ -4,10 +4,12 @@ exports.createDynamicCheckers = void 0; var tslib_1 = require("tslib"); var checker_1 = require("../store/checker"); var modi_1 = require("../store/modi"); -function createDynamicCheckers(schema) { +function createDynamicCheckers(schema, authDict) { var checkers = []; checkers.push.apply(checkers, tslib_1.__spreadArray([], tslib_1.__read((0, modi_1.createModiRelatedCheckers)(schema)), false)); - checkers.push.apply(checkers, tslib_1.__spreadArray([], tslib_1.__read((0, checker_1.createRelationHierarchyCheckers)(schema)), false)); + if (authDict) { + checkers.push.apply(checkers, tslib_1.__spreadArray([], tslib_1.__read((0, checker_1.createAuthCheckers)(schema, authDict)), false)); + } return checkers; } exports.createDynamicCheckers = createDynamicCheckers; diff --git a/lib/compiler/schemalBuilder.js b/lib/compiler/schemalBuilder.js index e9b1b10..0d3a8af 100644 --- a/lib/compiler/schemalBuilder.js +++ b/lib/compiler/schemalBuilder.js @@ -337,8 +337,8 @@ function analyzeEntity(filename, path, program, relativePath) { var localEnumStringTypes = []; var additionalImports = []; var localeDef = undefined; - var relationHierarchy = undefined; - var reverseCascadeRelationHierarchy = undefined; + // let relationHierarchy: ts.ObjectLiteralExpression | undefined = undefined; + // let reverseCascadeRelationHierarchy: ts.ObjectLiteralExpression | undefined = undefined; ts.forEachChild(sourceFile, function (node) { var _a, _b, _c, _d; if (ts.isImportDeclaration(node)) { @@ -796,22 +796,22 @@ function analyzeEntity(filename, path, program, relativePath) { _static = true; // static如果有值只能为true } } - else if (ts.isTypeReferenceNode(declaration.type) && ts.isIdentifier(declaration.type.typeName) && declaration.type.typeName.text === 'RelationHierarchy') { + /* else if (ts.isTypeReferenceNode(declaration.type!) && ts.isIdentifier(declaration.type.typeName) && declaration.type.typeName.text === 'RelationHierarchy') { // RelationHierary - (0, assert_1.default)(hasRelationDef, "".concat(moduleName, "\u4E2D\u7684Relation\u5B9A\u4E49\u5728RelationHierarchy\u4E4B\u540E")); - var initializer = declaration.initializer; - (0, assert_1.default)(ts.isObjectLiteralExpression(initializer), "".concat(moduleName, "\u4E2D\u7684RelationHierarchy\u7684\u5B9A\u4E49\u5FC5\u987B\u662F\u521D\u59CB\u5316\u4E3AObjectLiteralExpress")); + assert(hasRelationDef, `${moduleName}中的Relation定义在RelationHierarchy之后`); + const { initializer } = declaration; + assert(ts.isObjectLiteralExpression(initializer!), `${moduleName}中的RelationHierarchy的定义必须是初始化为ObjectLiteralExpress`); relationHierarchy = initializer; } - else if (ts.isTypeReferenceNode(declaration.type) && ts.isIdentifier(declaration.type.typeName) && declaration.type.typeName.text === 'ReverseCascadeRelationHierarchy') { + else if (ts.isTypeReferenceNode(declaration.type!) && ts.isIdentifier(declaration.type.typeName) && declaration.type.typeName.text === 'ReverseCascadeRelationHierarchy') { // ReverseCascadeRelationHierarchy - (0, assert_1.default)(hasRelationDef, "".concat(moduleName, "\u4E2D\u7684Relation\u5B9A\u4E49\u5728ReverseCascadeRelationHierarchy\u4E4B\u540E")); - var initializer = declaration.initializer; - (0, assert_1.default)(ts.isObjectLiteralExpression(initializer), "".concat(moduleName, "\u4E2D\u7684RelationHierarchy\u7684\u5B9A\u4E49\u5FC5\u987B\u662F\u521D\u59CB\u5316\u4E3AObjectLiteralExpress")); + assert(hasRelationDef, `${moduleName}中的Relation定义在ReverseCascadeRelationHierarchy之后`); + const { initializer } = declaration; + assert(ts.isObjectLiteralExpression(initializer!), `${moduleName}中的RelationHierarchy的定义必须是初始化为ObjectLiteralExpress`); reverseCascadeRelationHierarchy = initializer; - } + } */ else { - throw new Error("".concat(moduleName, "\uFF1A\u4E0D\u80FD\u7406\u89E3\u7684\u5B9A\u4E49\u5185\u5BB9").concat(declaration.name.getText())); + throw new Error("".concat(moduleName, "\uFF1A\u4E0D\u80FD\u7406\u89E3\u7684\u5B9A\u4E49\u5185\u5BB9").concat(declaration.name.text)); } }); } @@ -851,25 +851,25 @@ function analyzeEntity(filename, path, program, relativePath) { locale: localeDef, }); } - if (hasRelationDef) { - if (!relationHierarchy && !reverseCascadeRelationHierarchy) { - console.warn("".concat(filename, "\u4E2D\u5B9A\u4E49\u4E86Relation,\u4F46\u5E76\u6CA1\u6709relationHierarchy\u6216reverseCascadeRelationHierarchy\u7684\u5B9A\u4E49\uFF0C\u8BF7\u6CE8\u610F\u81EA\u4E3B\u7F16\u5199\u6743\u9650\u5206\u914D\u7684checker")); + /* if (hasRelationDef) { + if(!relationHierarchy && !reverseCascadeRelationHierarchy){ + console.warn(`${filename}中定义了Relation,但并没有relationHierarchy或reverseCascadeRelationHierarchy的定义,请注意自主编写权限分配的checker`); } if (relationHierarchy) { - (0, lodash_1.assign)(schema, { - relationHierarchy: relationHierarchy, + assign(schema, { + relationHierarchy, }); } if (reverseCascadeRelationHierarchy) { - (0, lodash_1.assign)(schema, { - reverseCascadeRelationHierarchy: reverseCascadeRelationHierarchy, + assign(schema, { + reverseCascadeRelationHierarchy, }); } } else { - (0, assert_1.default)(!relationHierarchy, "".concat(filename, "\u4E2D\u5177\u6709relationHierarchy\u5B9A\u4E49\u4F46\u6CA1\u6709Relation\u5B9A\u4E49")); - (0, assert_1.default)(!reverseCascadeRelationHierarchy, "".concat(filename, "\u4E2D\u5177\u6709reverseCascadeRelationHierarchy\u5B9A\u4E49\u4F46\u6CA1\u6709Relation\u5B9A\u4E49")); - } + assert(!relationHierarchy, `${filename}中具有relationHierarchy定义但没有Relation定义`); + assert(!reverseCascadeRelationHierarchy, `${filename}中具有reverseCascadeRelationHierarchy定义但没有Relation定义`) + } */ (0, lodash_1.assign)(Schema, (_a = {}, _a[moduleName] = schema, _a)); @@ -3066,13 +3066,19 @@ function outputStorage(outputDir, printer) { var entityAssignments = []; for (var entity in Schema) { var indexExpressions = []; - var _a = Schema[entity], sourceFile = _a.sourceFile, inModi = _a.inModi, indexes = _a.indexes, toModi = _a.toModi, actionType = _a.actionType, _static = _a.static, relationHierarchy = _a.relationHierarchy, reverseCascadeRelationHierarchy = _a.reverseCascadeRelationHierarchy; + var _a = Schema[entity], sourceFile = _a.sourceFile, inModi = _a.inModi, indexes = _a.indexes, toModi = _a.toModi, actionType = _a.actionType, _static = _a.static, hasRelationDef = _a.hasRelationDef; var fromSchemaSpecifiers = [ factory.createImportSpecifier(false, undefined, factory.createIdentifier("OpSchema")) ]; - if (relationHierarchy || reverseCascadeRelationHierarchy) { - fromSchemaSpecifiers.push(factory.createImportSpecifier(false, undefined, factory.createIdentifier("Relation"))); - } + /* if (relationHierarchy || reverseCascadeRelationHierarchy) { + fromSchemaSpecifiers.push( + factory.createImportSpecifier( + false, + undefined, + factory.createIdentifier("Relation") + ) + ); + } */ 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(fromSchemaSpecifiers)), factory.createStringLiteral("./Schema"), undefined) @@ -3131,18 +3137,35 @@ function outputStorage(outputDir, printer) { if (indexExpressions.length > 0) { propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("indexes"), factory.createArrayLiteralExpression(indexExpressions, true))); } - if (relationHierarchy) { - propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("relationHierarchy"), relationHierarchy)); + /* if (relationHierarchy) { + propertyAssignments.push( + factory.createPropertyAssignment( + factory.createIdentifier("relationHierarchy"), + relationHierarchy, + ) + ); } if (reverseCascadeRelationHierarchy) { - propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("reverseCascadeRelationHierarchy"), reverseCascadeRelationHierarchy)); + propertyAssignments.push( + factory.createPropertyAssignment( + factory.createIdentifier("reverseCascadeRelationHierarchy"), + reverseCascadeRelationHierarchy, + ) + ); + } */ + if (hasRelationDef) { + var type = hasRelationDef.type; + (0, assert_1.default)(ts.isUnionTypeNode(type)); + var types = type.types; + var relationTexts = types.map(function (ele) { + (0, assert_1.default)(ts.isLiteralTypeNode(ele) && ts.isStringLiteral(ele.literal)); + return ele.literal.text; + }); + propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("relation"), factory.createArrayLiteralExpression(relationTexts.map(function (ele) { return factory.createStringLiteral(ele); })))); } var sdTypeArguments = [ factory.createTypeReferenceNode(factory.createIdentifier("OpSchema"), undefined) ]; - if (relationHierarchy) { - sdTypeArguments.push(factory.createTypeReferenceNode(factory.createIdentifier("Relation"), undefined)); - } statements.push(factory.createVariableStatement([factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([factory.createVariableDeclaration(factory.createIdentifier("desc"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("StorageDesc"), sdTypeArguments), factory.createObjectLiteralExpression(propertyAssignments, true))], ts.NodeFlags.Const))); var result_2 = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray(statements), sourceFile); var filename_1 = path_1.default.join(outputDir, entity, 'Storage.ts'); diff --git a/lib/store/checker.d.ts b/lib/store/checker.d.ts index 4ad1052..dc7e6fd 100644 --- a/lib/store/checker.d.ts +++ b/lib/store/checker.d.ts @@ -1,7 +1,7 @@ -import { Checker, EntityDict, OperateOption, SelectOption, StorageSchema, Trigger } from "../types"; +import { AuthDefDict, Checker, EntityDict, OperateOption, SelectOption, StorageSchema, Trigger } from "../types"; import { EntityDict as BaseEntityDict } from '../base-app-domain'; import { AsyncContext } from "./AsyncRowStore"; import { SyncContext } from './SyncRowStore'; export declare function translateCheckerInAsyncContext>(checker: Checker): Trigger['fn']; export declare function translateCheckerInSyncContext>(checker: Checker): (operation: ED[T]['Operation'], context: Cxt, option: OperateOption | SelectOption) => void; -export declare function createRelationHierarchyCheckers | SyncContext>(schema: StorageSchema): Checker[]; +export declare function createAuthCheckers | SyncContext>(schema: StorageSchema, authDict: AuthDefDict): Checker[]; diff --git a/lib/store/checker.js b/lib/store/checker.js index 90c533f..5a3b24d 100644 --- a/lib/store/checker.js +++ b/lib/store/checker.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.createRelationHierarchyCheckers = exports.translateCheckerInSyncContext = exports.translateCheckerInAsyncContext = void 0; +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"); @@ -123,6 +123,7 @@ function translateCheckerInAsyncContext(checker) { if (context.isRoot()) { return [2 /*return*/, 0]; } + (0, assert_1.default)(operation.action !== 'create', "".concat(entity, "\u4E0A\u7684create\u52A8\u4F5C\u5B9A\u4E49\u4E86relation\u7C7B\u578B\u7684checker,\u8BF7\u4F7F\u7528expressionRelation\u66FF\u4EE3")); // 对后台而言,将生成的relationFilter加到filter之上(select可以在此加以权限的过滤) _b = operation; _c = filter_1.combineFilters; @@ -143,43 +144,32 @@ function translateCheckerInAsyncContext(checker) { return (function (_a, context, option) { var operation = _a.operation; return tslib_1.__awaiter(_this, void 0, void 0, function () { - var exprResult, result2, isLegal; - var _this = this; - return tslib_1.__generator(this, function (_b) { - switch (_b.label) { + var exprResult, expressionEntity, expr, expressionFilter, _b, result, isLegal; + return tslib_1.__generator(this, function (_c) { + switch (_c.label) { case 0: if (context.isRoot() && type === 'expressionRelation') { return [2 /*return*/, 0]; } return [4 /*yield*/, expression_1(operation, context, option)]; case 1: - exprResult = _b.sent(); + exprResult = _c.sent(); if (!(typeof exprResult === 'string')) return [3 /*break*/, 2]; throw new Exception_1.OakUserUnpermittedException(exprResult || errMsg_2); case 2: if (!(exprResult === undefined)) return [3 /*break*/, 3]; return [2 /*return*/, 0]; - case 3: return [4 /*yield*/, Promise.all(exprResult.map(function (e1) { return Promise.all(e1.map(function (e2) { return tslib_1.__awaiter(_this, void 0, void 0, function () { - var expressionEntity, expr, expressionFilter, _a, result; - return tslib_1.__generator(this, function (_b) { - switch (_b.label) { - case 0: - expressionEntity = e2.entity, expr = e2.expr, expressionFilter = e2.filter; - return [4 /*yield*/, context.select(expressionEntity, { - data: { - $expr: expr, - }, - filter: expressionFilter, - }, Object.assign({}, option, { dontCollect: true }))]; - case 1: - _a = tslib_1.__read.apply(void 0, [_b.sent(), 1]), result = _a[0]; - return [2 /*return*/, result ? result.$expr : false]; - } - }); - }); })); }))]; + case 3: + expressionEntity = exprResult.entity, expr = exprResult.expr, expressionFilter = exprResult.filter; + return [4 /*yield*/, context.select(expressionEntity, { + data: { + $expr: expr, + }, + filter: expressionFilter, + }, Object.assign({}, option, { dontCollect: true }))]; case 4: - result2 = _b.sent(); - isLegal = result2.find(function (r1) { return r1.every(function (r2) { return r2 === true; }); }); + _b = tslib_1.__read.apply(void 0, [_c.sent(), 1]), result = _b[0]; + isLegal = result ? result.$expr : false; if (!isLegal) { // 条件判定为假,抛异常 if (type === 'expression') { @@ -189,7 +179,7 @@ function translateCheckerInAsyncContext(checker) { throw new Exception_1.OakUserUnpermittedException(errMsg_2); } } - _b.label = 5; + _c.label = 5; case 5: return [2 /*return*/, 0]; } }); @@ -260,18 +250,14 @@ function translateCheckerInSyncContext(checker) { } else { (0, assert_1.default)(!(exprResult instanceof Promise)); - var result2 = exprResult.map(function (e1) { return e1.map(function (e2) { - var expressionEntity = e2.entity, expr = e2.expr, expressionFilter = e2.filter; - var _a = tslib_1.__read(context.select(expressionEntity, { - data: { - $expr: expr, - }, - filter: expressionFilter, - }, Object.assign({}, option, { dontCollect: true })), 1), result = _a[0]; - return result ? result.$expr : false; - }); }); - // exprResult外层是or,里层是and关系 - var isLegal = result2.find(function (r1) { return r1.every(function (r2) { return r2 === true; }); }); + var expressionEntity = exprResult.entity, expr = exprResult.expr, expressionFilter = exprResult.filter; + var _a = tslib_1.__read(context.select(expressionEntity, { + data: { + $expr: expr, + }, + filter: expressionFilter, + }, Object.assign({}, option, { dontCollect: true })), 1), result = _a[0]; + var isLegal = result ? result.$expr : false; if (!isLegal) { // 条件判定为假,抛异常 if (type === 'expression') { @@ -315,247 +301,230 @@ function buildReverseHierarchyMap(relationHierarchy) { } return reverseHierarchy; } -function translateSingleCascadeRelationItem(schema, lch, entity2, entityId, userId) { +function translateCascadeRelationFilterMaker(schema, lch, entity2) { var cascadePath = lch.cascadePath, relations = lch.relations; var paths = cascadePath.split('.'); - var translateFilterIter = function (entity, iter) { - var _a, _b, _c, _d, _e; + var translateRelationFilter = function (entity) { + // 有两种情况,此entity和user有Relation定义,或是此entity上有userId + if (schema[entity].relation) { + 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, + }, + }, + }; + }; + } + var attributes = schema[entity].attributes; + (0, assert_1.default)(attributes.hasOwnProperty('userId') && attributes.userId.type === 'ref' && attributes.userId.ref === 'user', "\u5728".concat(entity, "\u4E0A\u65E2\u627E\u4E0D\u5230userId\uFF0C\u4E5F\u6CA1\u6709relation\u5B9A\u4E49")); + return function (userId) { return ({ + userId: userId, + }); }; + }; + var translateFilterMakerIter = function (entity, iter) { var relation = (0, relation_1.judgeRelation)(schema, entity, paths[iter]); if (iter === paths.length - 1) { if (relation === 2) { - return { - entity: paths[iter], - entityId: { - $in: { - entity: "user".concat((0, string_1.firstLetterUpperCase)(paths[iter])), - data: (_a = {}, - _a["".concat(paths[iter], "Id")] = 1, - _a), - filter: { - userId: userId, - relation: { - $in: relations, - }, - }, - }, + var filterMaker_1 = translateRelationFilter(paths[iter]); + return function (userId) { + var _a; + var filter = filterMaker_1(userId); + if (filter.$in) { + return { + entity: paths[iter], + entityId: filter + }; } + return _a = {}, + _a[paths[iter]] = filter, + _a; }; } (0, assert_1.default)(typeof relation === 'string'); - return _b = {}, - _b["".concat(paths[iter], "Id")] = { - $in: { - entity: "user".concat((0, string_1.firstLetterUpperCase)(relation)), - data: (_c = {}, - _c["".concat(relation, "Id")] = 1, - _c), - filter: { - userId: userId, - relation: { - $in: relations, - }, - }, - }, - }, - _b; + var filterMaker_2 = translateRelationFilter(relation); + return function (userId) { + var _a, _b; + var filter = filterMaker_2(userId); + if (filter.$in) { + return _a = {}, + _a["".concat(paths[iter], "Id")] = filter, + _a; + } + return _b = {}, + _b[paths[iter]] = filter, + _b; + }; } else { - var subFilter = translateFilterIter(paths[iter], iter + 1); + var subFilterMaker_1 = translateFilterMakerIter(paths[iter], iter + 1); if (iter === 0) { - return _d = {}, - _d[paths[iter]] = subFilter, - _d.id = entityId, - _d; + return function (userId) { + var _a; + var subFilter = subFilterMaker_1(userId); + return _a = {}, + _a[paths[iter]] = subFilter, + _a; + }; } - return _e = {}, - _e[paths[iter]] = subFilter, - _e; + return function (userId) { + var _a; + return (_a = {}, + _a[paths[iter]] = subFilterMaker_1(userId), + _a); + }; } }; - var filter = translateFilterIter(entity2, 0); - return { - entity: entity2, - filter: filter, - expr: { - $gt: [{ - '#attr': '$$createAt$$', - }, 0] - }, - }; + var filter = paths.length > 0 ? translateFilterMakerIter(entity2, 0) : translateRelationFilter(entity2); + return filter; } -function translateFromCascadeRelationHierarchy(schema, legalCascadeHierarchies, entity, entityId, userId) { - if (legalCascadeHierarchies instanceof Array) { - return legalCascadeHierarchies.map(function (ele) { +function translateActionAuthFilterMaker(schema, relationItem, entity) { + if (relationItem instanceof Array) { + var maker_1 = relationItem.map(function (ele) { if (ele instanceof Array) { - return ele.map(function (ele2) { return translateSingleCascadeRelationItem(schema, ele2, entity, entityId, userId); }); + return ele.map(function (ele2) { return translateCascadeRelationFilterMaker(schema, ele2, entity); }); } - return [translateSingleCascadeRelationItem(schema, ele, entity, entityId, userId)]; + return [translateCascadeRelationFilterMaker(schema, ele, entity)]; }); + return function (userId) { return ({ + $or: maker_1.map(function (ele) { return ({ + $and: ele.map(function (ele2) { return ele2(userId); }) + }); }) + }); }; } - else { - return [[translateSingleCascadeRelationItem(schema, legalCascadeHierarchies, entity, entityId, userId)]]; - } + var filterMaker = translateCascadeRelationFilterMaker(schema, relationItem, entity); + return function (userId) { return filterMaker(userId); }; } -function makeRelationExpressionCombination(schema, entity, entityId, userId, relation, reverseHierarchy, reverseCascadeRelationHierarchy) { - var _a; - var userEntityName = "user".concat((0, string_1.firstLetterUpperCase)(entity)); - var entityIdAttr = "".concat(entity, "Id"); - var legalRelations = reverseHierarchy && reverseHierarchy[relation]; - var legalCascadeHierarchies = reverseCascadeRelationHierarchy && reverseCascadeRelationHierarchy[relation]; - if (!legalRelations && !legalCascadeHierarchies) { - return undefined; - } - if ((legalRelations === null || legalRelations === void 0 ? void 0 : legalRelations.length) === 0) { - throw new Error('这是不应该跑出来的情况,请杀程序员祭天'); - } - var expressionCombination = []; - if (legalRelations && legalRelations.length > 0) { - expressionCombination.push([{ - entity: userEntityName, - expr: { - $gt: [{ - '#attr': '$$createAt$$', - }, 0] - }, - filter: (_a = { - userId: userId - }, - _a[entityIdAttr] = entityId, - _a.relation = { - $in: legalRelations, - }, - _a) - }]); - } - if (legalCascadeHierarchies) { - expressionCombination.push.apply(expressionCombination, tslib_1.__spreadArray([], tslib_1.__read(translateFromCascadeRelationHierarchy(schema, legalCascadeHierarchies, entity, entityId, userId)), false)); - } - return expressionCombination; -} -function createRelationHierarchyCheckers(schema) { +function createAuthCheckers(schema, authDict) { var checkers = []; var _loop_1 = function (entity) { - var _a = schema[entity], relationHierarchy = _a.relationHierarchy, reverseCascadeRelationHierarchy = _a.reverseCascadeRelationHierarchy; - if (relationHierarchy || reverseCascadeRelationHierarchy) { - var reverseHierarchy_1 = relationHierarchy && buildReverseHierarchyMap(relationHierarchy); - var userEntityName_1 = "user".concat((0, string_1.firstLetterUpperCase)(entity)); - var entityIdAttr_1 = "".concat(entity, "Id"); - checkers.push({ - entity: userEntityName_1, - action: 'create', - type: 'expressionRelation', - expression: 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]; - var userId = context.getCurrentUserId(); - var schema = context.getSchema(); - return makeRelationExpressionCombination(schema, entity, entityId, userId, relation, reverseHierarchy_1, reverseCascadeRelationHierarchy); - }, - errMsg: '越权操作', - }); - checkers.push({ - entity: userEntityName_1, - action: 'remove', - type: 'expressionRelation', - expression: function (operation, context) { - var _a; - var userId = context.getCurrentUserId(); - var filter = operation.filter; - var makeFilterFromRows = function (rows) { - var relations = (0, lodash_1.uniq)(rows.map(function (ele) { return ele.relation; })); - var entityIds = (0, lodash_1.uniq)(rows.map(function (ele) { return ele[entityIdAttr_1]; })); - (0, assert_1.default)(entityIds.length === 1, "\u5728\u56DE\u6536".concat(userEntityName_1, "\u4E0A\u6743\u9650\u65F6\uFF0C\u5355\u6B21\u56DE\u6536\u6D89\u53CA\u5230\u4E86\u4E0D\u540C\u7684\u5BF9\u8C61\uFF0C\u6B64\u64CD\u4F5C\u4E0D\u88AB\u5141\u8BB8")); - var entityId = entityIds[0]; - var schema = context.getSchema(); - var exprComb = relations.map(function (relation) { return makeRelationExpressionCombination(schema, entity, entityId, userId, relation, reverseHierarchy_1, reverseCascadeRelationHierarchy); }); - // 对每个relation求出其相应的exprComb,此操作对多行进行expr,需要对之进行类似于笛卡尔积的相乘 - var result = exprComb.reduce(function (accu, current) { - var e_2, _a, e_3, _b; - if (!current) { - return accu; - } - var result2 = []; - try { - for (var current_1 = (e_2 = void 0, tslib_1.__values(current)), current_1_1 = current_1.next(); !current_1_1.done; current_1_1 = current_1.next()) { - var c = current_1_1.value; - try { - for (var _c = (e_3 = void 0, tslib_1.__values(accu)), _d = _c.next(); !_d.done; _d = _c.next()) { - var a = _d.value; - result2.push(a.concat(c)); - } - } - catch (e_3_1) { e_3 = { error: e_3_1 }; } - finally { - try { - if (_d && !_d.done && (_b = _c.return)) _b.call(_c); - } - finally { if (e_3) throw e_3.error; } - } - } - } - catch (e_2_1) { e_2 = { error: e_2_1 }; } - finally { - try { - if (current_1_1 && !current_1_1.done && (_a = current_1.return)) _a.call(current_1); - } - finally { if (e_2) throw e_2.error; } - } - return result2; - }, [[]]); - return result && result.length > 0 ? result : undefined; - }; - var toBeRemoved = context.select(userEntityName_1, { - data: (_a = { - id: 1, - relation: 1 - }, - _a[entityIdAttr_1] = 1, - _a), - filter: filter, - }, { dontCollect: true }); - if (toBeRemoved instanceof Promise) { - return toBeRemoved.then(function (rows) { return makeFilterFromRows(rows); }); - } - return makeFilterFromRows(toBeRemoved); - }, - errMsg: '越权操作', - }); - /* // 一个人不能授权给自己,也不能删除自己的授权 - checkers.push({ - entity: userEntityName as keyof ED, - action: 'create' as ED[keyof ED]['Action'], - type: 'data', - checker: (data, context) => { - assert(!(data instanceof Array)); - const { userId } = data as ED[keyof ED]['CreateSingle']['data']; - const userId2 = context.getCurrentUserId(true); - if (userId === userId2) { - throw new OakDataException('不允许授权给自己'); - } + var _a, _b; + if (authDict[entity]) { + var _c = authDict[entity], relationAuth = _c.relationAuth, actionAuth = _c.actionAuth; + if (relationAuth) { + var raFilterMakerDict_1 = {}; + for (var r in relationAuth) { + Object.assign(raFilterMakerDict_1, (_a = {}, + _a[r] = translateActionAuthFilterMaker(schema, relationAuth[r], entity), + _a)); } - }); - - checkers.push({ - entity: userEntityName as keyof ED, - action: 'remove' as ED[keyof ED]['Action'], - type: 'row', - filter: (operation, context) => { - const userId = context.getCurrentUserId(true); - if (userId) { + var userEntityName_1 = "user".concat((0, string_1.firstLetterUpperCase)(entity)); + var entityIdAttr_1 = "".concat(entity, "Id"); + checkers.push({ + entity: userEntityName_1, + action: 'create', + type: 'expressionRelation', + expression: 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]; + var userId = context.getCurrentUserId(); + if (!raFilterMakerDict_1[relation]) { + return; + } + var filter = raFilterMakerDict_1[relation](userId); return { - userId: { - $ne: userId, + entity: entity, + filter: filter, + expr: { + $gt: [{ + '#attr': '$$createAt$$', + }, 0] }, }; + }, + errMsg: '越权操作', + }); + checkers.push({ + entity: userEntityName_1, + action: 'remove', + type: 'relation', + relationFilter: function (operation, context) { + var _a; + var userId = context.getCurrentUserId(); + var filter = operation.filter; + var makeFilterFromRows = function (rows) { + var relations = (0, lodash_1.uniq)(rows.map(function (ele) { return ele.relation; })); + var entityIds = (0, lodash_1.uniq)(rows.map(function (ele) { return ele[entityIdAttr_1]; })); + (0, assert_1.default)(entityIds.length === 1, "\u5728\u56DE\u6536".concat(userEntityName_1, "\u4E0A\u6743\u9650\u65F6\uFF0C\u5355\u6B21\u56DE\u6536\u6D89\u53CA\u5230\u4E86\u4E0D\u540C\u7684\u5BF9\u8C61\uFF0C\u6B64\u64CD\u4F5C\u4E0D\u88AB\u5141\u8BB8")); + var entityId = entityIds[0]; + // 所有的relation条件要同时满足and关系(注意这里的filter翻译出来是在entity对象上,不是在userEntity对象上) + return { + $and: relations.map(function (relation) { return raFilterMakerDict_1[relation]; }).filter(function (ele) { return !!ele; }).map(function (ele) { + var _a; + return (_a = {}, + _a[entity] = ele(userId), + _a); + }) + }; + }; + var toBeRemoved = context.select(userEntityName_1, { + data: (_a = { + id: 1, + relation: 1 + }, + _a[entityIdAttr_1] = 1, + _a), + filter: filter, + }, { dontCollect: true }); + if (toBeRemoved instanceof Promise) { + return toBeRemoved.then(function (rows) { return makeFilterFromRows(rows); }); + } + return makeFilterFromRows(toBeRemoved); + }, + errMsg: '越权操作', + }); + // 转让权限现在用update动作,只允许update userId给其它人 + // todo 等实现的时候再写 + } + if (actionAuth) { + var aaFilterMakerDict = {}; + for (var a in actionAuth) { + Object.assign(aaFilterMakerDict, (_b = {}, + _b[a] = translateActionAuthFilterMaker(schema, actionAuth[a], entity), + _b)); + if (a === 'create') { + /** + * create动作所增加的auth约束只可能在外键的对象上,所以需要对此外键对象进行查找 + */ + var _d = actionAuth[a]; + /* checkers.push({ + entity, + action: a, + type: 'expressionRelation', + expression: (operation, context) => { + // create要保证数据的外键指向关系满足filter的约束,因为这行还没有插入,所以要 + + } + }); */ } - console.warn(`没有当前用户但在删除权限,请检查。对象是${entity}`); - return {}; - }, - errMsg: '不允许回收自己的授权', - }); */ - // 转让权限现在用update动作,只允许update userId给其它人 - // todo 等实现的时候再写 + else { + /* checkers.push({ + entity, + action: a, + type: 'relation', + relationFilter: (operation, context) => { + const { filter } = operation; + } + }); */ + } + } + } } }; for (var entity in schema) { @@ -563,4 +532,4 @@ function createRelationHierarchyCheckers(schema) { } return checkers; } -exports.createRelationHierarchyCheckers = createRelationHierarchyCheckers; +exports.createAuthCheckers = createAuthCheckers; diff --git a/lib/types/Action.d.ts b/lib/types/Action.d.ts index cf34d33..242e274 100644 --- a/lib/types/Action.d.ts +++ b/lib/types/Action.d.ts @@ -1,4 +1,4 @@ -import { EntityDict } from "./Entity"; +import { CascadeRelationItem, EntityDict } from "./Entity"; import { GenericAction } from '../actions/action'; export declare type Action = string; export declare type State = string; @@ -13,10 +13,6 @@ export declare type ActionDictOfEntityDict = { [A in keyof E[T]['OpSchema']]?: ActionDef; }; }; -export declare type CascadeActionItem = { - cascadePath: string; - relation: string[]; -}; export declare type CascadeActionAuth = { - [K in A | GenericAction]?: CascadeActionItem | (CascadeActionItem | CascadeActionItem[])[]; + [K in A | GenericAction]?: CascadeRelationItem | (CascadeRelationItem | CascadeRelationItem[])[]; }; diff --git a/lib/types/Auth.d.ts b/lib/types/Auth.d.ts index f76d0dc..3903352 100644 --- a/lib/types/Auth.d.ts +++ b/lib/types/Auth.d.ts @@ -1,3 +1,4 @@ +import { CascadeActionAuth, CascadeRelationAuth } from "."; import { AsyncContext } from "../store/AsyncRowStore"; import { SyncContext } from "../store/SyncRowStore"; import { EntityDict, OperateOption, SelectOption } from "../types/Entity"; @@ -42,7 +43,7 @@ export declare type ExpressionTask = expr: RefOrExpression; filter: ED[T]['Selection']['filter']; }; -export declare type ExpressionTaskCombination = ExpressionTask[][]; +export declare type ExpressionTaskCombination = ExpressionTask; export declare type ExpressionChecker | SyncContext> = { priority?: number; type: 'expression'; @@ -62,3 +63,10 @@ export declare type ExpressionRelationChecker ED[T]['Update']['filter']); }; export declare type Checker | SyncContext> = DataChecker | RowChecker | RelationChecker | ExpressionChecker | ExpressionRelationChecker; +export declare type AuthDef = { + relationAuth?: CascadeRelationAuth>; + actionAuth?: CascadeActionAuth; +}; +export declare type AuthDefDict = { + [K in keyof ED]?: AuthDef; +}; diff --git a/lib/types/Entity.d.ts b/lib/types/Entity.d.ts index 9c191cd..83f6fdd 100644 --- a/lib/types/Entity.d.ts +++ b/lib/types/Entity.d.ts @@ -80,6 +80,7 @@ export interface EntityDef { CreateMulti: DeduceCreateMultipleOperation; Update: DeduceUpdateOperation; Remove: DeduceRemoveOperation; + Relation?: string; } export interface EntityDict { [E: string]: EntityDef; @@ -104,7 +105,7 @@ export declare type AggregationResult = Array<{ '#data'?: Partial; }>; export declare type AttrFilter = { - [K in keyof SH]: any; + [K in keyof SH]?: any; }; export declare type DeduceFilter = MakeFilter & ExprOp>; export declare type DeduceSorterAttr = OneOf<{ @@ -155,9 +156,9 @@ export declare type RelationHierarchy = { }; export declare type CascadeRelationItem = { cascadePath: string; - relations: string[]; + relations?: string[]; }; -export declare type ReverseCascadeRelationHierarchy = { +export declare type CascadeRelationAuth = { [K in R]?: CascadeRelationItem | (CascadeRelationItem | CascadeRelationItem[])[]; }; export declare type SelectOpResult = { diff --git a/lib/types/Storage.d.ts b/lib/types/Storage.d.ts index 854bfb6..341fabc 100644 --- a/lib/types/Storage.d.ts +++ b/lib/types/Storage.d.ts @@ -1,5 +1,5 @@ import { ActionType } from '.'; -import { EntityDict, EntityShape, InstinctiveAttributes, RelationHierarchy, ReverseCascadeRelationHierarchy } from './Entity'; +import { EntityDict, EntityShape, InstinctiveAttributes } from './Entity'; import { DataType, DataTypeParams } from './schema/DataTypes'; export declare type Ref = 'ref'; export interface Column { @@ -36,7 +36,7 @@ export declare type UniqConstraint = { attributes: Array; type?: string; }; -export interface StorageDesc { +export interface StorageDesc { storageName?: string; comment?: string; attributes: Attributes; @@ -48,10 +48,9 @@ export interface StorageDesc; + [K in keyof ED]: StorageDesc; }; diff --git a/src/checkers/index.ts b/src/checkers/index.ts index 3cb2927..55f462d 100644 --- a/src/checkers/index.ts +++ b/src/checkers/index.ts @@ -1,13 +1,15 @@ import { EntityDict } from '../base-app-domain'; import { AsyncContext } from '../store/AsyncRowStore'; -import { createRelationHierarchyCheckers } from '../store/checker'; +import { createAuthCheckers } from '../store/checker'; import { createModiRelatedCheckers } from '../store/modi'; import { SyncContext } from '../store/SyncRowStore'; -import { StorageSchema, EntityDict as BaseEntityDict, Checker } from '../types'; +import { StorageSchema, EntityDict as BaseEntityDict, Checker, AuthDef, AuthDefDict } from '../types'; -export function createDynamicCheckers | SyncContext>(schema: StorageSchema){ +export function createDynamicCheckers | SyncContext>(schema: StorageSchema, authDict?: AuthDefDict){ const checkers: Checker[] = []; checkers.push(...createModiRelatedCheckers(schema)); - checkers.push(...createRelationHierarchyCheckers(schema)); + if (authDict) { + checkers.push(...createAuthCheckers(schema, authDict)); + } return checkers; } diff --git a/src/compiler/schemalBuilder.ts b/src/compiler/schemalBuilder.ts index 179a390..165eb5e 100644 --- a/src/compiler/schemalBuilder.ts +++ b/src/compiler/schemalBuilder.ts @@ -25,8 +25,8 @@ const Schema: Record { if (ts.isImportDeclaration(node)) { const entityImported = getEntityImported(node); @@ -1125,7 +1125,7 @@ function analyzeEntity(filename: string, path: string, program: ts.Program, rela _static = true; // static如果有值只能为true } } - else if (ts.isTypeReferenceNode(declaration.type!) && ts.isIdentifier(declaration.type.typeName) && declaration.type.typeName.text === 'RelationHierarchy') { + /* else if (ts.isTypeReferenceNode(declaration.type!) && ts.isIdentifier(declaration.type.typeName) && declaration.type.typeName.text === 'RelationHierarchy') { // RelationHierary assert(hasRelationDef, `${moduleName}中的Relation定义在RelationHierarchy之后`); const { initializer } = declaration; @@ -1138,9 +1138,9 @@ function analyzeEntity(filename: string, path: string, program: ts.Program, rela const { initializer } = declaration; assert(ts.isObjectLiteralExpression(initializer!), `${moduleName}中的RelationHierarchy的定义必须是初始化为ObjectLiteralExpress`); reverseCascadeRelationHierarchy = initializer; - } + } */ else { - throw new Error(`${moduleName}:不能理解的定义内容${declaration.name.getText()}`); + throw new Error(`${moduleName}:不能理解的定义内容${(declaration.name as ts.Identifier).text}`); } } ); @@ -1182,7 +1182,7 @@ function analyzeEntity(filename: string, path: string, program: ts.Program, rela locale: localeDef, }); } - if (hasRelationDef) { + /* if (hasRelationDef) { if(!relationHierarchy && !reverseCascadeRelationHierarchy){ console.warn(`${filename}中定义了Relation,但并没有relationHierarchy或reverseCascadeRelationHierarchy的定义,请注意自主编写权限分配的checker`); } @@ -1200,7 +1200,7 @@ function analyzeEntity(filename: string, path: string, program: ts.Program, rela else { assert(!relationHierarchy, `${filename}中具有relationHierarchy定义但没有Relation定义`); assert(!reverseCascadeRelationHierarchy, `${filename}中具有reverseCascadeRelationHierarchy定义但没有Relation定义`) - } + } */ assign(Schema, { [moduleName]: schema, @@ -5664,7 +5664,7 @@ function outputStorage(outputDir: string, printer: ts.Printer) { for (const entity in Schema) { const indexExpressions: ts.Expression[] = []; - const { sourceFile, inModi, indexes, toModi, actionType, static: _static, relationHierarchy, reverseCascadeRelationHierarchy } = Schema[entity]; + const { sourceFile, inModi, indexes, toModi, actionType, static: _static, hasRelationDef } = Schema[entity]; const fromSchemaSpecifiers = [ factory.createImportSpecifier( false, @@ -5672,7 +5672,7 @@ function outputStorage(outputDir: string, printer: ts.Printer) { factory.createIdentifier("OpSchema") ) ]; - if (relationHierarchy || reverseCascadeRelationHierarchy) { + /* if (relationHierarchy || reverseCascadeRelationHierarchy) { fromSchemaSpecifiers.push( factory.createImportSpecifier( false, @@ -5680,7 +5680,7 @@ function outputStorage(outputDir: string, printer: ts.Printer) { factory.createIdentifier("Relation") ) ); - } + } */ const statements: ts.Statement[] = [ factory.createImportDeclaration( undefined, @@ -5881,7 +5881,7 @@ function outputStorage(outputDir: string, printer: ts.Printer) { ) ); } - if (relationHierarchy) { + /* if (relationHierarchy) { propertyAssignments.push( factory.createPropertyAssignment( factory.createIdentifier("relationHierarchy"), @@ -5896,21 +5896,32 @@ function outputStorage(outputDir: string, printer: ts.Printer) { reverseCascadeRelationHierarchy, ) ); - } + } */ + if (hasRelationDef) { + const { type } = hasRelationDef; + assert(ts.isUnionTypeNode(type)); + const { types } = type; + const relationTexts = types.map( + ele => { + assert(ts.isLiteralTypeNode(ele) && ts.isStringLiteral(ele.literal)); + return ele.literal.text; + } + ) + propertyAssignments.push( + factory.createPropertyAssignment( + factory.createIdentifier("relation"), + factory.createArrayLiteralExpression(relationTexts.map( + ele => factory.createStringLiteral(ele) + )), + ) + ); + } const sdTypeArguments = [ factory.createTypeReferenceNode( factory.createIdentifier("OpSchema"), undefined ) ]; - if (relationHierarchy) { - sdTypeArguments.push( - factory.createTypeReferenceNode( - factory.createIdentifier("Relation"), - undefined - ) - ) - } statements.push( factory.createVariableStatement( [factory.createModifier(ts.SyntaxKind.ExportKeyword)], diff --git a/src/store/checker.ts b/src/store/checker.ts index 2dfc7b2..fccd02b 100644 --- a/src/store/checker.ts +++ b/src/store/checker.ts @@ -1,7 +1,7 @@ import assert from 'assert'; import { addFilterSegment, checkFilterContains, combineFilters } from "../store/filter"; import { OakDataException, OakRowInconsistencyException, OakUserUnpermittedException } from '../types/Exception'; -import { CascadeRelationItem, Checker, CreateTriggerInTxn, EntityDict, ExpressionRelationChecker, ExpressionTask, ExpressionTaskCombination, OperateOption, RefOrExpression, RelationHierarchy, ReverseCascadeRelationHierarchy, SelectOption, StorageSchema, Trigger, UpdateTriggerInTxn } from "../types"; +import { AuthDef, AuthDefDict, CascadeRelationItem, Checker, CreateTriggerInTxn, EntityDict, ExpressionRelationChecker, ExpressionTask, ExpressionTaskCombination, OperateOption, RefOrExpression, RelationHierarchy, CascadeRelationAuth, SelectOption, StorageSchema, Trigger, UpdateTriggerInTxn } from "../types"; import { EntityDict as BaseEntityDict } from '../base-app-domain'; import { AsyncContext } from "./AsyncRowStore"; import { getFullProjection } from './actionDef'; @@ -90,6 +90,7 @@ export function translateCheckerInAsyncContext< if (context.isRoot()) { return 0; } + assert(operation.action !== 'create', `${entity as string}上的create动作定义了relation类型的checker,请使用expressionRelation替代`); // 对后台而言,将生成的relationFilter加到filter之上(select可以在此加以权限的过滤) operation.filter = combineFilters([operation.filter, await relationFilter(operation, context, option)]); return 0; @@ -110,30 +111,14 @@ export function translateCheckerInAsyncContext< return 0; } else { - const result2 = await Promise.all( - exprResult.map( - (e1) => Promise.all( - e1.map( - async (e2) => { - const { entity: expressionEntity, expr, filter: expressionFilter } = e2; - const [result] = await context.select(expressionEntity, { - data: { - $expr: expr, - }, - filter: expressionFilter, - }, Object.assign({}, option, { dontCollect: true })); - return result ? result.$expr as boolean : false; - } - ) - ) - ) - ); - // exprResult外层是or,里层是and关系 - const isLegal = result2.find( - (r1) => r1.every( - (r2) => r2 === true - ) - ); + const { entity: expressionEntity, expr, filter: expressionFilter } = exprResult; + const [result] = await context.select(expressionEntity, { + data: { + $expr: expr, + }, + filter: expressionFilter, + }, Object.assign({}, option, { dontCollect: true })); + const isLegal = result ? result.$expr as boolean : false; if (!isLegal) { // 条件判定为假,抛异常 if (type === 'expression') { @@ -215,26 +200,14 @@ export function translateCheckerInSyncContext< } else { assert(!(exprResult instanceof Promise)); - const result2 = exprResult.map( - (e1) => e1.map( - (e2) => { - const { entity: expressionEntity, expr, filter: expressionFilter } = e2; - const [result] = context.select(expressionEntity, { - data: { - $expr: expr, - }, - filter: expressionFilter, - }, Object.assign({}, option, { dontCollect: true })); - return result ? result.$expr as boolean : false; - } - ) - ); - // exprResult外层是or,里层是and关系 - const isLegal = result2.find( - (r1) => r1.every( - (r2) => r2 === true - ) - ); + const { entity: expressionEntity, expr, filter: expressionFilter } = exprResult; + const [result] = context.select(expressionEntity, { + data: { + $expr: expr, + }, + filter: expressionFilter, + }, Object.assign({}, option, { dontCollect: true })); + const isLegal = result ? result.$expr as boolean : false; if (!isLegal) { // 条件判定为假,抛异常 if (type === 'expression') { @@ -269,273 +242,255 @@ function buildReverseHierarchyMap(relationHierarchy: RelationHierarchy) { return reverseHierarchy; } -function translateSingleCascadeRelationItem( +function translateCascadeRelationFilterMaker( schema: StorageSchema, lch: CascadeRelationItem, - entity2: keyof ED, - entityId: string, - userId: string): ExpressionTask { + entity2: keyof ED): (userId: string) => ExpressionTask['filter'] { const { cascadePath, relations } = lch; const paths = cascadePath.split('.'); - const translateFilterIter = (entity: keyof ED, iter: number): ED[T]['Selection']['filter'] => { - const relation = judgeRelation(schema, entity, paths[iter]); - if (iter === paths.length - 1) { - if (relation === 2) { - return { - entity: paths[iter], - entityId: { - $in: { - entity: `user${firstLetterUpperCase(paths[iter])}`, - data: { - [`${paths[iter]}Id`]: 1, - }, - filter: { - userId, - relation: { - $in: relations, - }, - }, - }, - } + const translateRelationFilter = (entity: T): (userId: string) => ED[T]['Selection']['filter'] => { + // 有两种情况,此entity和user有Relation定义,或是此entity上有userId + if (schema[entity].relation) { + const relationEntityName = `user${firstLetterUpperCase(entity as string)}`; + return (userId) => { + const filter = relations ? { + userId, + relation: { + $in: relations, + }, + } : { + userId, }; - } - assert(typeof relation === 'string'); - return { - [`${paths[iter]}Id`]: { - $in: { - entity: `user${firstLetterUpperCase(relation)}`, - data: { - [`${relation}Id`]: 1, - }, - filter: { - userId, - relation: { - $in: relations, + return { + id: { + $in: { + entity: relationEntityName, + data: { + [`${entity as string}Id`]: 1, }, + filter, }, }, } }; } - else { - const subFilter = translateFilterIter(paths[iter], iter + 1); - if (iter === 0) { + + const { attributes } = schema[entity]; + assert(attributes.hasOwnProperty('userId') && attributes.userId.type === 'ref' && attributes.userId.ref === 'user', `在${entity as string}上既找不到userId,也没有relation定义`); + return (userId) => ({ + userId, + }); + }; + + const translateFilterMakerIter = (entity: T, iter: number): (userId: string) => ED[T]['Selection']['filter'] => { + const relation = judgeRelation(schema, entity, paths[iter]); + if (iter === paths.length - 1) { + if (relation === 2) { + const filterMaker = translateRelationFilter(paths[iter]); + return (userId) => { + const filter = filterMaker(userId); + if (filter!.$in) { + return { + entity: paths[iter], + entityId: filter + }; + } + return { + [paths[iter]]: filter, + }; + } + } + assert(typeof relation === 'string'); + const filterMaker = translateRelationFilter(relation); + return (userId) => { + const filter = filterMaker(userId); + + if (filter!.$in) { + return { + [`${paths[iter]}Id`]: filter + }; + } return { - [paths[iter]]: subFilter, - id: entityId, + [paths[iter]]: filter, }; } - return { - [paths[iter]]: subFilter, - }; + } + else { + const subFilterMaker = translateFilterMakerIter(paths[iter], iter + 1); + if (iter === 0) { + return (userId) => { + const subFilter = subFilterMaker(userId); + return { + [paths[iter]]: subFilter, + }; + }; + } + return (userId) => ({ + [paths[iter]]: subFilterMaker(userId), + }); } }; - const filter = translateFilterIter(entity2, 0); - return { - entity: entity2, - filter, - expr: { - $gt: [{ - '#attr': '$$createAt$$', - }, 0] - }, - }; + + const filter = paths.length > 0 ? translateFilterMakerIter(entity2, 0) : translateRelationFilter(entity2); + return filter; } -function translateFromCascadeRelationHierarchy( +function translateActionAuthFilterMaker( schema: StorageSchema, - legalCascadeHierarchies: CascadeRelationItem | (CascadeRelationItem | CascadeRelationItem[])[], - entity: keyof ED, - entityId: string, - userId: string): ExpressionTaskCombination { - if (legalCascadeHierarchies instanceof Array) { - return legalCascadeHierarchies.map( + relationItem: CascadeRelationItem | (CascadeRelationItem | CascadeRelationItem[])[], + entity: keyof ED +): (userId: string) => ED[keyof ED]['Selection']['filter'] { + if (relationItem instanceof Array) { + const maker = relationItem.map( ele => { if (ele instanceof Array) { return ele.map( - ele2 => translateSingleCascadeRelationItem(schema, ele2, entity, entityId, userId) + ele2 => translateCascadeRelationFilterMaker(schema, ele2, entity) ); } - return [translateSingleCascadeRelationItem(schema, ele, entity, entityId, userId)]; + return [translateCascadeRelationFilterMaker(schema, ele, entity)]; } - ) - } - else { - return [[translateSingleCascadeRelationItem(schema, legalCascadeHierarchies, entity, entityId, userId)]]; + ); + return (userId) => ({ + $or: maker.map( + ele => ({ + $and: ele.map( + ele2 => ele2(userId)! + ) + }) + ) + }) } + const filterMaker = translateCascadeRelationFilterMaker(schema, relationItem, entity); + return (userId) => filterMaker(userId); } -function makeRelationExpressionCombination( +export function createAuthCheckers | SyncContext>( schema: StorageSchema, - entity: keyof ED, - entityId: string, - userId: string, - relation: string, - reverseHierarchy?: Record, - reverseCascadeRelationHierarchy?: ReverseCascadeRelationHierarchy, -) { - const userEntityName = `user${firstLetterUpperCase(entity as string)}`; - const entityIdAttr = `${entity as string}Id`; - const legalRelations = reverseHierarchy && reverseHierarchy[relation]; - const legalCascadeHierarchies = reverseCascadeRelationHierarchy && reverseCascadeRelationHierarchy[relation]; - if (!legalRelations && !legalCascadeHierarchies) { - return undefined; - } - if (legalRelations?.length === 0) { - throw new Error('这是不应该跑出来的情况,请杀程序员祭天'); - } - const expressionCombination: ExpressionTaskCombination = []; - if (legalRelations && legalRelations.length > 0) { - expressionCombination.push([{ - entity: userEntityName as keyof ED, - expr: { - $gt: [{ - '#attr': '$$createAt$$', - }, 0] - }, - filter: { - userId, - [entityIdAttr]: entityId, - relation: { - $in: legalRelations, - } - } - }]); - } - if (legalCascadeHierarchies) { - expressionCombination.push(...translateFromCascadeRelationHierarchy( - schema, - legalCascadeHierarchies, - entity, - entityId, - userId! - )); - } - return expressionCombination; -} - -export function createRelationHierarchyCheckers | SyncContext>(schema: StorageSchema) { + authDict: AuthDefDict) { const checkers: Checker[] = []; for (const entity in schema) { - const { relationHierarchy, reverseCascadeRelationHierarchy } = schema[entity]; - if (relationHierarchy || reverseCascadeRelationHierarchy) { - const reverseHierarchy = relationHierarchy && buildReverseHierarchyMap(relationHierarchy); - const userEntityName = `user${firstLetterUpperCase(entity)}`; - const entityIdAttr = `${entity}Id`; - checkers.push({ - entity: userEntityName as keyof ED, - action: 'create', - type: 'expressionRelation', - expression: (operation: any, context: Cxt) => { - const { data } = operation as ED[keyof ED]['Create']; - assert(!(data instanceof Array)); - const { relation, [entityIdAttr]: entityId } = data; - const userId = context.getCurrentUserId(); - const schema = context.getSchema(); - return makeRelationExpressionCombination(schema, entity, entityId, userId!, relation, reverseHierarchy, reverseCascadeRelationHierarchy); - }, - errMsg: '越权操作', - }); - checkers.push({ - entity: userEntityName as keyof ED, - action: 'remove', - type: 'expressionRelation', - expression: (operation: any, context: Cxt) => { - const userId = context.getCurrentUserId(); - const { filter } = operation as ED[keyof ED]['Remove']; - const makeFilterFromRows = (rows: Partial[]) => { - 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]!; - const schema = context.getSchema(); - const exprComb = relations.map( - (relation) => makeRelationExpressionCombination( - schema, - entity, - entityId, - userId!, - relation!, - reverseHierarchy, - reverseCascadeRelationHierarchy, - ) - ); - // 对每个relation求出其相应的exprComb,此操作对多行进行expr,需要对之进行类似于笛卡尔积的相乘 - const result = exprComb.reduce( - (accu, current) => { - if (!current) { - return accu; - } - const result2 = [] as ExpressionTaskCombination; - for (const c of current) { - for (const a of accu!) { - result2.push(a.concat(c)); - } - } - return result2; + if (authDict[entity]) { + const { relationAuth, actionAuth } = authDict[entity]!; + if (relationAuth) { + const raFilterMakerDict = {} as Record ED[keyof ED]['Selection']['filter']>; + for (const r in relationAuth) { + Object.assign(raFilterMakerDict, { + [r]: translateActionAuthFilterMaker(schema, relationAuth[r as NonNullable]!, entity), + }); + } + const userEntityName = `user${firstLetterUpperCase(entity)}`; + const entityIdAttr = `${entity}Id`; + checkers.push({ + entity: userEntityName as keyof ED, + action: 'create', + type: 'expressionRelation', + expression: (operation, context) => { + const { data } = operation as ED[keyof ED]['Create']; + assert(!(data instanceof Array)); + const { relation, [entityIdAttr]: entityId } = data; + const userId = context.getCurrentUserId(); + if (!raFilterMakerDict[relation]) { + return; + } + const filter = raFilterMakerDict[relation]!(userId!); + return { + entity, + filter, + expr: { + $gt: [{ + '#attr': '$$createAt$$', + }, 0] }, - [[]] as ExpressionTaskCombination, - ); + } + }, + errMsg: '越权操作', + }); - return result && result.length > 0 ? result : undefined; - }; + checkers.push({ + entity: userEntityName as keyof ED, + action: 'remove' as ED[keyof ED]['Action'], + type: 'relation', + relationFilter: (operation: any, context: Cxt) => { + const userId = context.getCurrentUserId(); + const { filter } = operation as ED[keyof ED]['Remove']; + const makeFilterFromRows = (rows: Partial[]) => { + 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]!; - 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) - ); + // 所有的relation条件要同时满足and关系(注意这里的filter翻译出来是在entity对象上,不是在userEntity对象上) + return { + $and: relations.map( + (relation) => raFilterMakerDict[relation!] + ).filter( + ele => !!ele + ).map( + ele => ({ + [entity]: ele(userId!), + }) + ) + } 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) { + const aaFilterMakerDict = {} as Record ED[keyof ED]['Selection']['filter']>; + for (const a in actionAuth) { + Object.assign(aaFilterMakerDict, { + [a]: translateActionAuthFilterMaker(schema, actionAuth[a as ED[keyof ED]['Action']]!, entity), + }); + + if (a === 'create') { + /** + * create动作所增加的auth约束只可能在外键的对象上,所以需要对此外键对象进行查找 + */ + const { } = actionAuth[a as ED[keyof ED]['Action']]!; + /* checkers.push({ + entity, + action: a, + type: 'expressionRelation', + expression: (operation, context) => { + // create要保证数据的外键指向关系满足filter的约束,因为这行还没有插入,所以要 + + } + }); */ } - return makeFilterFromRows(toBeRemoved); - }, - errMsg: '越权操作', - }); - - /* // 一个人不能授权给自己,也不能删除自己的授权 - checkers.push({ - entity: userEntityName as keyof ED, - action: 'create' as ED[keyof ED]['Action'], - type: 'data', - checker: (data, context) => { - assert(!(data instanceof Array)); - const { userId } = data as ED[keyof ED]['CreateSingle']['data']; - const userId2 = context.getCurrentUserId(true); - if (userId === userId2) { - throw new OakDataException('不允许授权给自己'); + else { + /* checkers.push({ + entity, + action: a, + type: 'relation', + relationFilter: (operation, context) => { + const { filter } = operation; + } + }); */ } } - }); - - checkers.push({ - entity: userEntityName as keyof ED, - action: 'remove' as ED[keyof ED]['Action'], - type: 'row', - filter: (operation, context) => { - const userId = context.getCurrentUserId(true); - if (userId) { - return { - userId: { - $ne: userId, - }, - }; - } - console.warn(`没有当前用户但在删除权限,请检查。对象是${entity}`); - return {}; - }, - errMsg: '不允许回收自己的授权', - }); */ - - // 转让权限现在用update动作,只允许update userId给其它人 - // todo 等实现的时候再写 + } } } diff --git a/src/types/Action.ts b/src/types/Action.ts index 2a8d522..daff3fe 100644 --- a/src/types/Action.ts +++ b/src/types/Action.ts @@ -1,4 +1,4 @@ -import { EntityDict } from "./Entity"; +import { CascadeRelationItem, EntityDict } from "./Entity"; import { GenericAction } from '../actions/action'; export type Action = string; @@ -17,11 +17,7 @@ export type ActionDictOfEntityDict = { }; }; -export type CascadeActionItem = { - cascadePath: string; - relation: string[]; -} - +// 即在cascadePath指向的对象上,有relation关系。若relation为空则不限定关系 export type CascadeActionAuth = { - [K in A | GenericAction]?: CascadeActionItem | (CascadeActionItem | CascadeActionItem[])[]; + [K in A | GenericAction]?: CascadeRelationItem | (CascadeRelationItem | CascadeRelationItem[])[]; }; diff --git a/src/types/Auth.ts b/src/types/Auth.ts index dd3aec2..e5eb4f6 100644 --- a/src/types/Auth.ts +++ b/src/types/Auth.ts @@ -1,3 +1,4 @@ +import { CascadeActionAuth, RelationHierarchy, CascadeRelationAuth } from "."; import { AsyncContext } from "../store/AsyncRowStore"; import { SyncContext } from "../store/SyncRowStore"; import { EntityDict, OperateOption, SelectOption } from "../types/Entity"; @@ -56,7 +57,7 @@ export type ExpressionTask = { filter: ED[T]['Selection']['filter']; }; -export type ExpressionTaskCombination = ExpressionTask[][]; +export type ExpressionTaskCombination = ExpressionTask; export type ExpressionChecker | SyncContext> = { priority?: number; @@ -89,3 +90,13 @@ export type ExpressionRelationChecker | SyncContext> = DataChecker | RowChecker | RelationChecker | ExpressionChecker | ExpressionRelationChecker; + + +export type AuthDef = { + relationAuth?: CascadeRelationAuth>; + actionAuth?: CascadeActionAuth; +}; + +export type AuthDefDict = { + [K in keyof ED]?: AuthDef; +}; \ No newline at end of file diff --git a/src/types/Entity.ts b/src/types/Entity.ts index c756b73..92bd6d2 100644 --- a/src/types/Entity.ts +++ b/src/types/Entity.ts @@ -99,6 +99,7 @@ export interface EntityDef { CreateMulti: DeduceCreateMultipleOperation; Update: DeduceUpdateOperation; Remove: DeduceRemoveOperation; + Relation?: string; }; export interface EntityDict { @@ -130,7 +131,7 @@ export type AggregationResult = Array<{ }>; export type AttrFilter = { - [K in keyof SH]: any; + [K in keyof SH]?: any; } export type DeduceFilter = MakeFilter & ExprOp>; @@ -207,10 +208,10 @@ export type RelationHierarchy = { export type CascadeRelationItem = { cascadePath: string; - relations: string[]; + relations?: string[]; }; -export type ReverseCascadeRelationHierarchy = { +export type CascadeRelationAuth = { [K in R]?: CascadeRelationItem | (CascadeRelationItem | CascadeRelationItem[])[]; }; diff --git a/src/types/Port.ts b/src/types/Port.ts index eef5054..bb35b31 100644 --- a/src/types/Port.ts +++ b/src/types/Port.ts @@ -16,5 +16,6 @@ export type Importation>[], context: AsyncContext, option?: Record ) => Promise; }; \ No newline at end of file diff --git a/src/types/Storage.ts b/src/types/Storage.ts index 341b1c0..6b4f1ec 100644 --- a/src/types/Storage.ts +++ b/src/types/Storage.ts @@ -1,5 +1,5 @@ import { ActionType } from '.'; -import { EntityDict, EntityShape, InstinctiveAttributes, RelationHierarchy, ReverseCascadeRelationHierarchy } from './Entity'; +import { EntityDict, EntityShape, InstinctiveAttributes, RelationHierarchy, CascadeRelationAuth } from './Entity'; import { DataType, DataTypeParams } from './schema/DataTypes'; export type Ref = 'ref'; @@ -47,7 +47,7 @@ export type UniqConstraint = { type?: string; }; -export interface StorageDesc { +export interface StorageDesc { storageName?: string, comment?: string, attributes: Attributes; @@ -59,13 +59,14 @@ export interface StorageDesc; + [K in keyof ED]: StorageDesc; } From c1eae2142f67e778ff232730d3d4307002787814 Mon Sep 17 00:00:00 2001 From: "Xc@centOs" Date: Tue, 17 Jan 2023 19:58:15 +0800 Subject: [PATCH 09/19] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86checker?= =?UTF-8?q?=E5=92=8Cauth=E7=9A=84=E9=80=BB=E8=BE=91(=E6=9C=AA=E6=94=BE?= =?UTF-8?q?=E5=BC=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/checkers/index.js | 7 ++-- lib/store/TriggerExecutor.js | 6 ++-- lib/store/checker.js | 68 ++++++++++++++++++++++++------------ lib/types/Auth.d.ts | 2 ++ lib/types/Expression.d.ts | 19 +++++++++- lib/types/Expression.js | 15 ++++++-- src/checkers/index.ts | 4 +-- src/store/TriggerExecutor.ts | 8 ++--- src/store/checker.ts | 52 ++++++++++++++++++--------- src/types/Auth.ts | 2 ++ src/types/Expression.ts | 37 ++++++++++++++++++-- 11 files changed, 162 insertions(+), 58 deletions(-) diff --git a/lib/checkers/index.js b/lib/checkers/index.js index 3c7f105..fed2477 100644 --- a/lib/checkers/index.js +++ b/lib/checkers/index.js @@ -2,14 +2,13 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.createDynamicCheckers = void 0; var tslib_1 = require("tslib"); -var checker_1 = require("../store/checker"); var modi_1 = require("../store/modi"); function createDynamicCheckers(schema, authDict) { var checkers = []; checkers.push.apply(checkers, tslib_1.__spreadArray([], tslib_1.__read((0, modi_1.createModiRelatedCheckers)(schema)), false)); - if (authDict) { - checkers.push.apply(checkers, tslib_1.__spreadArray([], tslib_1.__read((0, checker_1.createAuthCheckers)(schema, authDict)), false)); - } + /* if (authDict) { + checkers.push(...createAuthCheckers(schema, authDict)); + } */ return checkers; } exports.createDynamicCheckers = createDynamicCheckers; diff --git a/lib/store/TriggerExecutor.js b/lib/store/TriggerExecutor.js index a99564a..6b0d21b 100644 --- a/lib/store/TriggerExecutor.js +++ b/lib/store/TriggerExecutor.js @@ -36,11 +36,11 @@ var TriggerExecutor = /** @class */ (function () { var trigger = { checkerType: type, name: triggerName, - priority: checker.priority || 2, + priority: checker.priority || 20, entity: entity, action: action, fn: fn, - when: 'before', + when: checker.when || 'before', filter: conditionalFilter, }; this.registerTrigger(trigger); @@ -59,7 +59,7 @@ var TriggerExecutor = /** @class */ (function () { throw new Error("\u4E0D\u53EF\u6709\u540C\u540D\u7684\u89E6\u53D1\u5668\u300C".concat(trigger.name, "\u300D")); } if (typeof trigger.priority !== 'number') { - trigger.priority = 1; // 默认最低 + trigger.priority = 10; // 默认值 } if (trigger.filter) { (0, assert_1.default)(typeof trigger.action === 'string' && trigger.action !== 'create' diff --git a/lib/store/checker.js b/lib/store/checker.js index 5a3b24d..6a50bac 100644 --- a/lib/store/checker.js +++ b/lib/store/checker.js @@ -413,9 +413,9 @@ function translateActionAuthFilterMaker(schema, relationItem, entity) { function createAuthCheckers(schema, authDict) { var checkers = []; var _loop_1 = function (entity) { - var _a, _b; + var _a; if (authDict[entity]) { - var _c = authDict[entity], relationAuth = _c.relationAuth, actionAuth = _c.actionAuth; + var _b = authDict[entity], relationAuth = _b.relationAuth, actionAuth = _b.actionAuth; if (relationAuth) { var raFilterMakerDict_1 = {}; for (var r in relationAuth) { @@ -440,7 +440,7 @@ function createAuthCheckers(schema, authDict) { var filter = raFilterMakerDict_1[relation](userId); return { entity: entity, - filter: filter, + filter: (0, filter_1.combineFilters)([filter, { id: entityId }]), expr: { $gt: [{ '#attr': '$$createAt$$', @@ -493,36 +493,58 @@ function createAuthCheckers(schema, authDict) { // todo 等实现的时候再写 } if (actionAuth) { - var aaFilterMakerDict = {}; - for (var a in actionAuth) { - Object.assign(aaFilterMakerDict, (_b = {}, - _b[a] = translateActionAuthFilterMaker(schema, actionAuth[a], entity), - _b)); + var _loop_2 = function (a) { + var filterMaker = translateActionAuthFilterMaker(schema, actionAuth[a], entity); if (a === 'create') { /** - * create动作所增加的auth约束只可能在外键的对象上,所以需要对此外键对象进行查找 + * create动作所增加的auth约束只可能在外键的对象上,但因为还有级联和触发器,不太容易在创建前检查,先放在创建后 */ - var _d = actionAuth[a]; - /* checkers.push({ - entity, + var _c = actionAuth[a]; + checkers.push({ + entity: entity, action: a, type: 'expressionRelation', - expression: (operation, context) => { - // create要保证数据的外键指向关系满足filter的约束,因为这行还没有插入,所以要 - - } - }); */ + when: 'after', + expression: function (operation, context) { + // 在插入后检查 + var makeExprInner = function (data) { + var id = data.id; + return { + entity: entity, + filter: (0, filter_1.combineFilters)([filter, { id: id }]), + expr: { + $gt: [{ + '#attr': '$$createAt$$', + }, 0] + }, + }; + }; + var filter = filterMaker(context.getCurrentUserId()); + var data = operation.data; + if (data instanceof Array) { + throw new Error('需要expr支持count'); + } + return makeExprInner(data); + }, + errMsg: '定义的actionAuth中检查出来越权操作', + }); } else { - /* checkers.push({ - entity, + checkers.push({ + entity: entity, action: a, type: 'relation', - relationFilter: (operation, context) => { - const { filter } = operation; - } - }); */ + relationFilter: function (operation, context) { + // const { filter } = operation; + var filter = filterMaker(context.getCurrentUserId()); + return filter; + }, + errMsg: '定义的actionAuth中检查出来越权操作', + }); } + }; + for (var a in actionAuth) { + _loop_2(a); } } } diff --git a/lib/types/Auth.d.ts b/lib/types/Auth.d.ts index 3903352..28ed127 100644 --- a/lib/types/Auth.d.ts +++ b/lib/types/Auth.d.ts @@ -47,6 +47,7 @@ export declare type ExpressionTaskCombination = Expressio export declare type ExpressionChecker | SyncContext> = { priority?: number; type: 'expression'; + when?: 'after'; entity: T; action: ED[T]['Action'] | Array; expression: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ExpressionTaskCombination | undefined | string | Promise | string | undefined>; @@ -56,6 +57,7 @@ export declare type ExpressionChecker | SyncContext> = { priority?: number; type: 'expressionRelation'; + when?: 'after'; entity: T; action: ED[T]['Action'] | Array; expression: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ExpressionTaskCombination | undefined | string | Promise | string | undefined>; diff --git a/lib/types/Expression.d.ts b/lib/types/Expression.d.ts index 8cf41b3..cdeb126 100644 --- a/lib/types/Expression.d.ts +++ b/lib/types/Expression.d.ts @@ -122,7 +122,23 @@ interface GeoDistance { $distance: [RefOrExpression | Geo, RefOrExpression | Geo]; } declare type GeoExpression = GeoContains | GeoDistance; -export declare type Expression = GeoExpression | DateExpression | LogicExpression | BoolExpression | CompareExpression | MathExpression | StringExpression; +interface AggrCountExpression { + $$count: RefOrExpression; +} +interface AggrSumExpression { + $$sum: RefOrExpression; +} +interface AggrMaxExpression { + $$max: RefOrExpression; +} +interface AggrMinExpression { + $$min: RefOrExpression; +} +interface AggrAvgExpression { + $$avg: RefOrExpression; +} +export declare type AggrExpression = AggrAvgExpression | AggrCountExpression | AggrSumExpression | AggrMaxExpression | AggrMinExpression; +export declare type Expression = GeoExpression | DateExpression | LogicExpression | BoolExpression | CompareExpression | MathExpression | StringExpression | AggrExpression; export declare type ExpressionConstant = Geo | number | Date | string | boolean; export declare function isGeoExpression(expression: any): expression is GeoExpression; export declare function isDateExpression(expression: any): expression is DateExpression; @@ -131,6 +147,7 @@ export declare function isBoolExpression(expression: any): expression is Bool export declare function isCompareExpression(expression: any): expression is CompareExpression; export declare function isMathExpression(expression: any): expression is MathExpression; export declare function isStringExpression(expression: any): expression is StringExpression; +export declare function isAggrExpression(expression: any): expression is AggrExpression; export declare function isExpression(expression: any): expression is Expression; export declare function opMultipleParams(op: string): boolean; export declare function execOp(op: string, params: any, obscure?: boolean): ExpressionConstant; diff --git a/lib/types/Expression.js b/lib/types/Expression.js index 463f906..64c0471 100644 --- a/lib/types/Expression.js +++ b/lib/types/Expression.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.getAttrRefInExpression = exports.execOp = exports.opMultipleParams = exports.isExpression = exports.isStringExpression = exports.isMathExpression = exports.isCompareExpression = exports.isBoolExpression = exports.isLogicExpression = exports.isDateExpression = exports.isGeoExpression = void 0; +exports.getAttrRefInExpression = exports.execOp = exports.opMultipleParams = exports.isExpression = exports.isAggrExpression = exports.isStringExpression = exports.isMathExpression = exports.isCompareExpression = exports.isBoolExpression = exports.isLogicExpression = exports.isDateExpression = exports.isGeoExpression = void 0; var tslib_1 = require("tslib"); var assert_1 = tslib_1.__importDefault(require("assert")); var dayjs_1 = tslib_1.__importDefault(require("dayjs")); @@ -42,6 +42,7 @@ dayjs_1.default.extend(dayOfYear_1.default); ; ; ; +; function isGeoExpression(expression) { if (Object.keys(expression).length == 1) { var op = Object.keys(expression)[0]; @@ -115,6 +116,16 @@ function isStringExpression(expression) { return false; } exports.isStringExpression = isStringExpression; +function isAggrExpression(expression) { + if (Object.keys(expression).length == 1) { + var op = Object.keys(expression)[0]; + if (['$$max', '$$min', '$$sum', '$$avg', '$$count'].includes(op)) { + return true; + } + } + return false; +} +exports.isAggrExpression = isAggrExpression; function isExpression(expression) { return typeof expression === 'object' && Object.keys(expression).length === 1 && Object.keys(expression)[0].startsWith('$'); } @@ -122,7 +133,7 @@ exports.isExpression = isExpression; function opMultipleParams(op) { return !['$year', '$month', '$weekday', '$weekOfYear', '$day', '$dayOfMonth', '$dayOfWeek', '$dayOfYear', '$not', '$true', '$false', '$abs', - '$round', '$floor', '$ceil'].includes(op); + '$round', '$floor', '$ceil', '$$max', '$$min', '$$sum', '$$avg', '$$count'].includes(op); } exports.opMultipleParams = opMultipleParams; function execOp(op, params, obscure) { diff --git a/src/checkers/index.ts b/src/checkers/index.ts index 55f462d..4a1c402 100644 --- a/src/checkers/index.ts +++ b/src/checkers/index.ts @@ -8,8 +8,8 @@ import { StorageSchema, EntityDict as BaseEntityDict, Checker, AuthDef, AuthDefD export function createDynamicCheckers | SyncContext>(schema: StorageSchema, authDict?: AuthDefDict){ const checkers: Checker[] = []; checkers.push(...createModiRelatedCheckers(schema)); - if (authDict) { + /* if (authDict) { checkers.push(...createAuthCheckers(schema, authDict)); - } + } */ return checkers; } diff --git a/src/store/TriggerExecutor.ts b/src/store/TriggerExecutor.ts index 1b6f1b9..bb68749 100644 --- a/src/store/TriggerExecutor.ts +++ b/src/store/TriggerExecutor.ts @@ -4,7 +4,7 @@ import { addFilterSegment, checkFilterRepel } from "../store/filter"; import { DeduceCreateOperation, EntityDict, OperateOption, SelectOption, TriggerDataAttribute, TriggerTimestampAttribute } from "../types/Entity"; import { EntityDict as BaseEntityDict } from '../base-app-domain'; import { Logger } from "../types/Logger"; -import { Checker, CheckerType } from '../types/Auth'; +import { Checker, CheckerType, ExpressionChecker, RelationChecker } from '../types/Auth'; import { Trigger, CreateTriggerCrossTxn, CreateTrigger, CreateTriggerInTxn, SelectTriggerAfter, UpdateTrigger } from "../types/Trigger"; import { AsyncContext } from './AsyncRowStore'; import { SyncContext } from './SyncRowStore'; @@ -53,11 +53,11 @@ export class TriggerExecutor { const trigger = { checkerType: type, name: triggerName, - priority: checker.priority || 2, // checker的默认优先级稍高一点点 + priority: checker.priority || 20, // checker的默认优先级稍高 entity, action: action as 'update', fn, - when: 'before', + when: (checker as ExpressionChecker).when || 'before', filter: conditionalFilter, } as UpdateTrigger; this.registerTrigger(trigger); @@ -77,7 +77,7 @@ export class TriggerExecutor { throw new Error(`不可有同名的触发器「${trigger.name}」`); } if (typeof trigger.priority !== 'number') { - trigger.priority = 1; // 默认最低 + trigger.priority = 10; // 默认值 } if ((trigger as UpdateTrigger).filter) { assert(typeof trigger.action === 'string' && trigger.action !== 'create' diff --git a/src/store/checker.ts b/src/store/checker.ts index fccd02b..42b9673 100644 --- a/src/store/checker.ts +++ b/src/store/checker.ts @@ -398,7 +398,7 @@ export function createAuthCheckers ED[keyof ED]['Selection']['filter']>; for (const a in actionAuth) { - Object.assign(aaFilterMakerDict, { - [a]: translateActionAuthFilterMaker(schema, actionAuth[a as ED[keyof ED]['Action']]!, entity), - }); - + const filterMaker = translateActionAuthFilterMaker(schema, actionAuth[a as ED[keyof ED]['Action']]!, entity); if (a === 'create') { /** - * create动作所增加的auth约束只可能在外键的对象上,所以需要对此外键对象进行查找 + * create动作所增加的auth约束只可能在外键的对象上,但因为还有级联和触发器,不太容易在创建前检查,先放在创建后 */ const { } = actionAuth[a as ED[keyof ED]['Action']]!; - /* checkers.push({ + checkers.push({ entity, action: a, type: 'expressionRelation', + when: 'after', expression: (operation, context) => { - // create要保证数据的外键指向关系满足filter的约束,因为这行还没有插入,所以要 - - } - }); */ + // 在插入后检查 + const makeExprInner = (data: ED[keyof ED]['CreateSingle']['data']) => { + const { id } = data; + return { + entity, + filter: combineFilters([filter, { id }]), + expr: { + $gt: [{ + '#attr': '$$createAt$$', + }, 0] as any + }, + }; + }; + const filter = filterMaker(context.getCurrentUserId()!); + const { data } = operation as ED[keyof ED]['Create']; + if (data instanceof Array) { + throw new Error('需要expr支持count'); + } + return makeExprInner(data); + }, + errMsg: '定义的actionAuth中检查出来越权操作', + }); } else { - /* checkers.push({ + checkers.push({ entity, - action: a, + action: a as ED[keyof ED]['Action'], type: 'relation', relationFilter: (operation, context) => { - const { filter } = operation; - } - }); */ + // const { filter } = operation; + const filter = filterMaker(context.getCurrentUserId()!); + return filter; + }, + errMsg: '定义的actionAuth中检查出来越权操作', + }); } } } diff --git a/src/types/Auth.ts b/src/types/Auth.ts index e5eb4f6..ce8c186 100644 --- a/src/types/Auth.ts +++ b/src/types/Auth.ts @@ -62,6 +62,7 @@ export type ExpressionTaskCombination = ExpressionTask | SyncContext> = { priority?: number; type: 'expression'; + when?: 'after'; entity: T; action: ED[T]['Action'] | Array; expression: ( @@ -76,6 +77,7 @@ export type ExpressionChecker | SyncContext> = { priority?: number; type: 'expressionRelation'; + when?: 'after'; entity: T; action: ED[T]['Action'] | Array; expression: ( diff --git a/src/types/Expression.ts b/src/types/Expression.ts index 342c2a3..7425586 100644 --- a/src/types/Expression.ts +++ b/src/types/Expression.ts @@ -154,8 +154,31 @@ interface GeoDistance { type GeoExpression = GeoContains | GeoDistance; +//// Aggr +interface AggrCountExpression { + $$count: RefOrExpression; +}; + +interface AggrSumExpression { + $$sum: RefOrExpression; +} + +interface AggrMaxExpression { + $$max: RefOrExpression; +} + +interface AggrMinExpression { + $$min: RefOrExpression; +} + +interface AggrAvgExpression { + $$avg: RefOrExpression; +} + +export type AggrExpression = AggrAvgExpression | AggrCountExpression | AggrSumExpression | AggrMaxExpression | AggrMinExpression; + export type Expression = GeoExpression | DateExpression | LogicExpression - | BoolExpression | CompareExpression | MathExpression | StringExpression; + | BoolExpression | CompareExpression | MathExpression | StringExpression | AggrExpression; export type ExpressionConstant = Geo | number | Date | string | boolean; @@ -233,6 +256,16 @@ export function isStringExpression(expression: any): expression is StringExpr return false; } +export function isAggrExpression(expression: any): expression is AggrExpression { + if (Object.keys(expression).length == 1) { + const op = Object.keys(expression)[0]; + if (['$$max', '$$min', '$$sum', '$$avg', '$$count'].includes(op)) { + return true; + } + } + return false; +} + export function isExpression(expression: any): expression is Expression { return typeof expression === 'object' && Object.keys(expression).length === 1 && Object.keys(expression)[0].startsWith('$'); } @@ -240,7 +273,7 @@ export function isExpression(expression: any): expression is Expression { export function opMultipleParams(op: string) { return !['$year', '$month', '$weekday', '$weekOfYear', '$day', '$dayOfMonth', '$dayOfWeek', '$dayOfYear', '$not', '$true', '$false', '$abs', - '$round', '$floor', '$ceil'].includes(op); + '$round', '$floor', '$ceil', '$$max', '$$min', '$$sum', '$$avg', '$$count'].includes(op); } export function execOp(op: string, params: any, obscure?: boolean): ExpressionConstant { From a49e37a5fe0344b0c9277fe08684776ef95ba18d Mon Sep 17 00:00:00 2001 From: "Xc@centOs" Date: Wed, 18 Jan 2023 10:58:43 +0800 Subject: [PATCH 10/19] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BA=86checker?= =?UTF-8?q?=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/compiler/schemalBuilder.js | 22 ++++-- lib/store/checker.js | 129 +++++++++------------------------ lib/types/Auth.d.ts | 19 +++-- src/compiler/schemalBuilder.ts | 48 ++++++++---- src/store/TriggerExecutor.ts | 4 +- src/store/checker.ts | 91 ++++------------------- src/store/modi.ts | 2 +- src/types/Auth.ts | 23 +++--- 8 files changed, 120 insertions(+), 218 deletions(-) diff --git a/lib/compiler/schemalBuilder.js b/lib/compiler/schemalBuilder.js index 0d3a8af..bbf7d86 100644 --- a/lib/compiler/schemalBuilder.js +++ b/lib/compiler/schemalBuilder.js @@ -3155,13 +3155,21 @@ function outputStorage(outputDir, printer) { } */ if (hasRelationDef) { var type = hasRelationDef.type; - (0, assert_1.default)(ts.isUnionTypeNode(type)); - var types = type.types; - var relationTexts = types.map(function (ele) { - (0, assert_1.default)(ts.isLiteralTypeNode(ele) && ts.isStringLiteral(ele.literal)); - return ele.literal.text; - }); - propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("relation"), factory.createArrayLiteralExpression(relationTexts.map(function (ele) { return factory.createStringLiteral(ele); })))); + if (ts.isUnionTypeNode(type)) { + var types = type.types; + var relationTexts = types.map(function (ele) { + (0, assert_1.default)(ts.isLiteralTypeNode(ele) && ts.isStringLiteral(ele.literal)); + return ele.literal.text; + }); + propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("relation"), factory.createArrayLiteralExpression(relationTexts.map(function (ele) { return factory.createStringLiteral(ele); })))); + } + else { + (0, assert_1.default)(ts.isLiteralTypeNode(type)); + (0, assert_1.default)(ts.isStringLiteral(type.literal)); + propertyAssignments.push(factory.createPropertyAssignment(factory.createIdentifier("relation"), factory.createArrayLiteralExpression([ + type.literal + ]))); + } } var sdTypeArguments = [ factory.createTypeReferenceNode(factory.createIdentifier("OpSchema"), undefined) diff --git a/lib/store/checker.js b/lib/store/checker.js index 6a50bac..ffa50da 100644 --- a/lib/store/checker.js +++ b/lib/store/checker.js @@ -138,49 +138,22 @@ function translateCheckerInAsyncContext(checker) { }); }); } - case 'expression': - case 'expressionRelation': { - var expression_1 = checker.expression, errMsg_2 = checker.errMsg; + case 'logical': + case 'logicalRelation': { + var checkerFn_2 = checker.checker; return (function (_a, context, option) { var operation = _a.operation; return tslib_1.__awaiter(_this, void 0, void 0, function () { - var exprResult, expressionEntity, expr, expressionFilter, _b, result, isLegal; - return tslib_1.__generator(this, function (_c) { - switch (_c.label) { + return tslib_1.__generator(this, function (_b) { + switch (_b.label) { case 0: - if (context.isRoot() && type === 'expressionRelation') { + if (context.isRoot() && type === 'logicalRelation') { return [2 /*return*/, 0]; } - return [4 /*yield*/, expression_1(operation, context, option)]; + return [4 /*yield*/, checkerFn_2(operation, context, option)]; case 1: - exprResult = _c.sent(); - if (!(typeof exprResult === 'string')) return [3 /*break*/, 2]; - throw new Exception_1.OakUserUnpermittedException(exprResult || errMsg_2); - case 2: - if (!(exprResult === undefined)) return [3 /*break*/, 3]; + _b.sent(); return [2 /*return*/, 0]; - case 3: - expressionEntity = exprResult.entity, expr = exprResult.expr, expressionFilter = exprResult.filter; - return [4 /*yield*/, context.select(expressionEntity, { - data: { - $expr: expr, - }, - filter: expressionFilter, - }, Object.assign({}, option, { dontCollect: true }))]; - case 4: - _b = tslib_1.__read.apply(void 0, [_c.sent(), 1]), result = _b[0]; - isLegal = result ? result.$expr : false; - if (!isLegal) { - // 条件判定为假,抛异常 - if (type === 'expression') { - throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_2); - } - else { - throw new Exception_1.OakUserUnpermittedException(errMsg_2); - } - } - _c.label = 5; - case 5: return [2 /*return*/, 0]; } }); }); @@ -196,11 +169,11 @@ function translateCheckerInSyncContext(checker) { var entity = checker.entity, type = checker.type; switch (type) { case 'data': { - var checkerFn_2 = checker.checker; - return function (operation, context) { return checkerFn_2(operation.data, context); }; + var checkerFn_3 = checker.checker; + return function (operation, context) { return checkerFn_3(operation.data, context); }; } case 'row': { - var filter_3 = checker.filter, errMsg_3 = checker.errMsg; + var filter_3 = checker.filter, errMsg_2 = checker.errMsg; return function (operation, context, option) { var operationFilter = operation.filter, action = operation.action; var filter2 = typeof filter_3 === 'function' ? filter_3(operation, context, option) : filter_3; @@ -214,12 +187,12 @@ function translateCheckerInSyncContext(checker) { if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter, true)) { return; } - throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_3); + throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_2); } }; } case 'relation': { - var filter_4 = checker.relationFilter, errMsg_4 = checker.errMsg; + var filter_4 = checker.relationFilter, errMsg_3 = checker.errMsg; return function (operation, context, option) { if (context.isRoot()) { return; @@ -231,43 +204,17 @@ function translateCheckerInSyncContext(checker) { if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter, true)) { return; } - throw new Exception_1.OakUserUnpermittedException(errMsg_4); + throw new Exception_1.OakUserUnpermittedException(errMsg_3); }; } - case 'expression': - case 'expressionRelation': { - var expression_2 = checker.expression, errMsg_5 = checker.errMsg; + case 'logical': + case 'logicalRelation': { + var checkerFn_4 = checker.checker; return function (operation, context, option) { - if (context.isRoot() && type === 'expressionRelation') { + if (context.isRoot() && type === 'logicalRelation') { return; } - var exprResult = expression_2(operation, context, option); - if (typeof exprResult === 'string') { - throw new Exception_1.OakUserUnpermittedException(exprResult || errMsg_5); - } - else if (exprResult === undefined) { - return 0; - } - else { - (0, assert_1.default)(!(exprResult instanceof Promise)); - var expressionEntity = exprResult.entity, expr = exprResult.expr, expressionFilter = exprResult.filter; - var _a = tslib_1.__read(context.select(expressionEntity, { - data: { - $expr: expr, - }, - filter: expressionFilter, - }, Object.assign({}, option, { dontCollect: true })), 1), result = _a[0]; - var isLegal = result ? result.$expr : false; - if (!isLegal) { - // 条件判定为假,抛异常 - if (type === 'expression') { - throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_5); - } - else { - throw new Exception_1.OakUserUnpermittedException(errMsg_5); - } - } - } + checkerFn_4(operation, context, option); }; } default: { @@ -428,8 +375,8 @@ function createAuthCheckers(schema, authDict) { checkers.push({ entity: userEntityName_1, action: 'create', - type: 'expressionRelation', - expression: function (operation, context) { + 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]; @@ -438,15 +385,7 @@ function createAuthCheckers(schema, authDict) { return; } var filter = raFilterMakerDict_1[relation](userId); - return { - entity: entity, - filter: (0, filter_1.combineFilters)([filter, { id: entityId }]), - expr: { - $gt: [{ - '#attr': '$$createAt$$', - }, 0] - }, - }; + return filter; }, errMsg: '越权操作', }); @@ -500,34 +439,34 @@ function createAuthCheckers(schema, authDict) { * create动作所增加的auth约束只可能在外键的对象上,但因为还有级联和触发器,不太容易在创建前检查,先放在创建后 */ var _c = actionAuth[a]; - checkers.push({ - entity: entity, + /* checkers.push({ + entity, action: a, type: 'expressionRelation', when: 'after', - expression: function (operation, context) { + expression: (operation, context) => { // 在插入后检查 - var makeExprInner = function (data) { - var id = data.id; + const makeExprInner = (data: ED[keyof ED]['CreateSingle']['data']) => { + const { id } = data; return { - entity: entity, - filter: (0, filter_1.combineFilters)([filter, { id: id }]), + entity, + filter: combineFilters([filter, { id }]), expr: { $gt: [{ - '#attr': '$$createAt$$', - }, 0] + '#attr': '$$createAt$$', + }, 0] as any }, }; }; - var filter = filterMaker(context.getCurrentUserId()); - var data = operation.data; + const filter = filterMaker(context.getCurrentUserId()!); + const { data } = operation as ED[keyof ED]['Create']; if (data instanceof Array) { throw new Error('需要expr支持count'); } return makeExprInner(data); }, errMsg: '定义的actionAuth中检查出来越权操作', - }); + }); */ } else { checkers.push({ diff --git a/lib/types/Auth.d.ts b/lib/types/Auth.d.ts index 28ed127..8d7b513 100644 --- a/lib/types/Auth.d.ts +++ b/lib/types/Auth.d.ts @@ -33,7 +33,8 @@ export declare type RelationChecker | Array>; + when?: 'after'; + action: ED[T]['Action'] | Array; relationFilter: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ED[T]['Selection']['filter'] | Promise; errMsg: string; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter'] | Promise); @@ -44,27 +45,25 @@ export declare type ExpressionTask = filter: ED[T]['Selection']['filter']; }; export declare type ExpressionTaskCombination = ExpressionTask; -export declare type ExpressionChecker | SyncContext> = { +export declare type LogicalChecker | SyncContext> = { priority?: number; - type: 'expression'; + type: 'logical'; when?: 'after'; entity: T; action: ED[T]['Action'] | Array; - expression: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ExpressionTaskCombination | undefined | string | Promise | string | undefined>; - errMsg: string; + checker: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => void | Promise; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); }; -export declare type ExpressionRelationChecker | SyncContext> = { +export declare type LogicalRelationChecker | SyncContext> = { priority?: number; - type: 'expressionRelation'; + type: 'logicalRelation'; when?: 'after'; entity: T; action: ED[T]['Action'] | Array; - expression: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ExpressionTaskCombination | undefined | string | Promise | string | undefined>; - errMsg: string; + checker: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => void | Promise; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); }; -export declare type Checker | SyncContext> = DataChecker | RowChecker | RelationChecker | ExpressionChecker | ExpressionRelationChecker; +export declare type Checker | SyncContext> = DataChecker | RowChecker | RelationChecker | LogicalChecker | LogicalRelationChecker; export declare type AuthDef = { relationAuth?: CascadeRelationAuth>; actionAuth?: CascadeActionAuth; diff --git a/src/compiler/schemalBuilder.ts b/src/compiler/schemalBuilder.ts index 165eb5e..f7c86e9 100644 --- a/src/compiler/schemalBuilder.ts +++ b/src/compiler/schemalBuilder.ts @@ -5899,23 +5899,39 @@ function outputStorage(outputDir: string, printer: ts.Printer) { } */ if (hasRelationDef) { const { type } = hasRelationDef; - assert(ts.isUnionTypeNode(type)); - const { types } = type; - const relationTexts = types.map( - ele => { - assert(ts.isLiteralTypeNode(ele) && ts.isStringLiteral(ele.literal)); - return ele.literal.text; - } - ) - propertyAssignments.push( - factory.createPropertyAssignment( - factory.createIdentifier("relation"), - factory.createArrayLiteralExpression(relationTexts.map( - ele => factory.createStringLiteral(ele) - )), + if (ts.isUnionTypeNode(type)) { + const { types } = type; + const relationTexts = types.map( + ele => { + assert(ts.isLiteralTypeNode(ele) && ts.isStringLiteral(ele.literal)); + return ele.literal.text; + } ) - ); - } + propertyAssignments.push( + factory.createPropertyAssignment( + factory.createIdentifier("relation"), + factory.createArrayLiteralExpression(relationTexts.map( + ele => factory.createStringLiteral(ele) + )), + ) + ); + } + else { + assert(ts.isLiteralTypeNode(type)); + assert(ts.isStringLiteral(type.literal)); + + propertyAssignments.push( + factory.createPropertyAssignment( + factory.createIdentifier("relation"), + factory.createArrayLiteralExpression( + [ + type.literal + ] + ), + ) + ); + } + } const sdTypeArguments = [ factory.createTypeReferenceNode( factory.createIdentifier("OpSchema"), diff --git a/src/store/TriggerExecutor.ts b/src/store/TriggerExecutor.ts index bb68749..f3070af 100644 --- a/src/store/TriggerExecutor.ts +++ b/src/store/TriggerExecutor.ts @@ -4,7 +4,7 @@ import { addFilterSegment, checkFilterRepel } from "../store/filter"; import { DeduceCreateOperation, EntityDict, OperateOption, SelectOption, TriggerDataAttribute, TriggerTimestampAttribute } from "../types/Entity"; import { EntityDict as BaseEntityDict } from '../base-app-domain'; import { Logger } from "../types/Logger"; -import { Checker, CheckerType, ExpressionChecker, RelationChecker } from '../types/Auth'; +import { Checker, CheckerType, LogicalChecker, RelationChecker } from '../types/Auth'; import { Trigger, CreateTriggerCrossTxn, CreateTrigger, CreateTriggerInTxn, SelectTriggerAfter, UpdateTrigger } from "../types/Trigger"; import { AsyncContext } from './AsyncRowStore'; import { SyncContext } from './SyncRowStore'; @@ -57,7 +57,7 @@ export class TriggerExecutor { entity, action: action as 'update', fn, - when: (checker as ExpressionChecker).when || 'before', + when: (checker as LogicalChecker).when || 'before', filter: conditionalFilter, } as UpdateTrigger; this.registerTrigger(trigger); diff --git a/src/store/checker.ts b/src/store/checker.ts index 42b9673..09b88a4 100644 --- a/src/store/checker.ts +++ b/src/store/checker.ts @@ -1,7 +1,7 @@ import assert from 'assert'; import { addFilterSegment, checkFilterContains, combineFilters } from "../store/filter"; import { OakDataException, OakRowInconsistencyException, OakUserUnpermittedException } from '../types/Exception'; -import { AuthDef, AuthDefDict, CascadeRelationItem, Checker, CreateTriggerInTxn, EntityDict, ExpressionRelationChecker, ExpressionTask, ExpressionTaskCombination, OperateOption, RefOrExpression, RelationHierarchy, CascadeRelationAuth, SelectOption, StorageSchema, Trigger, UpdateTriggerInTxn } from "../types"; +import { AuthDef, AuthDefDict, CascadeRelationItem, Checker, CreateTriggerInTxn, EntityDict, LogicalRelationChecker, ExpressionTask, ExpressionTaskCombination, OperateOption, RefOrExpression, RelationHierarchy, CascadeRelationAuth, SelectOption, StorageSchema, Trigger, UpdateTriggerInTxn } from "../types"; import { EntityDict as BaseEntityDict } from '../base-app-domain'; import { AsyncContext } from "./AsyncRowStore"; import { getFullProjection } from './actionDef'; @@ -96,39 +96,14 @@ export function translateCheckerInAsyncContext< return 0; }) as UpdateTriggerInTxn['fn']; } - case 'expression': - case 'expressionRelation': { - const { expression, errMsg } = checker; + case 'logical': + case 'logicalRelation': { + const { checker: checkerFn } = checker; return (async ({ operation }, context, option) => { - if (context.isRoot() && type === 'expressionRelation') { + if (context.isRoot() && type === 'logicalRelation') { return 0; } - const exprResult = await expression(operation, context, option); - if (typeof exprResult === 'string') { - throw new OakUserUnpermittedException(exprResult || errMsg); - } - else if (exprResult === undefined) { - return 0; - } - else { - const { entity: expressionEntity, expr, filter: expressionFilter } = exprResult; - const [result] = await context.select(expressionEntity, { - data: { - $expr: expr, - }, - filter: expressionFilter, - }, Object.assign({}, option, { dontCollect: true })); - const isLegal = result ? result.$expr as boolean : false; - if (!isLegal) { - // 条件判定为假,抛异常 - if (type === 'expression') { - throw new OakRowInconsistencyException(undefined, errMsg); - } - else { - throw new OakUserUnpermittedException(errMsg); - } - } - } + await checkerFn(operation, context, option); return 0; }) as UpdateTriggerInTxn['fn']; } @@ -184,40 +159,14 @@ export function translateCheckerInSyncContext< throw new OakUserUnpermittedException(errMsg); }; } - case 'expression': - case 'expressionRelation': { - const { expression, errMsg } = checker; + case 'logical': + case 'logicalRelation': { + const { checker: checkerFn } = checker; return (operation, context, option) => { - if (context.isRoot() && type === 'expressionRelation') { + if (context.isRoot() && type === 'logicalRelation') { return; } - const exprResult = expression(operation, context, option); - if (typeof exprResult === 'string') { - throw new OakUserUnpermittedException(exprResult || errMsg); - } - else if (exprResult === undefined) { - return 0; - } - else { - assert(!(exprResult instanceof Promise)); - const { entity: expressionEntity, expr, filter: expressionFilter } = exprResult; - const [result] = context.select(expressionEntity, { - data: { - $expr: expr, - }, - filter: expressionFilter, - }, Object.assign({}, option, { dontCollect: true })); - const isLegal = result ? result.$expr as boolean : false; - if (!isLegal) { - // 条件判定为假,抛异常 - if (type === 'expression') { - throw new OakRowInconsistencyException(undefined, errMsg); - } - else { - throw new OakUserUnpermittedException(errMsg); - } - } - } + checkerFn(operation, context, option); }; } default: { @@ -386,8 +335,8 @@ export function createAuthCheckers { + type: 'relation', + relationFilter: (operation, context) => { const { data } = operation as ED[keyof ED]['Create']; assert(!(data instanceof Array)); const { relation, [entityIdAttr]: entityId } = data; @@ -396,15 +345,7 @@ export function createAuthCheckers | Array>; + when?: 'after'; + action: ED[T]['Action'] | Array; relationFilter: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ED[T]['Selection']['filter'] | Promise; // 生成一个额外的relation相关的filter,加在原先的filter上 errMsg: string; conditionalFilter?: ED[T]['Update']['filter'] | ( @@ -59,39 +60,37 @@ export type ExpressionTask = { export type ExpressionTaskCombination = ExpressionTask; -export type ExpressionChecker | SyncContext> = { +export type LogicalChecker | SyncContext> = { priority?: number; - type: 'expression'; + type: 'logical'; when?: 'after'; entity: T; action: ED[T]['Action'] | Array; - expression: ( + checker: ( operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption - ) => ExpressionTaskCombination | undefined | string | Promise | string | undefined> ; // 生成一个带表达式的查询任务数组,表达式结果为true代表可以过(or关系)。如果返回undefined直接过,返回string直接挂 - errMsg: string; + ) => void | Promise; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); }; -export type ExpressionRelationChecker | SyncContext> = { +export type LogicalRelationChecker | SyncContext> = { priority?: number; - type: 'expressionRelation'; + type: 'logicalRelation'; when?: 'after'; entity: T; action: ED[T]['Action'] | Array; - expression: ( + checker: ( operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption - ) => ExpressionTaskCombination | undefined | string | Promise | string | undefined> ; // 生成一个带表达式的查询任务数组,表达式结果为true代表可以过(or关系)。如果返回undefined直接过,返回string直接挂 - errMsg: string; + ) => void | Promise; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); }; export type Checker | SyncContext> = - DataChecker | RowChecker | RelationChecker | ExpressionChecker | ExpressionRelationChecker; + DataChecker | RowChecker | RelationChecker | LogicalChecker | LogicalRelationChecker; export type AuthDef = { From 325ba690680415890c29e268674dff066b257943 Mon Sep 17 00:00:00 2001 From: wenjiarui Date: Wed, 18 Jan 2023 12:00:49 +0800 Subject: [PATCH 11/19] excelDate --- src/utils/date.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/utils/date.ts diff --git a/src/utils/date.ts b/src/utils/date.ts new file mode 100644 index 0000000..8f3e66d --- /dev/null +++ b/src/utils/date.ts @@ -0,0 +1,14 @@ +import dayjs from 'dayjs'; + +export function excelStringToDate(str: string | number) { + if (!str) { + return undefined; + } + if (typeof str === 'number') { + if (str < 100000) { + return dayjs((((str - 25569) * 24 - 8) * 3600) * 1000).valueOf(); // excel日期可能为1900-1-1至今的天数 + } + return dayjs(str).valueOf(); + } + return Date.parse(str); +} \ No newline at end of file From db2447bf9be342ffe25f0bcb9059cec14e1b2f15 Mon Sep 17 00:00:00 2001 From: wenjiarui Date: Wed, 18 Jan 2023 12:04:30 +0800 Subject: [PATCH 12/19] build --- lib/utils/date.d.ts | 1 + lib/utils/date.js | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 lib/utils/date.d.ts create mode 100644 lib/utils/date.js diff --git a/lib/utils/date.d.ts b/lib/utils/date.d.ts new file mode 100644 index 0000000..dfb8c6f --- /dev/null +++ b/lib/utils/date.d.ts @@ -0,0 +1 @@ +export declare function excelStringToDate(str: string | number): number | undefined; diff --git a/lib/utils/date.js b/lib/utils/date.js new file mode 100644 index 0000000..5b6dc09 --- /dev/null +++ b/lib/utils/date.js @@ -0,0 +1,18 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.excelStringToDate = void 0; +var tslib_1 = require("tslib"); +var dayjs_1 = tslib_1.__importDefault(require("dayjs")); +function excelStringToDate(str) { + if (!str) { + return undefined; + } + if (typeof str === 'number') { + if (str < 100000) { + return (0, dayjs_1.default)((((str - 25569) * 24 - 8) * 3600) * 1000).valueOf(); // excel日期可能为1900-1-1至今的天数 + } + return (0, dayjs_1.default)(str).valueOf(); + } + return Date.parse(str); +} +exports.excelStringToDate = excelStringToDate; From c2017e062dff4fe3204473e4e375d702cdaa79be Mon Sep 17 00:00:00 2001 From: "Xc@centOs" Date: Wed, 18 Jan 2023 17:10:48 +0800 Subject: [PATCH 13/19] =?UTF-8?q?checker=E7=9A=84=E9=87=8D=E5=AE=9A?= =?UTF-8?q?=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/compiler/schemalBuilder.js | 3 + lib/store/TriggerExecutor.js | 4 +- lib/store/checker.d.ts | 10 ++- lib/store/checker.js | 139 ++++++++++++------------------ lib/types/Auth.d.ts | 9 +- src/compiler/schemalBuilder.ts | 13 +++ src/store/TriggerExecutor.ts | 4 +- src/store/checker.ts | 152 +++++++++++++++------------------ src/types/Auth.ts | 10 +-- 9 files changed, 157 insertions(+), 187 deletions(-) diff --git a/lib/compiler/schemalBuilder.js b/lib/compiler/schemalBuilder.js index bbf7d86..c50ecf4 100644 --- a/lib/compiler/schemalBuilder.js +++ b/lib/compiler/schemalBuilder.js @@ -2808,6 +2808,9 @@ function outputSchema(outputDir, printer) { if (ActionAsts[entity]) { EntityDefAttrs.push(factory.createPropertySignature(undefined, factory.createIdentifier("ParticularAction"), undefined, factory.createTypeReferenceNode(factory.createIdentifier('ParticularAction'), undefined))); } + if (typeof Schema[entity].hasRelationDef === 'object' && ts.isTypeAliasDeclaration(Schema[entity].hasRelationDef)) { + EntityDefAttrs.push(factory.createPropertySignature(undefined, factory.createIdentifier("Relation"), undefined, factory.createTypeReferenceNode(factory.createIdentifier('Relation'), undefined))); + } statements.push(factory.createTypeAliasDeclaration(undefined, [factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("EntityDef"), undefined, factory.createTypeLiteralNode(EntityDefAttrs))); var result = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray(statements), Schema[entity].sourceFile); var fileName = path_1.default.join(outputDir, entity, 'Schema.ts'); diff --git a/lib/store/TriggerExecutor.js b/lib/store/TriggerExecutor.js index 6b0d21b..0e51be6 100644 --- a/lib/store/TriggerExecutor.js +++ b/lib/store/TriggerExecutor.js @@ -32,7 +32,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 fn = (0, checker_1.translateCheckerInAsyncContext)(checker); + var _a = (0, checker_1.translateCheckerInAsyncContext)(checker), fn = _a.fn, when = _a.when; var trigger = { checkerType: type, name: triggerName, @@ -40,7 +40,7 @@ var TriggerExecutor = /** @class */ (function () { entity: entity, action: action, fn: fn, - when: checker.when || 'before', + when: when, filter: conditionalFilter, }; this.registerTrigger(trigger); diff --git a/lib/store/checker.d.ts b/lib/store/checker.d.ts index dc7e6fd..533c708 100644 --- a/lib/store/checker.d.ts +++ b/lib/store/checker.d.ts @@ -2,6 +2,12 @@ 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): Trigger['fn']; -export declare function translateCheckerInSyncContext>(checker: Checker): (operation: ED[T]['Operation'], context: Cxt, option: OperateOption | SelectOption) => void; +export declare function translateCheckerInAsyncContext>(checker: Checker): { + fn: Trigger['fn']; + when: 'before' | 'after'; +}; +export declare function translateCheckerInSyncContext>(checker: Checker): { + fn: (operation: ED[T]['Operation'], context: Cxt, option: OperateOption | SelectOption) => void; + when: 'before' | 'after'; +}; export declare function createAuthCheckers | SyncContext>(schema: StorageSchema, authDict: AuthDefDict): Checker[]; diff --git a/lib/store/checker.js b/lib/store/checker.js index ffa50da..7864cdd 100644 --- a/lib/store/checker.js +++ b/lib/store/checker.js @@ -11,11 +11,12 @@ var lodash_1 = require("../utils/lodash"); var relation_1 = require("./relation"); function translateCheckerInAsyncContext(checker) { var _this = this; - var entity = checker.entity, type = checker.type; + var entity = checker.entity, type = checker.type, action = checker.action; + var when = ((action === 'create' || action instanceof Array && action.includes('create')) && ['relation'].includes(type)) ? 'after' : 'before'; switch (type) { case 'data': { var checkerFn_1 = checker.checker; - return (function (_a, context) { + var fn = (function (_a, context) { var operation = _a.operation; return tslib_1.__awaiter(_this, void 0, void 0, function () { var data; @@ -31,10 +32,14 @@ function translateCheckerInAsyncContext(checker) { }); }); }); + return { + fn: fn, + when: when, + }; } case 'row': { var filter_2 = checker.filter, errMsg_1 = checker.errMsg, inconsistentRows_1 = checker.inconsistentRows; - return (function (_a, context, option) { + 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, data_1, rows2, data_2; @@ -110,10 +115,14 @@ function translateCheckerInAsyncContext(checker) { }); }); }); + return { + fn: fn, + when: when, + }; } case 'relation': { var relationFilter_1 = checker.relationFilter; - return (function (_a, context, option) { + var fn = (function (_a, context, option) { var operation = _a.operation; return tslib_1.__awaiter(_this, void 0, void 0, function () { var _b, _c, _d; @@ -137,11 +146,15 @@ function translateCheckerInAsyncContext(checker) { }); }); }); + return { + fn: fn, + when: when, + }; } case 'logical': case 'logicalRelation': { var checkerFn_2 = checker.checker; - return (function (_a, context, option) { + 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) { @@ -158,6 +171,10 @@ function translateCheckerInAsyncContext(checker) { }); }); }); + return { + fn: fn, + when: when, + }; } default: { (0, assert_1.default)(false); @@ -166,15 +183,20 @@ function translateCheckerInAsyncContext(checker) { } exports.translateCheckerInAsyncContext = translateCheckerInAsyncContext; function translateCheckerInSyncContext(checker) { - var entity = checker.entity, type = checker.type; + var entity = checker.entity, type = checker.type, action = checker.action; + var when = ((action === 'create' || action instanceof Array && action.includes('create')) && ['relation'].includes(type)) ? 'after' : 'before'; switch (type) { case 'data': { var checkerFn_3 = checker.checker; - return function (operation, context) { return checkerFn_3(operation.data, context); }; + 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; - return function (operation, context, option) { + 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); @@ -190,10 +212,14 @@ function translateCheckerInSyncContext(checker) { throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_2); } }; + return { + fn: fn, + when: when, + }; } case 'relation': { var filter_4 = checker.relationFilter, errMsg_3 = checker.errMsg; - return function (operation, context, option) { + var fn = function (operation, context, option) { if (context.isRoot()) { return; } @@ -206,16 +232,24 @@ function translateCheckerInSyncContext(checker) { } throw new Exception_1.OakUserUnpermittedException(errMsg_3); }; + return { + fn: fn, + when: when, + }; } case 'logical': case 'logicalRelation': { var checkerFn_4 = checker.checker; - return function (operation, context, option) { + 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); @@ -223,31 +257,6 @@ function translateCheckerInSyncContext(checker) { } } exports.translateCheckerInSyncContext = translateCheckerInSyncContext; -function buildReverseHierarchyMap(relationHierarchy) { - var e_1, _a; - var reverseHierarchy = {}; - for (var r in relationHierarchy) { - try { - for (var _b = (e_1 = void 0, tslib_1.__values(relationHierarchy[r])), _c = _b.next(); !_c.done; _c = _b.next()) { - var r2 = _c.value; - if (!reverseHierarchy[r2]) { - reverseHierarchy[r2] = [r]; - } - else { - reverseHierarchy[r2].push(r); - } - } - } - catch (e_1_1) { e_1 = { error: e_1_1 }; } - finally { - try { - if (_c && !_c.done && (_a = _b.return)) _a.call(_b); - } - finally { if (e_1) throw e_1.error; } - } - } - return reverseHierarchy; -} function translateCascadeRelationFilterMaker(schema, lch, entity2) { var cascadePath = lch.cascadePath, relations = lch.relations; var paths = cascadePath.split('.'); @@ -401,7 +410,7 @@ function createAuthCheckers(schema, authDict) { var relations = (0, lodash_1.uniq)(rows.map(function (ele) { return ele.relation; })); var entityIds = (0, lodash_1.uniq)(rows.map(function (ele) { return ele[entityIdAttr_1]; })); (0, assert_1.default)(entityIds.length === 1, "\u5728\u56DE\u6536".concat(userEntityName_1, "\u4E0A\u6743\u9650\u65F6\uFF0C\u5355\u6B21\u56DE\u6536\u6D89\u53CA\u5230\u4E86\u4E0D\u540C\u7684\u5BF9\u8C61\uFF0C\u6B64\u64CD\u4F5C\u4E0D\u88AB\u5141\u8BB8")); - var entityId = entityIds[0]; + // const entityId = entityIds[0]!; // 所有的relation条件要同时满足and关系(注意这里的filter翻译出来是在entity对象上,不是在userEntity对象上) return { $and: relations.map(function (relation) { return raFilterMakerDict_1[relation]; }).filter(function (ele) { return !!ele; }).map(function (ele) { @@ -434,53 +443,17 @@ function createAuthCheckers(schema, authDict) { if (actionAuth) { var _loop_2 = function (a) { var filterMaker = translateActionAuthFilterMaker(schema, actionAuth[a], entity); - if (a === 'create') { - /** - * create动作所增加的auth约束只可能在外键的对象上,但因为还有级联和触发器,不太容易在创建前检查,先放在创建后 - */ - var _c = actionAuth[a]; - /* checkers.push({ - entity, - action: a, - type: 'expressionRelation', - when: 'after', - expression: (operation, context) => { - // 在插入后检查 - const makeExprInner = (data: ED[keyof ED]['CreateSingle']['data']) => { - const { id } = data; - return { - entity, - filter: combineFilters([filter, { id }]), - expr: { - $gt: [{ - '#attr': '$$createAt$$', - }, 0] as any - }, - }; - }; - const filter = filterMaker(context.getCurrentUserId()!); - const { data } = operation as ED[keyof ED]['Create']; - if (data instanceof Array) { - throw new Error('需要expr支持count'); - } - return makeExprInner(data); - }, - errMsg: '定义的actionAuth中检查出来越权操作', - }); */ - } - else { - checkers.push({ - entity: entity, - action: a, - type: 'relation', - relationFilter: function (operation, context) { - // const { filter } = operation; - var filter = filterMaker(context.getCurrentUserId()); - return filter; - }, - errMsg: '定义的actionAuth中检查出来越权操作', - }); - } + checkers.push({ + entity: entity, + action: a, + type: 'relation', + relationFilter: function (operation, context) { + // const { filter } = operation; + var filter = filterMaker(context.getCurrentUserId()); + return filter; + }, + errMsg: '定义的actionAuth中检查出来越权操作', + }); }; for (var a in actionAuth) { _loop_2(a); diff --git a/lib/types/Auth.d.ts b/lib/types/Auth.d.ts index 8d7b513..cee2d7b 100644 --- a/lib/types/Auth.d.ts +++ b/lib/types/Auth.d.ts @@ -2,8 +2,7 @@ import { CascadeActionAuth, CascadeRelationAuth } from "."; import { AsyncContext } from "../store/AsyncRowStore"; import { SyncContext } from "../store/SyncRowStore"; import { EntityDict, OperateOption, SelectOption } from "../types/Entity"; -import { RefOrExpression } from "./Expression"; -export declare type CheckerType = 'relation' | 'row' | 'data' | 'expression' | 'expressionRelation'; +export declare type CheckerType = 'relation' | 'row' | 'data' | 'logical' | 'logicalRelation'; /** * conditionalFilter是指该action发生时,operation所操作的行中有满足conditionalFilter的行 * 被转化成trigger的filter条件,详细可看trigger中的说明 @@ -39,12 +38,6 @@ export declare type RelationChecker ED[T]['Update']['filter'] | Promise); }; -export declare type ExpressionTask = { - entity: T; - expr: RefOrExpression; - filter: ED[T]['Selection']['filter']; -}; -export declare type ExpressionTaskCombination = ExpressionTask; export declare type LogicalChecker | SyncContext> = { priority?: number; type: 'logical'; diff --git a/src/compiler/schemalBuilder.ts b/src/compiler/schemalBuilder.ts index f7c86e9..08a2a9e 100644 --- a/src/compiler/schemalBuilder.ts +++ b/src/compiler/schemalBuilder.ts @@ -5068,6 +5068,19 @@ function outputSchema(outputDir: string, printer: ts.Printer) { ) ); } + if (typeof Schema[entity].hasRelationDef === 'object' && ts.isTypeAliasDeclaration(Schema[entity].hasRelationDef as ts.Node)) { + EntityDefAttrs.push( + factory.createPropertySignature( + undefined, + factory.createIdentifier("Relation"), + undefined, + factory.createTypeReferenceNode( + factory.createIdentifier('Relation'), + undefined + ) + ) + ); + } statements.push( factory.createTypeAliasDeclaration( undefined, diff --git a/src/store/TriggerExecutor.ts b/src/store/TriggerExecutor.ts index f3070af..67a2c61 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 = translateCheckerInAsyncContext(checker); + const { fn, when } = translateCheckerInAsyncContext(checker); const trigger = { checkerType: type, name: triggerName, @@ -57,7 +57,7 @@ export class TriggerExecutor { entity, action: action as 'update', fn, - when: (checker as LogicalChecker).when || 'before', + when, filter: conditionalFilter, } as UpdateTrigger; this.registerTrigger(trigger); diff --git a/src/store/checker.ts b/src/store/checker.ts index 09b88a4..4e51009 100644 --- a/src/store/checker.ts +++ b/src/store/checker.ts @@ -1,32 +1,41 @@ import assert from 'assert'; import { addFilterSegment, checkFilterContains, combineFilters } from "../store/filter"; -import { OakDataException, OakRowInconsistencyException, OakUserUnpermittedException } from '../types/Exception'; -import { AuthDef, AuthDefDict, CascadeRelationItem, Checker, CreateTriggerInTxn, EntityDict, LogicalRelationChecker, ExpressionTask, ExpressionTaskCombination, OperateOption, RefOrExpression, RelationHierarchy, CascadeRelationAuth, SelectOption, StorageSchema, Trigger, UpdateTriggerInTxn } from "../types"; +import { OakRowInconsistencyException, OakUserUnpermittedException } from '../types/Exception'; +import { AuthDefDict, CascadeRelationItem, Checker, CreateTriggerInTxn, + EntityDict, OperateOption, SelectOption, StorageSchema, Trigger, UpdateTriggerInTxn, RelationHierarchy } from "../types"; import { EntityDict as BaseEntityDict } from '../base-app-domain'; import { AsyncContext } from "./AsyncRowStore"; import { getFullProjection } from './actionDef'; import { SyncContext } from './SyncRowStore'; import { firstLetterUpperCase } from '../utils/string'; -import { intersection, uniq } from '../utils/lodash'; +import { uniq } from '../utils/lodash'; import { judgeRelation } from './relation'; export function translateCheckerInAsyncContext< ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext ->(checker: Checker): Trigger['fn'] { - const { entity, type } = checker; +>(checker: Checker): { + fn: Trigger['fn']; + when: 'before' | 'after'; +} { + const { entity, type, action } = checker; + const when = ((action === 'create' || action instanceof Array && action.includes('create')) && ['relation'].includes(type)) ? 'after' : 'before' switch (type) { case 'data': { const { checker: checkerFn } = checker; - return (async ({ operation }, context) => { + const fn = (async ({ operation }, context) => { const { data } = operation; await checkerFn(data, context); return 0; }) as CreateTriggerInTxn['fn']; + return { + fn, + when, + }; } case 'row': { const { filter, errMsg, inconsistentRows } = checker; - return (async ({ operation }, context, option) => { + const fn = (async ({ operation }, context, option) => { const { filter: operationFilter, action } = operation; const filter2 = typeof filter === 'function' ? await filter(operation, context, option) : filter; if (['select', 'count', 'stat'].includes(action)) { @@ -83,10 +92,14 @@ export function translateCheckerInAsyncContext< } } }) as UpdateTriggerInTxn['fn']; + return { + fn, + when, + }; } case 'relation': { const { relationFilter } = checker; - return (async ({ operation }, context, option) => { + const fn = (async ({ operation }, context, option) => { if (context.isRoot()) { return 0; } @@ -95,17 +108,25 @@ export function translateCheckerInAsyncContext< operation.filter = combineFilters([operation.filter, await relationFilter(operation, context, option)]); return 0; }) as UpdateTriggerInTxn['fn']; + return { + fn, + when, + }; } case 'logical': case 'logicalRelation': { const { checker: checkerFn } = checker; - return (async ({ operation }, context, option) => { + const fn = (async ({ operation }, context, option) => { if (context.isRoot() && type === 'logicalRelation') { return 0; } await checkerFn(operation, context, option); return 0; }) as UpdateTriggerInTxn['fn']; + return { + fn, + when, + }; } default: { assert(false); @@ -117,16 +138,24 @@ export function translateCheckerInSyncContext< ED extends EntityDict & BaseEntityDict, T extends keyof ED, Cxt extends SyncContext ->(checker: Checker): (operation: ED[T]['Operation'], context: Cxt, option: OperateOption | SelectOption) => void { - const { entity, type } = checker; +>(checker: Checker): { + fn: (operation: ED[T]['Operation'], context: Cxt, option: OperateOption | SelectOption) => void; + when: 'before' | 'after'; +} { + const { entity, type, action } = checker; + const when = ((action === 'create' || action instanceof Array && action.includes('create')) && ['relation'].includes(type)) ? 'after' : 'before' switch (type) { case 'data': { const { checker: checkerFn } = checker; - return (operation, context) => checkerFn(operation.data, context); + const fn = (operation: ED[T]['Operation'], context: Cxt) => checkerFn(operation.data, context); + return { + fn, + when, + } } case 'row': { const { filter, errMsg } = checker; - return (operation, context, option) => { + const fn = (operation: ED[T]['Operation'], context: Cxt, option: OperateOption | SelectOption) => { const { filter: operationFilter, action } = operation; const filter2 = typeof filter === 'function' ? filter(operation, context, option) : filter; assert(operationFilter); @@ -142,10 +171,14 @@ export function translateCheckerInSyncContext< throw new OakRowInconsistencyException(undefined, errMsg); } }; + return { + fn, + when, + }; } case 'relation': { const { relationFilter: filter, errMsg } = checker; - return (operation, context, option) => { + const fn = (operation: ED[T]['Operation'], context: Cxt, option: OperateOption | SelectOption) => { if (context.isRoot()) { return; } @@ -158,16 +191,24 @@ export function translateCheckerInSyncContext< } throw new OakUserUnpermittedException(errMsg); }; + return { + fn, + when, + }; } case 'logical': case 'logicalRelation': { const { checker: checkerFn } = checker; - return (operation, context, option) => { + const fn = (operation: ED[T]['Operation'], context: Cxt, option: OperateOption | SelectOption) => { if (context.isRoot() && type === 'logicalRelation') { return; } checkerFn(operation, context, option); }; + return { + fn, + when, + }; } default: { assert(false); @@ -175,26 +216,10 @@ export function translateCheckerInSyncContext< } } - -function buildReverseHierarchyMap(relationHierarchy: RelationHierarchy) { - const reverseHierarchy = {} as Record; - for (const r in relationHierarchy) { - for (const r2 of relationHierarchy[r]!) { - if (!reverseHierarchy[r2]) { - reverseHierarchy[r2] = [r]; - } - else { - reverseHierarchy[r2].push(r); - } - } - } - return reverseHierarchy; -} - function translateCascadeRelationFilterMaker( schema: StorageSchema, lch: CascadeRelationItem, - entity2: keyof ED): (userId: string) => ExpressionTask['filter'] { + entity2: keyof ED): (userId: string) => ED[keyof ED]['Selection']['filter'] { const { cascadePath, relations } = lch; const paths = cascadePath.split('.'); @@ -315,6 +340,7 @@ function translateActionAuthFilterMaker( return (userId) => filterMaker(userId); } + export function createAuthCheckers | SyncContext>( schema: StorageSchema, authDict: AuthDefDict) { @@ -361,7 +387,7 @@ export function createAuthCheckers ele.relation)); const entityIds = uniq(rows.map(ele => ele[entityIdAttr])); assert(entityIds.length === 1, `在回收${userEntityName}上权限时,单次回收涉及到了不同的对象,此操作不被允许`); - const entityId = entityIds[0]!; + // const entityId = entityIds[0]!; // 所有的relation条件要同时满足and关系(注意这里的filter翻译出来是在entity对象上,不是在userEntity对象上) return { @@ -400,54 +426,18 @@ export function createAuthCheckers { - // 在插入后检查 - const makeExprInner = (data: ED[keyof ED]['CreateSingle']['data']) => { - const { id } = data; - return { - entity, - filter: combineFilters([filter, { id }]), - expr: { - $gt: [{ - '#attr': '$$createAt$$', - }, 0] as any - }, - }; - }; - const filter = filterMaker(context.getCurrentUserId()!); - const { data } = operation as ED[keyof ED]['Create']; - if (data instanceof Array) { - throw new Error('需要expr支持count'); - } - return makeExprInner(data); - }, - errMsg: '定义的actionAuth中检查出来越权操作', - }); */ - } - else { - checkers.push({ - entity, - action: a as ED[keyof ED]['Action'], - type: 'relation', - relationFilter: (operation, context) => { - // const { filter } = operation; - const filter = filterMaker(context.getCurrentUserId()!); - return filter; - }, - errMsg: '定义的actionAuth中检查出来越权操作', - }); - } + const filterMaker = translateActionAuthFilterMaker(schema, actionAuth[a as ED[keyof ED]['Action']]!, entity); + checkers.push({ + entity, + action: a as ED[keyof ED]['Action'], + type: 'relation', + relationFilter: (operation, context) => { + // const { filter } = operation; + const filter = filterMaker(context.getCurrentUserId()!); + return filter; + }, + errMsg: '定义的actionAuth中检查出来越权操作', + }); } } } diff --git a/src/types/Auth.ts b/src/types/Auth.ts index 10cbedf..c218609 100644 --- a/src/types/Auth.ts +++ b/src/types/Auth.ts @@ -4,7 +4,7 @@ import { SyncContext } from "../store/SyncRowStore"; import { EntityDict, OperateOption, SelectOption } from "../types/Entity"; import { RefOrExpression } from "./Expression"; -export type CheckerType = 'relation' | 'row' | 'data' | 'expression' | 'expressionRelation'; +export type CheckerType = 'relation' | 'row' | 'data' | 'logical' | 'logicalRelation'; /** * conditionalFilter是指该action发生时,operation所操作的行中有满足conditionalFilter的行 @@ -52,14 +52,6 @@ export type RelationChecker = { - entity: T; - expr: RefOrExpression; - filter: ED[T]['Selection']['filter']; -}; - -export type ExpressionTaskCombination = ExpressionTask; - export type LogicalChecker | SyncContext> = { priority?: number; type: 'logical'; From 5fbb9819d730e1c299f5b76d0f7651fd91200a46 Mon Sep 17 00:00:00 2001 From: Xc Date: Wed, 18 Jan 2023 23:08:42 +0800 Subject: [PATCH 14/19] =?UTF-8?q?checker=E7=9A=84=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=AE=9E=E7=8E=B0=E4=B8=8E=E8=B0=83=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/actions/relation.d.ts | 4 ++ lib/actions/relation.js | 36 ++++++++++++ lib/base-app-domain/Modi/Schema.d.ts | 2 - lib/base-app-domain/ModiEntity/Schema.d.ts | 2 - lib/base-app-domain/Oper/Schema.d.ts | 2 - lib/base-app-domain/OperEntity/Schema.d.ts | 2 - lib/base-app-domain/User/Schema.d.ts | 2 - lib/checkers/index.js | 7 ++- lib/compiler/schemalBuilder.js | 3 +- lib/store/checker.js | 67 ++++++++++++++++------ src/actions/relation.ts | 31 +++++++++- src/checkers/index.ts | 4 +- src/compiler/schemalBuilder.ts | 3 +- src/store/checker.ts | 65 +++++++++++++++------ 14 files changed, 177 insertions(+), 53 deletions(-) diff --git a/lib/actions/relation.d.ts b/lib/actions/relation.d.ts index e5081a1..d012b77 100644 --- a/lib/actions/relation.d.ts +++ b/lib/actions/relation.d.ts @@ -1 +1,5 @@ +import { CascadeRelationItem, RelationHierarchy } from "../types/Entity"; export declare type GenericRelation = 'owner'; +export declare function convertHierarchyToAuth(hierarchy: RelationHierarchy): { + [K in R]?: CascadeRelationItem; +}; diff --git a/lib/actions/relation.js b/lib/actions/relation.js index c8ad2e5..174f3fe 100644 --- a/lib/actions/relation.js +++ b/lib/actions/relation.js @@ -1,2 +1,38 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); +exports.convertHierarchyToAuth = void 0; +var tslib_1 = require("tslib"); +function convertHierarchyToAuth(hierarchy) { + var e_1, _a; + var _b; + var reverseHierarchy = {}; + for (var r in hierarchy) { + try { + for (var _c = (e_1 = void 0, tslib_1.__values(hierarchy[r])), _d = _c.next(); !_d.done; _d = _c.next()) { + var r2 = _d.value; + if (reverseHierarchy[r2]) { + (_b = reverseHierarchy[r2]) === null || _b === void 0 ? void 0 : _b.push(r); + } + else { + reverseHierarchy[r2] = [r]; + } + } + } + catch (e_1_1) { e_1 = { error: e_1_1 }; } + finally { + try { + if (_d && !_d.done && (_a = _c.return)) _a.call(_c); + } + finally { if (e_1) throw e_1.error; } + } + } + var result = {}; + for (var r in reverseHierarchy) { + result[r] = { + cascadePath: '', + relations: reverseHierarchy[r], + }; + } + return result; +} +exports.convertHierarchyToAuth = convertHierarchyToAuth; diff --git a/lib/base-app-domain/Modi/Schema.d.ts b/lib/base-app-domain/Modi/Schema.d.ts index dd96db2..eafd1be 100644 --- a/lib/base-app-domain/Modi/Schema.d.ts +++ b/lib/base-app-domain/Modi/Schema.d.ts @@ -129,8 +129,6 @@ export declare type RemoveOperationData = {}; export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation | SelectOperation; export declare type ModiIdSubQuery = Selection; -export declare type NativeAttr = OpAttr; -export declare type FullAttr = NativeAttr | `modiEntitys$${number}.${ModiEntity.NativeAttr}` | `operEntitys$${number}.${OperEntity.NativeAttr}`; export declare type EntityDef = { Schema: Schema; OpSchema: OpSchema; diff --git a/lib/base-app-domain/ModiEntity/Schema.d.ts b/lib/base-app-domain/ModiEntity/Schema.d.ts index b09482d..b664da1 100644 --- a/lib/base-app-domain/ModiEntity/Schema.d.ts +++ b/lib/base-app-domain/ModiEntity/Schema.d.ts @@ -146,8 +146,6 @@ export declare type Operation = CreateOperation | UpdateOperation | RemoveOperat export declare type ModiIdSubQuery = Selection; export declare type UserIdSubQuery = Selection; export declare type ModiEntityIdSubQuery = Selection; -export declare type NativeAttr = OpAttr | `modi.${Modi.NativeAttr}` | `entity.${User.NativeAttr}`; -export declare type FullAttr = NativeAttr; export declare type EntityDef = { Schema: Schema; OpSchema: OpSchema; diff --git a/lib/base-app-domain/Oper/Schema.d.ts b/lib/base-app-domain/Oper/Schema.d.ts index d8d1e5b..1aefe36 100644 --- a/lib/base-app-domain/Oper/Schema.d.ts +++ b/lib/base-app-domain/Oper/Schema.d.ts @@ -128,8 +128,6 @@ export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation | SelectOperation; export declare type UserIdSubQuery = Selection; export declare type OperIdSubQuery = Selection; -export declare type NativeAttr = OpAttr | `operator.${User.NativeAttr}`; -export declare type FullAttr = NativeAttr | `operEntitys$${number}.${OperEntity.NativeAttr}`; export declare type EntityDef = { Schema: Schema; OpSchema: OpSchema; diff --git a/lib/base-app-domain/OperEntity/Schema.d.ts b/lib/base-app-domain/OperEntity/Schema.d.ts index f23f394..413ecf2 100644 --- a/lib/base-app-domain/OperEntity/Schema.d.ts +++ b/lib/base-app-domain/OperEntity/Schema.d.ts @@ -162,8 +162,6 @@ export declare type OperIdSubQuery = Selection; export declare type ModiIdSubQuery = Selection; export declare type UserIdSubQuery = Selection; export declare type OperEntityIdSubQuery = Selection; -export declare type NativeAttr = OpAttr | `oper.${Oper.NativeAttr}` | `entity.${Modi.NativeAttr}` | `entity.${User.NativeAttr}`; -export declare type FullAttr = NativeAttr; export declare type EntityDef = { Schema: Schema; OpSchema: OpSchema; diff --git a/lib/base-app-domain/User/Schema.d.ts b/lib/base-app-domain/User/Schema.d.ts index c747fbc..07b8ee2 100644 --- a/lib/base-app-domain/User/Schema.d.ts +++ b/lib/base-app-domain/User/Schema.d.ts @@ -112,8 +112,6 @@ export declare type RemoveOperationData = {}; export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation | SelectOperation; export declare type UserIdSubQuery = Selection; -export declare type NativeAttr = OpAttr; -export declare type FullAttr = NativeAttr | `opers$${number}.${Oper.NativeAttr}` | `operEntitys$${number}.${OperEntity.NativeAttr}` | `modiEntitys$${number}.${ModiEntity.NativeAttr}`; export declare type EntityDef = { Schema: Schema; OpSchema: OpSchema; diff --git a/lib/checkers/index.js b/lib/checkers/index.js index fed2477..3c7f105 100644 --- a/lib/checkers/index.js +++ b/lib/checkers/index.js @@ -2,13 +2,14 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.createDynamicCheckers = void 0; var tslib_1 = require("tslib"); +var checker_1 = require("../store/checker"); var modi_1 = require("../store/modi"); function createDynamicCheckers(schema, authDict) { var checkers = []; checkers.push.apply(checkers, tslib_1.__spreadArray([], tslib_1.__read((0, modi_1.createModiRelatedCheckers)(schema)), false)); - /* if (authDict) { - checkers.push(...createAuthCheckers(schema, authDict)); - } */ + if (authDict) { + checkers.push.apply(checkers, tslib_1.__spreadArray([], tslib_1.__read((0, checker_1.createAuthCheckers)(schema, authDict)), false)); + } return checkers; } exports.createDynamicCheckers = createDynamicCheckers; diff --git a/lib/compiler/schemalBuilder.js b/lib/compiler/schemalBuilder.js index c50ecf4..4f10215 100644 --- a/lib/compiler/schemalBuilder.js +++ b/lib/compiler/schemalBuilder.js @@ -2776,7 +2776,8 @@ function outputSchema(outputDir, printer) { constructSorter(statements, entity); constructActions(statements, entity); constructQuery(statements, entity); - constructFullAttrs(statements, entity); + // 现在FullAttrs和NativeAttrs似乎没什么用,还会引起递归 + // constructFullAttrs(statements, entity); var makeActionArguments = []; if (ActionAsts[entity]) { makeActionArguments.push(factory.createTypeReferenceNode('Action')); diff --git a/lib/store/checker.js b/lib/store/checker.js index 7864cdd..e3a35d8 100644 --- a/lib/store/checker.js +++ b/lib/store/checker.js @@ -121,27 +121,44 @@ function translateCheckerInAsyncContext(checker) { }; } case 'relation': { - var relationFilter_1 = checker.relationFilter; + 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 _b, _c, _d; + var filter2, data, filter, _b, _c, _d; return tslib_1.__generator(this, function (_e) { switch (_e.label) { case 0: if (context.isRoot()) { return [2 /*return*/, 0]; } - (0, assert_1.default)(operation.action !== 'create', "".concat(entity, "\u4E0A\u7684create\u52A8\u4F5C\u5B9A\u4E49\u4E86relation\u7C7B\u578B\u7684checker,\u8BF7\u4F7F\u7528expressionRelation\u66FF\u4EE3")); - // 对后台而言,将生成的relationFilter加到filter之上(select可以在此加以权限的过滤) + if (!(operation.action === 'create')) return [3 /*break*/, 3]; + return [4 /*yield*/, relationFilter_1(operation, context, option)]; + case 1: + filter2 = _e.sent(); + data = operation.data; + filter = data instanceof Array ? { + id: { + $in: data.map(function (ele) { return ele.id; }), + }, + } : { + id: data.id, + }; + return [4 /*yield*/, (0, filter_1.checkFilterContains)(entity, context, filter2, filter, true)]; + case 2: + if (_e.sent()) { + return [2 /*return*/, 0]; + } + throw new Exception_1.OakUserUnpermittedException(errMsg_2); + case 3: _b = operation; _c = filter_1.combineFilters; _d = [operation.filter]; return [4 /*yield*/, relationFilter_1(operation, context, option)]; - case 1: - // 对后台而言,将生成的relationFilter加到filter之上(select可以在此加以权限的过滤) + case 4: _b.filter = _c.apply(void 0, [_d.concat([_e.sent()])]); - return [2 /*return*/, 0]; + _e.label = 5; + case 5: return [2 /*return*/, 0]; } }); }); @@ -195,7 +212,7 @@ 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; @@ -209,7 +226,7 @@ function translateCheckerInSyncContext(checker) { if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter, true)) { return; } - throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_2); + throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_3); } }; return { @@ -218,19 +235,28 @@ function translateCheckerInSyncContext(checker) { }; } case 'relation': { - var filter_4 = 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; } - var filter2 = typeof filter_4 === 'function' ? filter_4(operation, context, option) : filter_4; - var operationFilter = operation.filter; - (0, assert_1.default)(operationFilter); + var filter2 = typeof relationFilter_2 === 'function' ? relationFilter_2(operation, context, option) : relationFilter_2; + var filter = operation.filter, action = operation.action; + var filter3 = filter; + if (action === 'create') { + var data = operation.data; + filter3 = data instanceof Array ? { + id: { + $in: data.map(function (ele) { return ele.id; }), + }, + } : { id: data.id }; + } + (0, assert_1.default)(filter3); (0, assert_1.default)(!(filter2 instanceof Promise)); - if ((0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter, true)) { + if ((0, filter_1.checkFilterContains)(entity, context, filter2, filter3, true)) { return; } - throw new Exception_1.OakUserUnpermittedException(errMsg_3); + throw new Exception_1.OakUserUnpermittedException(errMsg_4); }; return { fn: fn, @@ -304,7 +330,7 @@ function translateCascadeRelationFilterMaker(schema, lch, entity2) { if (filter.$in) { return { entity: paths[iter], - entityId: filter + entityId: filter, }; } return _a = {}, @@ -346,7 +372,7 @@ function translateCascadeRelationFilterMaker(schema, lch, entity2) { }; } }; - var filter = paths.length > 0 ? translateFilterMakerIter(entity2, 0) : translateRelationFilter(entity2); + var filter = cascadePath ? translateFilterMakerIter(entity2, 0) : translateRelationFilter(entity2); return filter; } function translateActionAuthFilterMaker(schema, relationItem, entity) { @@ -386,15 +412,18 @@ function createAuthCheckers(schema, authDict) { action: 'create', type: 'relation', relationFilter: function (operation, context) { + var _a; var data = operation.data; (0, assert_1.default)(!(data instanceof Array)); - var _a = data, relation = _a.relation, _b = entityIdAttr_1, entityId = _a[_b]; + var _b = data, relation = _b.relation, _c = entityIdAttr_1, entityId = _b[_c]; var userId = context.getCurrentUserId(); if (!raFilterMakerDict_1[relation]) { return; } var filter = raFilterMakerDict_1[relation](userId); - return filter; + return _a = {}, + _a[entity] = filter, + _a; }, errMsg: '越权操作', }); diff --git a/src/actions/relation.ts b/src/actions/relation.ts index d59cadc..d958bd7 100644 --- a/src/actions/relation.ts +++ b/src/actions/relation.ts @@ -1 +1,30 @@ -export type GenericRelation = 'owner'; \ No newline at end of file +import { CascadeRelationItem, RelationHierarchy } from "../types/Entity"; + +export type GenericRelation = 'owner'; + +export function convertHierarchyToAuth(hierarchy: RelationHierarchy): { + [K in R]?: CascadeRelationItem; +} { + const reverseHierarchy: RelationHierarchy = {}; + for (const r in hierarchy) { + for (const r2 of hierarchy[r]!) { + if (reverseHierarchy[r2]) { + reverseHierarchy[r2]?.push(r); + } + else { + reverseHierarchy[r2] = [r]; + } + } + } + const result: { + [K in R]?: CascadeRelationItem; + } = {}; + for (const r in reverseHierarchy) { + result[r] = { + cascadePath: '', + relations: reverseHierarchy[r], + }; + } + + return result; +} \ No newline at end of file diff --git a/src/checkers/index.ts b/src/checkers/index.ts index 4a1c402..55f462d 100644 --- a/src/checkers/index.ts +++ b/src/checkers/index.ts @@ -8,8 +8,8 @@ import { StorageSchema, EntityDict as BaseEntityDict, Checker, AuthDef, AuthDefD export function createDynamicCheckers | SyncContext>(schema: StorageSchema, authDict?: AuthDefDict){ const checkers: Checker[] = []; checkers.push(...createModiRelatedCheckers(schema)); - /* if (authDict) { + if (authDict) { checkers.push(...createAuthCheckers(schema, authDict)); - } */ + } return checkers; } diff --git a/src/compiler/schemalBuilder.ts b/src/compiler/schemalBuilder.ts index 08a2a9e..866087d 100644 --- a/src/compiler/schemalBuilder.ts +++ b/src/compiler/schemalBuilder.ts @@ -4929,7 +4929,8 @@ function outputSchema(outputDir: string, printer: ts.Printer) { constructSorter(statements, entity); constructActions(statements, entity); constructQuery(statements, entity); - constructFullAttrs(statements, entity); + // 现在FullAttrs和NativeAttrs似乎没什么用,还会引起递归 + // constructFullAttrs(statements, entity); const makeActionArguments: ts.TypeNode[] = []; if (ActionAsts[entity]) { diff --git a/src/store/checker.ts b/src/store/checker.ts index 4e51009..c42639e 100644 --- a/src/store/checker.ts +++ b/src/store/checker.ts @@ -1,8 +1,10 @@ import assert from 'assert'; import { addFilterSegment, checkFilterContains, combineFilters } from "../store/filter"; import { OakRowInconsistencyException, OakUserUnpermittedException } from '../types/Exception'; -import { AuthDefDict, CascadeRelationItem, Checker, CreateTriggerInTxn, - EntityDict, OperateOption, SelectOption, StorageSchema, Trigger, UpdateTriggerInTxn, RelationHierarchy } from "../types"; +import { + AuthDefDict, CascadeRelationItem, Checker, CreateTriggerInTxn, + EntityDict, OperateOption, SelectOption, StorageSchema, Trigger, UpdateTriggerInTxn, RelationHierarchy +} from "../types"; import { EntityDict as BaseEntityDict } from '../base-app-domain'; import { AsyncContext } from "./AsyncRowStore"; import { getFullProjection } from './actionDef'; @@ -98,14 +100,34 @@ export function translateCheckerInAsyncContext< }; } case 'relation': { - const { relationFilter } = checker; + const { relationFilter, errMsg } = checker; const fn = (async ({ operation }, context, option) => { if (context.isRoot()) { return 0; } - assert(operation.action !== 'create', `${entity as string}上的create动作定义了relation类型的checker,请使用expressionRelation替代`); + // assert(operation.action !== 'create', `${entity as string}上的create动作定义了relation类型的checker,请使用expressionRelation替代`); // 对后台而言,将生成的relationFilter加到filter之上(select可以在此加以权限的过滤) - operation.filter = combineFilters([operation.filter, await relationFilter(operation, context, option)]); + if (operation.action === 'create') { + const filter2 = await relationFilter(operation, context, option); + + const { data } = operation as ED[keyof ED]['Create']; + const filter = data instanceof Array ? { + id: { + $in: data.map( + ele => ele.id, + ), + }, + } : { + id: data.id, + }; + if (await checkFilterContains(entity, context, filter2, filter, true)) { + return 0; + } + throw new OakUserUnpermittedException(errMsg); + } + else { + operation.filter = combineFilters([operation.filter, await relationFilter(operation, context, option)]); + } return 0; }) as UpdateTriggerInTxn['fn']; return { @@ -177,16 +199,25 @@ export function translateCheckerInSyncContext< }; } case 'relation': { - const { relationFilter: filter, errMsg } = checker; + const { relationFilter, errMsg } = checker; const fn = (operation: ED[T]['Operation'], context: Cxt, option: OperateOption | SelectOption) => { if (context.isRoot()) { return; } - const filter2 = typeof filter === 'function' ? filter(operation, context, option) : filter; - const { filter: operationFilter } = operation; - assert(operationFilter); + const filter2 = typeof relationFilter === 'function' ? relationFilter(operation, context, option) : relationFilter; + const { filter, action } = operation; + let filter3 = filter; + if (action === 'create') { + const { data } = operation as ED[T]['Create']; + filter3 = data instanceof Array ? { + id: { + $in: data.map(ele => ele.id), + }, + } : { id: data.id }; + } + assert(filter3); assert(!(filter2 instanceof Promise)); - if (checkFilterContains(entity, context, filter2, operationFilter, true)) { + if (checkFilterContains(entity, context, filter2, filter3, true)) { return; } throw new OakUserUnpermittedException(errMsg); @@ -267,7 +298,7 @@ function translateCascadeRelationFilterMaker 0 ? translateFilterMakerIter(entity2, 0) : translateRelationFilter(entity2); + const filter = cascadePath ? translateFilterMakerIter(entity2, 0) : translateRelationFilter(entity2); return filter; } @@ -362,7 +393,7 @@ export function createAuthCheckers { + relationFilter: (operation, context) => { const { data } = operation as ED[keyof ED]['Create']; assert(!(data instanceof Array)); const { relation, [entityIdAttr]: entityId } = data; @@ -371,7 +402,9 @@ export function createAuthCheckers { // const { filter } = operation; const filter = filterMaker(context.getCurrentUserId()!); From 8c7b53f91655fca81d5fc4627f780b1d87d568a0 Mon Sep 17 00:00:00 2001 From: "Xc@centOs" Date: Thu, 19 Jan 2023 14:56:45 +0800 Subject: [PATCH 15/19] =?UTF-8?q?=E9=87=8D=E6=9E=84=E4=BA=86Entity.ts?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=AE=9A=E4=B9=89,=E7=AE=80=E5=8C=96?= =?UTF-8?q?=E4=BA=86=E8=AE=B8=E5=A4=9A=E4=B8=8D=E5=BF=85=E8=A6=81=E7=9A=84?= =?UTF-8?q?=E6=B3=9B=E5=9E=8B=E5=A3=B0=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/actions/action.d.ts | 16 +-- lib/actions/relation.d.ts | 2 +- lib/base-app-domain/EntityDict.d.ts | 2 +- lib/base-app-domain/Modi/Action.d.ts | 8 +- lib/base-app-domain/Modi/Schema.d.ts | 48 +++---- lib/base-app-domain/ModiEntity/Schema.d.ts | 56 ++++---- lib/base-app-domain/Oper/Schema.d.ts | 52 +++---- lib/base-app-domain/OperEntity/Schema.d.ts | 60 ++++----- lib/base-app-domain/User/Schema.d.ts | 48 +++---- lib/base-app-domain/_SubQuery.d.ts | 10 +- lib/compiler/schemalBuilder.js | 5 +- lib/store/CascadeStore.d.ts | 8 +- lib/store/TriggerExecutor.d.ts | 2 +- lib/store/relation.d.ts | 2 +- lib/types/Action.d.ts | 10 +- lib/types/Auth.d.ts | 18 +-- lib/types/DataType.d.ts | 28 ++-- lib/types/Demand.d.ts | 46 +++---- lib/types/Entity.d.ts | 149 ++++++++++----------- lib/types/Entity.js | 1 - lib/types/Expression.d.ts | 28 ++-- lib/types/Geo.d.ts | 12 +- lib/types/Locale.d.ts | 10 +- lib/types/Polyfill.d.ts | 16 +-- lib/types/Port.d.ts | 4 +- lib/types/RowStore.d.ts | 2 +- lib/types/Storage.d.ts | 8 +- lib/types/Timer.d.ts | 6 +- lib/types/Trigger.d.ts | 10 +- lib/types/Watcher.d.ts | 4 +- lib/types/schema/DataTypes.d.ts | 14 +- lib/utils/concurrent.d.ts | 2 +- lib/utils/uuid.d.ts | 2 +- lib/utils/validator.d.ts | 4 +- package.json | 2 +- src/compiler/schemalBuilder.ts | 25 ---- src/store/CascadeStore.ts | 12 +- src/store/TriggerExecutor.ts | 20 +-- src/store/checker.ts | 6 +- src/store/filter.ts | 4 +- src/store/selection.ts | 4 +- src/types/Entity.ts | 119 +++++++--------- 42 files changed, 417 insertions(+), 468 deletions(-) diff --git a/lib/actions/action.d.ts b/lib/actions/action.d.ts index 05fe2f5..a2f31d3 100644 --- a/lib/actions/action.d.ts +++ b/lib/actions/action.d.ts @@ -1,16 +1,16 @@ import { ActionDef } from '../types/Action'; -export declare type ReadOnlyAction = 'select' | 'count' | 'stat' | 'download'; -export declare type AppendOnlyAction = ReadOnlyAction | 'create'; -export declare type ExcludeUpdateAction = AppendOnlyAction | 'remove'; -export declare type ExcludeRemoveAction = AppendOnlyAction | 'update'; -export declare type GenericAction = 'update' | ExcludeUpdateAction; -export declare type RelationAction = 'grant' | 'revoke'; +export type ReadOnlyAction = 'select' | 'count' | 'stat' | 'download'; +export type AppendOnlyAction = ReadOnlyAction | 'create'; +export type ExcludeUpdateAction = AppendOnlyAction | 'remove'; +export type ExcludeRemoveAction = AppendOnlyAction | 'update'; +export type GenericAction = 'update' | ExcludeUpdateAction; +export type RelationAction = 'grant' | 'revoke'; export declare const readOnlyActions: string[]; export declare const appendOnlyActions: string[]; export declare const excludeUpdateActions: string[]; export declare const exludeRemoveActions: string[]; export declare const genericActions: string[]; export declare const relationActions: string[]; -export declare type AbleAction = 'enable' | 'disable'; -export declare type AbleState = 'enabled' | 'disabled'; +export type AbleAction = 'enable' | 'disable'; +export type AbleState = 'enabled' | 'disabled'; export declare const makeAbleActionDef: (initialState?: AbleState) => ActionDef; diff --git a/lib/actions/relation.d.ts b/lib/actions/relation.d.ts index d012b77..2f74e02 100644 --- a/lib/actions/relation.d.ts +++ b/lib/actions/relation.d.ts @@ -1,5 +1,5 @@ import { CascadeRelationItem, RelationHierarchy } from "../types/Entity"; -export declare type GenericRelation = 'owner'; +export type GenericRelation = 'owner'; export declare function convertHierarchyToAuth(hierarchy: RelationHierarchy): { [K in R]?: CascadeRelationItem; }; diff --git a/lib/base-app-domain/EntityDict.d.ts b/lib/base-app-domain/EntityDict.d.ts index cb81cf2..b54b36e 100644 --- a/lib/base-app-domain/EntityDict.d.ts +++ b/lib/base-app-domain/EntityDict.d.ts @@ -3,7 +3,7 @@ import { EntityDef as ModiEntity } from "./ModiEntity/Schema"; import { EntityDef as Oper } from "./Oper/Schema"; import { EntityDef as OperEntity } from "./OperEntity/Schema"; import { EntityDef as User } from "./User/Schema"; -export declare type EntityDict = { +export type EntityDict = { modi: Modi; modiEntity: ModiEntity; oper: Oper; diff --git a/lib/base-app-domain/Modi/Action.d.ts b/lib/base-app-domain/Modi/Action.d.ts index e22999c..a114e7c 100644 --- a/lib/base-app-domain/Modi/Action.d.ts +++ b/lib/base-app-domain/Modi/Action.d.ts @@ -1,9 +1,9 @@ import { ActionDef } from "../../types/Action"; import { GenericAction } from "../../actions/action"; -export declare type IState = 'active' | 'applied' | 'abandoned'; -export declare type IAction = 'apply' | 'abandon'; -export declare type ParticularAction = IAction; -export declare type Action = GenericAction | ParticularAction; +export type IState = 'active' | 'applied' | 'abandoned'; +export type IAction = 'apply' | 'abandon'; +export type ParticularAction = IAction; +export type Action = GenericAction | ParticularAction; export declare const actions: string[]; export declare const ActionDefDict: { iState: ActionDef; diff --git a/lib/base-app-domain/Modi/Schema.d.ts b/lib/base-app-domain/Modi/Schema.d.ts index eafd1be..5874a91 100644 --- a/lib/base-app-domain/Modi/Schema.d.ts +++ b/lib/base-app-domain/Modi/Schema.d.ts @@ -6,7 +6,7 @@ import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOper import { Action, ParticularAction, IState } from "./Action"; import * as ModiEntity from "../ModiEntity/Schema"; import * as OperEntity from "../OperEntity/Schema"; -export declare type OpSchema = EntityShape & { +export type OpSchema = EntityShape & { targetEntity: String<32>; entity: String<32>; entityId: String<64>; @@ -16,8 +16,8 @@ export declare type OpSchema = EntityShape & { extra?: Object | null; iState?: IState | null; }; -export declare type OpAttr = keyof OpSchema; -export declare type Schema = EntityShape & { +export type OpAttr = keyof OpSchema; +export type Schema = EntityShape & { targetEntity: String<32>; entity: String<32>; entityId: String<64>; @@ -33,7 +33,7 @@ export declare type Schema = EntityShape & { } & { [A in ExpressionKey]?: any; }; -declare type AttrFilter = { +type AttrFilter = { id: Q_StringValue | SubQuery.ModiIdSubQuery; $$createAt$$: Q_DateValue; $$seq$$: Q_StringValue; @@ -47,8 +47,8 @@ declare type AttrFilter = { extra: Object; iState: Q_EnumValue; }; -export declare type Filter = MakeFilter>; -export declare type Projection = { +export type Filter = MakeFilter>; +export type Projection = { "#id"?: NodeId; [k: string]: any; id?: number; @@ -76,10 +76,10 @@ export declare type Projection = { $entity: "operEntity"; }; } & Partial>; -declare type ModiIdProjection = OneOf<{ +type ModiIdProjection = OneOf<{ id: number; }>; -export declare type SortAttr = { +export type SortAttr = { id: number; } | { $$createAt$$: number; @@ -100,15 +100,15 @@ export declare type SortAttr = { } | { [k: string]: any; } | OneOf>; -export declare type SortNode = { +export type SortNode = { $attr: SortAttr; $direction?: "asc" | "desc"; }; -export declare type Sorter = SortNode[]; -export declare type SelectOperation

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

= Omit, "action">; -export declare type Aggregation = Omit, "id">; -export declare type CreateOperationData = FormCreateData> & ({ +export type Sorter = SortNode[]; +export type SelectOperation

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

= Omit, "action">; +export type Aggregation = Omit, "id">; +export type CreateOperationData = FormCreateData> & ({ entity?: string; entityId?: string; [K: string]: any; @@ -116,20 +116,20 @@ export declare type CreateOperationData = FormCreateData[]> | Array>>; operEntity$entity?: OakOperation<"create", Omit[]> | Array>>; }; -export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>; -export declare type CreateMultipleOperation = OakOperation<"create", Array>; -export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation; -export declare type UpdateOperationData = FormUpdateData & { +export type CreateSingleOperation = OakOperation<"create", CreateOperationData>; +export type CreateMultipleOperation = OakOperation<"create", Array>; +export type CreateOperation = CreateSingleOperation | CreateMultipleOperation; +export type UpdateOperationData = FormUpdateData & { [k: string]: any; modiEntitys$modi?: OakOperation<"create", Omit[]> | Array>>; operEntitys$entity?: OakOperation<"create", Omit[]> | Array>>; }; -export declare type UpdateOperation = OakOperation<"update" | ParticularAction | string, UpdateOperationData, Filter, Sorter>; -export declare type RemoveOperationData = {}; -export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; -export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation | SelectOperation; -export declare type ModiIdSubQuery = Selection; -export declare type EntityDef = { +export type UpdateOperation = OakOperation<"update" | ParticularAction | string, UpdateOperationData, Filter, Sorter>; +export type RemoveOperationData = {}; +export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; +export type Operation = CreateOperation | UpdateOperation | RemoveOperation; +export type ModiIdSubQuery = Selection; +export type EntityDef = { Schema: Schema; OpSchema: OpSchema; Action: OakMakeAction | string; diff --git a/lib/base-app-domain/ModiEntity/Schema.d.ts b/lib/base-app-domain/ModiEntity/Schema.d.ts index b664da1..98ea464 100644 --- a/lib/base-app-domain/ModiEntity/Schema.d.ts +++ b/lib/base-app-domain/ModiEntity/Schema.d.ts @@ -6,13 +6,13 @@ import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOper import { AppendOnlyAction } from "../../actions/action"; import * as Modi from "../Modi/Schema"; import * as User from "../User/Schema"; -export declare type OpSchema = EntityShape & { +export type OpSchema = EntityShape & { modiId: ForeignKey<"modi">; entity: "user" | string; entityId: String<64>; }; -export declare type OpAttr = keyof OpSchema; -export declare type Schema = EntityShape & { +export type OpAttr = keyof OpSchema; +export type Schema = EntityShape & { modiId: ForeignKey<"modi">; entity: "user" | string; entityId: String<64>; @@ -21,7 +21,7 @@ export declare type Schema = EntityShape & { } & { [A in ExpressionKey]?: any; }; -declare type AttrFilter = { +type AttrFilter = { id: Q_StringValue | SubQuery.ModiEntityIdSubQuery; $$createAt$$: Q_DateValue; $$seq$$: Q_StringValue; @@ -32,8 +32,8 @@ declare type AttrFilter = { entityId: Q_StringValue; user: User.Filter; }; -export declare type Filter> = MakeFilter & ExprOp>; -export declare type Projection = { +export type Filter> = MakeFilter & ExprOp>; +export type Projection = { "#id"?: NodeId; [k: string]: any; id?: number; @@ -46,16 +46,16 @@ export declare type Projection = { entityId?: number; user?: User.Projection; } & Partial>; -declare type ModiEntityIdProjection = OneOf<{ +type ModiEntityIdProjection = OneOf<{ id: number; }>; -declare type ModiIdProjection = OneOf<{ +type ModiIdProjection = OneOf<{ modiId: number; }>; -declare type UserIdProjection = OneOf<{ +type UserIdProjection = OneOf<{ entityId: number; }>; -export declare type SortAttr = { +export type SortAttr = { id: number; } | { $$createAt$$: number; @@ -76,15 +76,15 @@ export declare type SortAttr = { } | { [k: string]: any; } | OneOf>; -export declare type SortNode = { +export type SortNode = { $attr: SortAttr; $direction?: "asc" | "desc"; }; -export declare type Sorter = SortNode[]; -export declare type SelectOperation

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

= Omit, "action">; -export declare type Aggregation = Omit, "id">; -export declare type CreateOperationData = FormCreateData> & (({ +export type Sorter = SortNode[]; +export type SelectOperation

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

= Omit, "action">; +export type Aggregation = Omit, "id">; +export type CreateOperationData = FormCreateData> & (({ modiId?: never; modi: Modi.CreateSingleOperation; } | { @@ -108,10 +108,10 @@ export declare type CreateOperationData = FormCreateData; -export declare type CreateMultipleOperation = OakOperation<"create", Array>; -export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation; -export declare type UpdateOperationData = FormUpdateData> & (({ +export type CreateSingleOperation = OakOperation<"create", CreateOperationData>; +export type CreateMultipleOperation = OakOperation<"create", Array>; +export type CreateOperation = CreateSingleOperation | CreateMultipleOperation; +export type UpdateOperationData = FormUpdateData> & (({ modi: Modi.CreateSingleOperation; modiId?: never; } | { @@ -133,20 +133,20 @@ export declare type UpdateOperationData = FormUpdateData; -export declare type RemoveOperationData = {} & (({ +export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>; +export type RemoveOperationData = {} & (({ modi?: Modi.UpdateOperation | Modi.RemoveOperation; })) & ({ user?: User.UpdateOperation | User.RemoveOperation; } | { [k: string]: any; }); -export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; -export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation | SelectOperation; -export declare type ModiIdSubQuery = Selection; -export declare type UserIdSubQuery = Selection; -export declare type ModiEntityIdSubQuery = Selection; -export declare type EntityDef = { +export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; +export type Operation = CreateOperation | UpdateOperation | RemoveOperation; +export type ModiIdSubQuery = Selection; +export type UserIdSubQuery = Selection; +export type ModiEntityIdSubQuery = Selection; +export type EntityDef = { Schema: Schema; OpSchema: OpSchema; Action: OakMakeAction | string; diff --git a/lib/base-app-domain/Oper/Schema.d.ts b/lib/base-app-domain/Oper/Schema.d.ts index 1aefe36..10e71b1 100644 --- a/lib/base-app-domain/Oper/Schema.d.ts +++ b/lib/base-app-domain/Oper/Schema.d.ts @@ -6,15 +6,15 @@ import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOper import { AppendOnlyAction } from "../../actions/action"; import * as User from "../User/Schema"; import * as OperEntity from "../OperEntity/Schema"; -export declare type OpSchema = EntityShape & { +export type OpSchema = EntityShape & { action: String<16>; data: Object; filter?: Object | null; extra?: Object | null; operatorId?: ForeignKey<"user"> | null; }; -export declare type OpAttr = keyof OpSchema; -export declare type Schema = EntityShape & { +export type OpAttr = keyof OpSchema; +export type Schema = EntityShape & { action: String<16>; data: Object; filter?: Object | null; @@ -26,7 +26,7 @@ export declare type Schema = EntityShape & { } & { [A in ExpressionKey]?: any; }; -declare type AttrFilter = { +type AttrFilter = { id: Q_StringValue | SubQuery.OperIdSubQuery; $$createAt$$: Q_DateValue; $$seq$$: Q_StringValue; @@ -38,8 +38,8 @@ declare type AttrFilter = { operatorId: Q_StringValue | SubQuery.UserIdSubQuery; operator: User.Filter; }; -export declare type Filter = MakeFilter>; -export declare type Projection = { +export type Filter = MakeFilter>; +export type Projection = { "#id"?: NodeId; [k: string]: any; id?: number; @@ -59,13 +59,13 @@ export declare type Projection = { $entity: "operEntity"; }; } & Partial>; -declare type OperIdProjection = OneOf<{ +type OperIdProjection = OneOf<{ id: number; }>; -declare type UserIdProjection = OneOf<{ +type UserIdProjection = OneOf<{ operatorId: number; }>; -export declare type SortAttr = { +export type SortAttr = { id: number; } | { $$createAt$$: number; @@ -82,15 +82,15 @@ export declare type SortAttr = { } | { [k: string]: any; } | OneOf>; -export declare type SortNode = { +export type SortNode = { $attr: SortAttr; $direction?: "asc" | "desc"; }; -export declare type Sorter = SortNode[]; -export declare type SelectOperation

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

= Omit, "action">; -export declare type Aggregation = Omit, "id">; -export declare type CreateOperationData = FormCreateData> & (({ +export type Sorter = SortNode[]; +export type SelectOperation

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

= Omit, "action">; +export type Aggregation = Omit, "id">; +export type CreateOperationData = FormCreateData> & (({ operatorId?: never; operator?: User.CreateSingleOperation; } | { @@ -101,10 +101,10 @@ export declare type CreateOperationData = FormCreateData[]> | Array>>; }; -export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>; -export declare type CreateMultipleOperation = OakOperation<"create", Array>; -export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation; -export declare type UpdateOperationData = FormUpdateData> & (({ +export type CreateSingleOperation = OakOperation<"create", CreateOperationData>; +export type CreateMultipleOperation = OakOperation<"create", Array>; +export type CreateOperation = CreateSingleOperation | CreateMultipleOperation; +export type UpdateOperationData = FormUpdateData> & (({ operator: User.CreateSingleOperation; operatorId?: never; } | { @@ -120,15 +120,15 @@ export declare type UpdateOperationData = FormUpdateData[]> | Array>>; }; -export declare type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>; -export declare type RemoveOperationData = {} & (({ +export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>; +export type RemoveOperationData = {} & (({ operator?: User.UpdateOperation | User.RemoveOperation; })); -export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; -export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation | SelectOperation; -export declare type UserIdSubQuery = Selection; -export declare type OperIdSubQuery = Selection; -export declare type EntityDef = { +export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; +export type Operation = CreateOperation | UpdateOperation | RemoveOperation; +export type UserIdSubQuery = Selection; +export type OperIdSubQuery = Selection; +export type EntityDef = { Schema: Schema; OpSchema: OpSchema; Action: OakMakeAction | string; diff --git a/lib/base-app-domain/OperEntity/Schema.d.ts b/lib/base-app-domain/OperEntity/Schema.d.ts index 413ecf2..a500b12 100644 --- a/lib/base-app-domain/OperEntity/Schema.d.ts +++ b/lib/base-app-domain/OperEntity/Schema.d.ts @@ -7,13 +7,13 @@ import { AppendOnlyAction } from "../../actions/action"; import * as Oper from "../Oper/Schema"; import * as Modi from "../Modi/Schema"; import * as User from "../User/Schema"; -export declare type OpSchema = EntityShape & { +export type OpSchema = EntityShape & { operId: ForeignKey<"oper">; entity: "modi" | "user" | string; entityId: String<64>; }; -export declare type OpAttr = keyof OpSchema; -export declare type Schema = EntityShape & { +export type OpAttr = keyof OpSchema; +export type Schema = EntityShape & { operId: ForeignKey<"oper">; entity: "modi" | "user" | string; entityId: String<64>; @@ -23,7 +23,7 @@ export declare type Schema = EntityShape & { } & { [A in ExpressionKey]?: any; }; -declare type AttrFilter = { +type AttrFilter = { id: Q_StringValue | SubQuery.OperEntityIdSubQuery; $$createAt$$: Q_DateValue; $$seq$$: Q_StringValue; @@ -35,8 +35,8 @@ declare type AttrFilter = { modi: Modi.Filter; user: User.Filter; }; -export declare type Filter> = MakeFilter & ExprOp>; -export declare type Projection = { +export type Filter> = MakeFilter & ExprOp>; +export type Projection = { "#id"?: NodeId; [k: string]: any; id?: number; @@ -50,19 +50,19 @@ export declare type Projection = { modi?: Modi.Projection; user?: User.Projection; } & Partial>; -declare type OperEntityIdProjection = OneOf<{ +type OperEntityIdProjection = OneOf<{ id: number; }>; -declare type OperIdProjection = OneOf<{ +type OperIdProjection = OneOf<{ operId: number; }>; -declare type ModiIdProjection = OneOf<{ +type ModiIdProjection = OneOf<{ entityId: number; }>; -declare type UserIdProjection = OneOf<{ +type UserIdProjection = OneOf<{ entityId: number; }>; -export declare type SortAttr = { +export type SortAttr = { id: number; } | { $$createAt$$: number; @@ -85,15 +85,15 @@ export declare type SortAttr = { } | { [k: string]: any; } | OneOf>; -export declare type SortNode = { +export type SortNode = { $attr: SortAttr; $direction?: "asc" | "desc"; }; -export declare type Sorter = SortNode[]; -export declare type SelectOperation

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

= Omit, "action">; -export declare type Aggregation = Omit, "id">; -export declare type CreateOperationData = FormCreateData> & (({ +export type Sorter = SortNode[]; +export type SelectOperation

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

= Omit, "action">; +export type Aggregation = Omit, "id">; +export type CreateOperationData = FormCreateData> & (({ operId?: never; oper: Oper.CreateSingleOperation; } | { @@ -125,10 +125,10 @@ export declare type CreateOperationData = FormCreateData; -export declare type CreateMultipleOperation = OakOperation<"create", Array>; -export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation; -export declare type UpdateOperationData = FormUpdateData> & (({ +export type CreateSingleOperation = OakOperation<"create", CreateOperationData>; +export type CreateMultipleOperation = OakOperation<"create", Array>; +export type CreateOperation = CreateSingleOperation | CreateMultipleOperation; +export type UpdateOperationData = FormUpdateData> & (({ oper: Oper.CreateSingleOperation; operId?: never; } | { @@ -148,21 +148,21 @@ export declare type UpdateOperationData = FormUpdateData; -export declare type RemoveOperationData = {} & ({ +export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>; +export type RemoveOperationData = {} & ({ modi?: Modi.UpdateOperation | Modi.RemoveOperation; } | { user?: User.UpdateOperation | User.RemoveOperation; } | { [k: string]: any; }); -export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; -export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation | SelectOperation; -export declare type OperIdSubQuery = Selection; -export declare type ModiIdSubQuery = Selection; -export declare type UserIdSubQuery = Selection; -export declare type OperEntityIdSubQuery = Selection; -export declare type EntityDef = { +export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; +export type Operation = CreateOperation | UpdateOperation | RemoveOperation; +export type OperIdSubQuery = Selection; +export type ModiIdSubQuery = Selection; +export type UserIdSubQuery = Selection; +export type OperEntityIdSubQuery = Selection; +export type EntityDef = { Schema: Schema; OpSchema: OpSchema; Action: OakMakeAction | string; diff --git a/lib/base-app-domain/User/Schema.d.ts b/lib/base-app-domain/User/Schema.d.ts index 07b8ee2..3bc5d51 100644 --- a/lib/base-app-domain/User/Schema.d.ts +++ b/lib/base-app-domain/User/Schema.d.ts @@ -7,13 +7,13 @@ import { GenericAction, RelationAction } from "../../actions/action"; import * as Oper from "../Oper/Schema"; import * as OperEntity from "../OperEntity/Schema"; import * as ModiEntity from "../ModiEntity/Schema"; -export declare type OpSchema = EntityShape & { +export type OpSchema = EntityShape & { name?: String<16> | null; nickname?: String<64> | null; password?: Text | null; }; -export declare type OpAttr = keyof OpSchema; -export declare type Schema = EntityShape & { +export type OpAttr = keyof OpSchema; +export type Schema = EntityShape & { name?: String<16> | null; nickname?: String<64> | null; password?: Text | null; @@ -26,7 +26,7 @@ export declare type Schema = EntityShape & { } & { [A in ExpressionKey]?: any; }; -declare type AttrFilter = { +type AttrFilter = { id: Q_StringValue | SubQuery.UserIdSubQuery; $$createAt$$: Q_DateValue; $$seq$$: Q_StringValue; @@ -35,8 +35,8 @@ declare type AttrFilter = { nickname: Q_StringValue; password: Q_StringValue; }; -export declare type Filter = MakeFilter>; -export declare type Projection = { +export type Filter = MakeFilter>; +export type Projection = { "#id"?: NodeId; [k: string]: any; id?: number; @@ -65,10 +65,10 @@ export declare type Projection = { $entity: "modiEntity"; }; } & Partial>; -declare type UserIdProjection = OneOf<{ +type UserIdProjection = OneOf<{ id: number; }>; -export declare type SortAttr = { +export type SortAttr = { id: number; } | { $$createAt$$: number; @@ -85,34 +85,34 @@ export declare type SortAttr = { } | { [k: string]: any; } | OneOf>; -export declare type SortNode = { +export type SortNode = { $attr: SortAttr; $direction?: "asc" | "desc"; }; -export declare type Sorter = SortNode[]; -export declare type SelectOperation

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

= Omit, "action">; -export declare type Aggregation = Omit, "id">; -export declare type CreateOperationData = FormCreateData & { +export type Sorter = SortNode[]; +export type SelectOperation

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

= Omit, "action">; +export type Aggregation = Omit, "id">; +export type CreateOperationData = FormCreateData & { oper$operator?: OakOperation<"create", Omit[]> | Array>>; operEntity$entity?: OakOperation<"create", Omit[]> | Array>>; modiEntity$entity?: OakOperation<"create", Omit[]> | Array>>; }; -export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>; -export declare type CreateMultipleOperation = OakOperation<"create", Array>; -export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation; -export declare type UpdateOperationData = FormUpdateData & { +export type CreateSingleOperation = OakOperation<"create", CreateOperationData>; +export type CreateMultipleOperation = OakOperation<"create", Array>; +export type CreateOperation = CreateSingleOperation | CreateMultipleOperation; +export type UpdateOperationData = FormUpdateData & { [k: string]: any; opers$operator?: OakOperation<"create", Omit[]> | Array>>; operEntitys$entity?: OakOperation<"create", Omit[]> | Array>>; modiEntitys$entity?: OakOperation<"create", Omit[]> | Array>>; }; -export declare type UpdateOperation = OakOperation<"update" | RelationAction | string, UpdateOperationData, Filter, Sorter>; -export declare type RemoveOperationData = {}; -export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; -export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation | SelectOperation; -export declare type UserIdSubQuery = Selection; -export declare type EntityDef = { +export type UpdateOperation = OakOperation<"update" | RelationAction | string, UpdateOperationData, Filter, Sorter>; +export type RemoveOperationData = {}; +export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; +export type Operation = CreateOperation | UpdateOperation | RemoveOperation; +export type UserIdSubQuery = Selection; +export type EntityDef = { Schema: Schema; OpSchema: OpSchema; Action: OakMakeAction | string; diff --git a/lib/base-app-domain/_SubQuery.d.ts b/lib/base-app-domain/_SubQuery.d.ts index 4b68ed6..44e0c13 100644 --- a/lib/base-app-domain/_SubQuery.d.ts +++ b/lib/base-app-domain/_SubQuery.d.ts @@ -3,31 +3,31 @@ import * as ModiEntity from "./ModiEntity/Schema"; import * as Oper from "./Oper/Schema"; import * as OperEntity from "./OperEntity/Schema"; import * as User from "./User/Schema"; -export declare type ModiIdSubQuery = { +export type ModiIdSubQuery = { [K in "$in" | "$nin"]?: (ModiEntity.ModiIdSubQuery & { entity: "modiEntity"; }) | (Modi.ModiIdSubQuery & { entity: "modi"; }) | any; }; -export declare type ModiEntityIdSubQuery = { +export type ModiEntityIdSubQuery = { [K in "$in" | "$nin"]?: (ModiEntity.ModiEntityIdSubQuery & { entity: "modiEntity"; }) | any; }; -export declare type OperIdSubQuery = { +export type OperIdSubQuery = { [K in "$in" | "$nin"]?: (OperEntity.OperIdSubQuery & { entity: "operEntity"; }) | (Oper.OperIdSubQuery & { entity: "oper"; }) | any; }; -export declare type OperEntityIdSubQuery = { +export type OperEntityIdSubQuery = { [K in "$in" | "$nin"]?: (OperEntity.OperEntityIdSubQuery & { entity: "operEntity"; }) | any; }; -export declare type UserIdSubQuery = { +export type UserIdSubQuery = { [K in "$in" | "$nin"]?: (Oper.UserIdSubQuery & { entity: "oper"; }) | (User.UserIdSubQuery & { diff --git a/lib/compiler/schemalBuilder.js b/lib/compiler/schemalBuilder.js index 4f10215..2a3d8b2 100644 --- a/lib/compiler/schemalBuilder.js +++ b/lib/compiler/schemalBuilder.js @@ -1801,7 +1801,6 @@ function constructActions(statements, entity) { factory.createLiteralTypeNode(factory.createStringLiteral("action")) ])), factory.createTypeAliasDeclaration(undefined, [factory.createToken(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("Aggregation"), undefined, factory.createTypeReferenceNode(factory.createIdentifier("Omit"), [ factory.createTypeReferenceNode(factory.createIdentifier("DeduceAggregation"), [ - factory.createTypeReferenceNode(factory.createIdentifier("Schema"), undefined), factory.createTypeReferenceNode(factory.createIdentifier("Projection"), undefined), factory.createTypeReferenceNode(factory.createIdentifier("Filter"), undefined), factory.createTypeReferenceNode(factory.createIdentifier("Sorter"), undefined) @@ -2605,8 +2604,7 @@ function constructActions(statements, entity) { statements.push(factory.createTypeAliasDeclaration(undefined, [factory.createModifier(ts.SyntaxKind.ExportKeyword)], factory.createIdentifier("Operation"), undefined, factory.createUnionTypeNode([ factory.createTypeReferenceNode(factory.createIdentifier("CreateOperation"), undefined), factory.createTypeReferenceNode(factory.createIdentifier("UpdateOperation"), undefined), - factory.createTypeReferenceNode(factory.createIdentifier("RemoveOperation"), undefined), - factory.createTypeReferenceNode(factory.createIdentifier("SelectOperation"), undefined) + factory.createTypeReferenceNode(factory.createIdentifier("RemoveOperation"), undefined) ]))); } var initialStatements = function () { return [ @@ -2663,7 +2661,6 @@ var initialStatements = function () { return [ function outputSubQuery(outputDir, printer) { var statements = []; if (process.env.COMPLING_AS_LIB) { - statements.push(factory.createImportDeclaration(undefined, undefined, factory.createImportClause(false, undefined, factory.createNamedImports([factory.createImportSpecifier(false, undefined, factory.createIdentifier("Selection"))])), factory.createStringLiteral((0, env_1.TYPE_PATH_IN_OAK_DOMAIN)(1)), undefined)); } for (var entity in Schema) { // import * as User from '../User/Schema'; diff --git a/lib/store/CascadeStore.d.ts b/lib/store/CascadeStore.d.ts index 844d93b..c8346eb 100644 --- a/lib/store/CascadeStore.d.ts +++ b/lib/store/CascadeStore.d.ts @@ -1,4 +1,4 @@ -import { EntityDict, OperateOption, SelectOption, OperationResult, DeduceFilter, AggregationResult } from "../types/Entity"; +import { EntityDict, OperateOption, SelectOption, OperationResult, AggregationResult } from "../types/Entity"; import { EntityDict as BaseEntityDict } from '../base-app-domain'; import { RowStore } from '../types/RowStore'; import { StorageSchema } from '../types/Storage'; @@ -51,14 +51,14 @@ export declare abstract class CascadeStore | AsyncContext, OP extends OperateOption, R>(entity: T, action: ED[T]['Action'], data: ED[T]['CreateSingle']['data'] | ED[T]['Update']['data'] | ED[T]['Remove']['data'], context: Cxt, option: OP, cascadeUpdate: (entity: T2, operation: ED[T2]['Operation'], context: Cxt, option: OP) => R, filter?: DeduceFilter): { + protected destructCascadeUpdate | AsyncContext, OP extends OperateOption, R>(entity: T, action: ED[T]['Action'], data: ED[T]['CreateSingle']['data'] | ED[T]['Update']['data'] | ED[T]['Remove']['data'], context: Cxt, option: OP, cascadeUpdate: (entity: T2, operation: ED[T2]['Operation'], context: Cxt, option: OP) => R, filter?: ED[T]['Update']['filter']): { data: Record; beforeFns: (() => R)[]; afterFns: (() => R)[]; }; protected preProcessDataCreated(entity: T, data: ED[T]['Create']['data']): void; - protected preProcessDataUpdated(data: ED[T]['Update']['data']): void; - judgeRelation(entity: keyof ED, attr: string): string | 2 | 1 | string[] | 0; + protected preProcessDataUpdated(data: Record): void; + judgeRelation(entity: keyof ED, attr: string): string | 1 | 2 | string[] | 0; /** * 和具体的update过程无关的例程放在这里,包括对later动作的处理、对oper的记录以及对record的收集等 * @param entity diff --git a/lib/store/TriggerExecutor.d.ts b/lib/store/TriggerExecutor.d.ts index d63a7ed..77253f7 100644 --- a/lib/store/TriggerExecutor.d.ts +++ b/lib/store/TriggerExecutor.d.ts @@ -16,7 +16,7 @@ export declare class TriggerExecutor { private contextBuilder; constructor(contextBuilder: (cxtString: string) => Promise>, logger?: Logger); registerChecker>(checker: Checker): void; - getCheckers(entity: T, action: ED[T]['Action'], checkerTypes?: CheckerType[]): Trigger>[] | undefined; + getCheckers(entity: T, action: ED[T]['Action'], checkerTypes?: CheckerType[]): Trigger>[]; registerTrigger>(trigger: Trigger): void; unregisterTrigger>(trigger: Trigger): void; private preCommitTrigger; diff --git a/lib/store/relation.d.ts b/lib/store/relation.d.ts index 9def51f..4c9e882 100644 --- a/lib/store/relation.d.ts +++ b/lib/store/relation.d.ts @@ -10,4 +10,4 @@ import { StorageSchema } from "../types/Storage"; */ export declare function judgeRelation(schema: StorageSchema, entity: keyof ED, attr: string): string | 2 | 1 | string[] | 0; +}>(schema: StorageSchema, entity: keyof ED, attr: string): string | 1 | 2 | string[] | 0; diff --git a/lib/types/Action.d.ts b/lib/types/Action.d.ts index 242e274..6bba1b7 100644 --- a/lib/types/Action.d.ts +++ b/lib/types/Action.d.ts @@ -1,18 +1,18 @@ import { CascadeRelationItem, EntityDict } from "./Entity"; import { GenericAction } from '../actions/action'; -export declare type Action = string; -export declare type State = string; -export declare type ActionDef = { +export type Action = string; +export type State = string; +export type ActionDef = { stm: { [a in A]: [p: S | S[], n: S]; }; is?: S; }; -export declare type ActionDictOfEntityDict = { +export type ActionDictOfEntityDict = { [T in keyof E]?: { [A in keyof E[T]['OpSchema']]?: ActionDef; }; }; -export declare type CascadeActionAuth = { +export type CascadeActionAuth = { [K in A | GenericAction]?: CascadeRelationItem | (CascadeRelationItem | CascadeRelationItem[])[]; }; diff --git a/lib/types/Auth.d.ts b/lib/types/Auth.d.ts index cee2d7b..862f12c 100644 --- a/lib/types/Auth.d.ts +++ b/lib/types/Auth.d.ts @@ -2,12 +2,12 @@ import { CascadeActionAuth, CascadeRelationAuth } from "."; import { AsyncContext } from "../store/AsyncRowStore"; import { SyncContext } from "../store/SyncRowStore"; import { EntityDict, OperateOption, SelectOption } from "../types/Entity"; -export declare type CheckerType = 'relation' | 'row' | 'data' | 'logical' | 'logicalRelation'; +export type CheckerType = 'relation' | 'row' | 'data' | 'logical' | 'logicalRelation'; /** * conditionalFilter是指该action发生时,operation所操作的行中有满足conditionalFilter的行 * 被转化成trigger的filter条件,详细可看trigger中的说明 */ -export declare type DataChecker | SyncContext> = { +export type DataChecker | SyncContext> = { priority?: number; type: 'data'; entity: T; @@ -15,7 +15,7 @@ export declare type DataChecker void | Promise; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter'] | Promise); }; -export declare type RowChecker | SyncContext> = { +export type RowChecker | SyncContext> = { priority?: number; type: 'row'; entity: T; @@ -28,7 +28,7 @@ export declare type RowChecker ED[T]['Update']['filter'] | Promise); }; -export declare type RelationChecker | SyncContext> = { +export type RelationChecker | SyncContext> = { priority?: number; type: 'relation'; entity: T; @@ -38,7 +38,7 @@ export declare type RelationChecker ED[T]['Update']['filter'] | Promise); }; -export declare type LogicalChecker | SyncContext> = { +export type LogicalChecker | SyncContext> = { priority?: number; type: 'logical'; when?: 'after'; @@ -47,7 +47,7 @@ export declare type LogicalChecker void | Promise; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); }; -export declare type LogicalRelationChecker | SyncContext> = { +export type LogicalRelationChecker | SyncContext> = { priority?: number; type: 'logicalRelation'; when?: 'after'; @@ -56,11 +56,11 @@ export declare type LogicalRelationChecker void | Promise; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); }; -export declare type Checker | SyncContext> = DataChecker | RowChecker | RelationChecker | LogicalChecker | LogicalRelationChecker; -export declare type AuthDef = { +export type Checker | SyncContext> = DataChecker | RowChecker | RelationChecker | LogicalChecker | LogicalRelationChecker; +export type AuthDef = { relationAuth?: CascadeRelationAuth>; actionAuth?: CascadeActionAuth; }; -export declare type AuthDefDict = { +export type AuthDefDict = { [K in keyof ED]?: AuthDef; }; diff --git a/lib/types/DataType.d.ts b/lib/types/DataType.d.ts index 1c81265..63eaa1e 100644 --- a/lib/types/DataType.d.ts +++ b/lib/types/DataType.d.ts @@ -1,18 +1,18 @@ import { Geo, SingleGeo } from "./Geo"; -export declare type Int = number; -export declare type Uint = number; -export declare type Double

= number; -export declare type Float

= number; -export declare type String = string; -export declare type Text = string; -export declare type Image = string; -export declare type File = string; -export declare type Datetime = number | Date; -export declare type Boolean = boolean; -export declare type PrimaryKey = string; -export declare type ForeignKey = string; -export declare type Sequence = string; +export type Int = number; +export type Uint = number; +export type Double

= number; +export type Float

= number; +export type String = string; +export type Text = string; +export type Image = string; +export type File = string; +export type Datetime = number | Date; +export type Boolean = boolean; +export type PrimaryKey = string; +export type ForeignKey = string; +export type Sequence = string; export { Geo, SingleGeo } from './Geo'; -export declare type DataTypes = number | string | Datetime | Geo | Object | SingleGeo; +export type DataTypes = number | string | Datetime | Geo | Object | SingleGeo; export declare const types: string[]; export declare const unIndexedTypes: string[]; diff --git a/lib/types/Demand.d.ts b/lib/types/Demand.d.ts index c2605fe..041672f 100644 --- a/lib/types/Demand.d.ts +++ b/lib/types/Demand.d.ts @@ -1,12 +1,12 @@ import { RefOrExpression } from "./Expression"; import { OneOf } from "./Polyfill"; export declare const EXPRESSION_PREFIX = "$expr"; -export declare type NodeId = `node-${number}`; -export declare type ExpressionKey = '$expr' | '$expr1' | '$expr2' | '$expr3' | '$expr4' | '$expr5' | '$expr6' | '$expr7' | '$expr8' | '$expr9' | '$expr10' | '$expr11' | '$expr12' | '$expr13' | '$expr14' | '$expr15' | '$expr16' | '$expr17' | '$expr18' | '$expr19' | '$expr20'; -export declare type ExprOp = { +export type NodeId = `node-${number}`; +export type ExpressionKey = '$expr' | '$expr1' | '$expr2' | '$expr3' | '$expr4' | '$expr5' | '$expr6' | '$expr7' | '$expr8' | '$expr9' | '$expr10' | '$expr11' | '$expr12' | '$expr13' | '$expr14' | '$expr15' | '$expr16' | '$expr17' | '$expr18' | '$expr19' | '$expr20'; +export type ExprOp = { [K in ExpressionKey]: RefOrExpression; }; -export declare type Q_NumberComparisonValue = number | OneOf<{ +export type Q_NumberComparisonValue = number | OneOf<{ $gt: number; $lt: number; $gte: number; @@ -17,7 +17,7 @@ export declare type Q_NumberComparisonValue = number | OneOf<{ $nin: number[]; $between: [number, number]; }>; -export declare type Q_StringComparisonValue = string | OneOf<{ +export type Q_StringComparisonValue = string | OneOf<{ $gt: string; $lt: string; $gte: string; @@ -30,44 +30,44 @@ export declare type Q_StringComparisonValue = string | OneOf<{ $in: string[]; $nin: string[]; }>; -export declare type Q_BooleanComparisonValue = boolean; -export declare type Q_DateComparisonValue = Q_NumberComparisonValue; -export declare type Q_EnumComparisonValue = E | OneOf<{ +export type Q_BooleanComparisonValue = boolean; +export type Q_DateComparisonValue = Q_NumberComparisonValue; +export type Q_EnumComparisonValue = E | OneOf<{ $in: E[]; $nin: E[]; }>; -export declare type Q_ExistsValue = { +export type Q_ExistsValue = { $exists: boolean; }; -export declare type Q_NumberValue = Q_NumberComparisonValue | Q_ExistsValue; -export declare type Q_StringValue = Q_StringComparisonValue | Q_ExistsValue; -export declare type Q_BooleanValue = Q_BooleanComparisonValue | Q_ExistsValue; -export declare type Q_DateValue = Q_DateComparisonValue | Q_ExistsValue; -export declare type Q_EnumValue = Q_EnumComparisonValue | Q_ExistsValue; -export declare type Q_State = S | { +export type Q_NumberValue = Q_NumberComparisonValue | Q_ExistsValue; +export type Q_StringValue = Q_StringComparisonValue | Q_ExistsValue; +export type Q_BooleanValue = Q_BooleanComparisonValue | Q_ExistsValue; +export type Q_DateValue = Q_DateComparisonValue | Q_ExistsValue; +export type Q_EnumValue = Q_EnumComparisonValue | Q_ExistsValue; +export type Q_State = S | { $in: S[]; } | { $nin: S[]; } | Q_ExistsValue; -export declare type Q_FullTextValue = { +export type Q_FullTextValue = { $search: string; $language?: 'zh_CN' | 'en_US'; }; -export declare type Q_FullTextKey = '$text'; -export declare type FulltextFilter = { +export type Q_FullTextKey = '$text'; +export type FulltextFilter = { [F in Q_FullTextKey]?: Q_FullTextValue; }; -declare type Q_LogicKey = '$and' | '$or'; -declare type Q_LinearLogicKey = '$not'; -export declare type MakeFilterWrapper = { +type Q_LogicKey = '$and' | '$or'; +type Q_LinearLogicKey = '$not'; +export type MakeFilterWrapper = { [Q in Q_LogicKey]?: Array>; } & { [Q in Q_LinearLogicKey]?: MakeFilterWrapper; } & Partial; -export declare type MakeFilter = { +export type MakeFilter = { '#id'?: NodeId; } & MakeFilterWrapper; -export declare type RefAttr = { +export type RefAttr = { '#attr': A; } | { '#refId': NodeId; diff --git a/lib/types/Entity.d.ts b/lib/types/Entity.d.ts index 83f6fdd..8c000d2 100644 --- a/lib/types/Entity.d.ts +++ b/lib/types/Entity.d.ts @@ -1,14 +1,11 @@ -import { GenericAction } from '../actions/action'; -import { ExprOp, MakeFilter, NodeId } from './Demand'; -import { OneOf } from './Polyfill'; import { PrimaryKey, Sequence } from './DataType'; -declare type TriggerDataAttributeType = '$$triggerData$$'; -declare type TriggerTimestampAttributeType = '$$triggerTimestamp$$'; -declare type PrimaryKeyAttributeType = 'id'; -declare type CreateAtAttributeType = '$$createAt$$'; -declare type UpdateAtAttributeType = '$$updateAt$$'; -declare type DeleteAtAttributeType = '$$deleteAt$$'; -declare type SeqAttributeType = '$$seq$$'; +type TriggerDataAttributeType = '$$triggerData$$'; +type TriggerTimestampAttributeType = '$$triggerTimestamp$$'; +type PrimaryKeyAttributeType = 'id'; +type CreateAtAttributeType = '$$createAt$$'; +type UpdateAtAttributeType = '$$updateAt$$'; +type DeleteAtAttributeType = '$$deleteAt$$'; +type SeqAttributeType = '$$seq$$'; export declare const TriggerDataAttribute = "$$triggerData$$"; export declare const TriggerTimestampAttribute = "$$triggerTimestamp$$"; export declare const PrimaryKeyAttribute = "id"; @@ -16,14 +13,14 @@ export declare const CreateAtAttribute = "$$createAt$$"; export declare const UpdateAtAttribute = "$$updateAt$$"; export declare const DeleteAtAttribute = "$$deleteAt$$"; export declare const SeqAttribute = "$$seq$$"; -export declare type InstinctiveAttributes = PrimaryKeyAttributeType | CreateAtAttributeType | UpdateAtAttributeType | DeleteAtAttributeType | TriggerDataAttributeType | TriggerTimestampAttributeType | SeqAttributeType; +export type InstinctiveAttributes = PrimaryKeyAttributeType | CreateAtAttributeType | UpdateAtAttributeType | DeleteAtAttributeType | TriggerDataAttributeType | TriggerTimestampAttributeType | SeqAttributeType; export declare const initinctiveAttributes: string[]; -export declare type Filter = { +type FilterPart = { filter?: A extends 'create' ? undefined : F; indexFrom?: A extends 'create' ? undefined : number; count?: A extends 'create' ? undefined : number; }; -export declare type SelectOption = { +export type SelectOption = { dontCollect?: boolean; blockTrigger?: true; obscure?: boolean; @@ -31,7 +28,7 @@ export declare type SelectOption = { includedDeleted?: true; dummy?: 1; }; -export declare type OperateOption = { +export type OperateOption = { blockTrigger?: true; dontCollect?: boolean; dontCreateOper?: boolean; @@ -41,19 +38,18 @@ export declare type OperateOption = { modiParentEntity?: string; dummy?: 1; }; -export declare type FormUpdateData = Partial<{ +export type FormUpdateData = Partial<{ [K in keyof Omit]: SH[K] | null; }>; -export declare type FormCreateData = Omit & { +export type FormCreateData = Omit & { id: string; }; -export declare type Operation = { +export type Operation = { id?: string; action: A; - data: DATA; - sorter?: SORTER; -} & Filter; -export declare type Selection = Operation<'select', DATA, FILTER, SORT>; + data: D; + sorter?: S; +} & FilterPart; export interface EntityShape { id: PrimaryKey; $$seq$$: Sequence; @@ -61,107 +57,104 @@ export interface EntityShape { $$updateAt$$: number | Date; $$deleteAt$$?: number | Date | null; } -export interface FileCarrierEntityShape extends EntityShape { -} interface GeneralEntityShape extends EntityShape { [K: string]: any; } -export declare type MakeAction = A; +export type MakeAction = A; export interface EntityDef { Schema: GeneralEntityShape; OpSchema: GeneralEntityShape; Action: string; ParticularAction?: string; - Selection: Omit, 'action'>; - Aggregation: Omit, DeduceFilter, DeduceSorter>, 'action'>; - Operation: DeduceOperation; - Create: DeduceCreateOperation; - CreateSingle: DeduceCreateSingleOperation; - CreateMulti: DeduceCreateMultipleOperation; - Update: DeduceUpdateOperation; - Remove: DeduceRemoveOperation; + Selection: Omit, 'action'>; + Aggregation: Omit, 'action'>; + Operation: CUDOperation; + Create: CreateOperation; + CreateSingle: CreateSingleOperation; + CreateMulti: CreateMultipleOperation; + Update: UpdateOperation; + Remove: RemoveOperation; Relation?: string; } export interface EntityDict { [E: string]: EntityDef; } -export interface OtmSubProjection extends Omit, 'action'> { +export interface OtmSubProjection extends Omit, 'action'> { $entity: string; } -declare type DeduceProjection = { - '#id'?: NodeId; -} & { - [K in keyof SH]?: number | OtmSubProjection | any; -} & Partial>; -export declare type AggregationOp = `#max-${number}` | `#min-${number}` | `#avg-${number}` | `#count-${number}` | `#sum-${number}`; -export declare type DeduceAggregationData> = { +export type AggregationOp = `#max-${number}` | `#min-${number}` | `#avg-${number}` | `#count-${number}` | `#sum-${number}`; +export type DeduceAggregationData

= { [A in AggregationOp]?: P; } & { '#aggr'?: P; }; -export declare type AggregationResult = Array<{ +export type AggregationResult = Array<{ [A in AggregationOp]?: number | string; } & { '#data'?: Partial; }>; -export declare type AttrFilter = { +export type AttrFilter = { [K in keyof SH]?: any; }; -export declare type DeduceFilter = MakeFilter & ExprOp>; -export declare type DeduceSorterAttr = OneOf<{ - [K: string]: number | object | undefined; -} & ExprOp>; -export declare type DeduceSorterItem = { - $attr: DeduceSorterAttr; +type SortAttr = { + [K: string]: any; +}; +type SorterItem = { + $attr: SortAttr; $direction?: "asc" | "desc"; }; -export declare type DeduceSorter = Array>; -export declare type DeduceSelection = Selection, DeduceFilter, DeduceSorter>; -export declare type DeduceAggregation, F extends DeduceFilter, S extends DeduceSorter> = Omit, F, S>, 'action'>; -export declare type DeduceCreateOperationData = { +type Sorter = Array; +type Filter = { + [K: string]: any; +}; +type Projection = { + [K: string]: any; +}; +export type DeduceAggregation

= Omit, F, S>, 'action'>; +type CreateOperationData = { id: string; -} & { - [k in keyof Omit]?: any; + [K: string]: any; }; -export declare type DeduceCreateSingleOperation = Operation<'create', DeduceCreateOperationData>; -export declare type DeduceCreateMultipleOperation = Operation<'create', Array>>; -export declare type DeduceCreateOperation = DeduceCreateSingleOperation | DeduceCreateMultipleOperation; -export declare type DeduceUpdateOperationData = { - [k in keyof Omit]?: any; +type CreateSingleOperation = Operation<'create', CreateOperationData, undefined, undefined>; +type CreateMultipleOperation = Operation<'create', Array, undefined, undefined>; +type CreateOperation = CreateSingleOperation | CreateMultipleOperation; +type UpdateOperationData = { + id?: never; + [k: string]: any; }; -export declare type DeduceUpdateOperation = Operation<'update' | string, DeduceUpdateOperationData, DeduceFilter, DeduceSorter>; -export declare type DeduceRemoveOperationData = { - [A in keyof Omit]?: any; +export type UpdateOperation = Operation; +type RemoveOperationData = { + [k: string]: any; }; -export declare type DeduceRemoveOperation = Operation<'remove', DeduceRemoveOperationData, DeduceFilter, DeduceSorter>; -export declare type DeduceOperation = DeduceCreateOperation | DeduceUpdateOperation | DeduceRemoveOperation; -export declare type CreateOpResult = { +export type RemoveOperation = Operation<'remove', RemoveOperationData, Filter, Sorter>; +export type CUDOperation = CreateOperation | UpdateOperation | RemoveOperation; +export type CreateOpResult = { a: 'c'; e: T; d: ED[T]['OpSchema'] | ED[T]['OpSchema'][]; }; -export declare type UpdateOpResult = { +export type UpdateOpResult = { a: 'u'; e: T; - d: DeduceUpdateOperationData; - f?: DeduceFilter; + d: UpdateOperationData; + f?: Filter; }; -export declare type RemoveOpResult = { +export type RemoveOpResult = { a: 'r'; e: T; - f?: DeduceFilter; + f?: Filter; }; -export declare type RelationHierarchy = { +export type RelationHierarchy = { [K in R]?: R[]; }; -export declare type CascadeRelationItem = { +export type CascadeRelationItem = { cascadePath: string; relations?: string[]; }; -export declare type CascadeRelationAuth = { +export type CascadeRelationAuth = { [K in R]?: CascadeRelationItem | (CascadeRelationItem | CascadeRelationItem[])[]; }; -export declare type SelectOpResult = { +export type SelectOpResult = { a: 's'; d: { [T in keyof ED]?: { @@ -169,14 +162,14 @@ export declare type SelectOpResult = { }; }; }; -export declare type OpRecord = CreateOpResult | UpdateOpResult | RemoveOpResult | SelectOpResult; -export declare type OperationResult = { +export type OpRecord = CreateOpResult | UpdateOpResult | RemoveOpResult | SelectOpResult; +export type OperationResult = { [K in keyof ED]?: { [A in ED[K]['Action']]?: number; }; }; -export declare type ActionType = 'readOnly' | 'appendOnly' | 'excludeUpdate' | 'excludeRemove' | 'crud'; -export declare type Configuration = { +export type ActionType = 'readOnly' | 'appendOnly' | 'excludeUpdate' | 'excludeRemove' | 'crud'; +export type Configuration = { actionType?: ActionType; static?: boolean; }; diff --git a/lib/types/Entity.js b/lib/types/Entity.js index b9c71bb..20f99ba 100644 --- a/lib/types/Entity.js +++ b/lib/types/Entity.js @@ -12,4 +12,3 @@ exports.initinctiveAttributes = [exports.PrimaryKeyAttribute, exports.TriggerDat ; ; ; -; diff --git a/lib/types/Expression.d.ts b/lib/types/Expression.d.ts index cdeb126..a379eb8 100644 --- a/lib/types/Expression.d.ts +++ b/lib/types/Expression.d.ts @@ -1,8 +1,8 @@ import { RefAttr } from "./Demand"; import { Geo } from "./Geo"; -export declare type RefOrExpression = RefAttr | Expression; -declare type MathType = RefOrExpression | number; -declare type StringType = RefOrExpression | string; +export type RefOrExpression = RefAttr | Expression; +type MathType = RefOrExpression | number; +type StringType = RefOrExpression | string; interface Add { $add: (MathType)[]; } @@ -30,8 +30,8 @@ interface Ceil { interface Pow { $pow: [MathType, MathType]; } -declare type MathExpression = Add | Subtract | Multiply | Divide | Abs | Round | Floor | Ceil | Pow; -declare type CmpType = RefOrExpression | string | number; +type MathExpression = Add | Subtract | Multiply | Divide | Abs | Round | Floor | Ceil | Pow; +type CmpType = RefOrExpression | string | number; interface Gt { $gt: [CmpType, CmpType]; } @@ -59,14 +59,14 @@ interface EndsWith { interface Includes { $includes: [RefOrExpression | string, RefOrExpression | string]; } -declare type CompareExpression = Lt | Gt | Lte | Gte | Eq | Ne | StartsWith | EndsWith | Includes; +type CompareExpression = Lt | Gt | Lte | Gte | Eq | Ne | StartsWith | EndsWith | Includes; interface BoolTrue { $true: Expression; } interface BoolFalse { $false: Expression; } -declare type BoolExpression = BoolTrue | BoolFalse; +type BoolExpression = BoolTrue | BoolFalse; interface LogicAnd { $and: Expression[]; } @@ -76,7 +76,7 @@ interface LogicOr { interface LogicNot { $not: Expression; } -declare type LogicExpression = LogicAnd | LogicOr | LogicNot; +type LogicExpression = LogicAnd | LogicOr | LogicNot; interface DateYear { $year: RefOrExpression | Date | number; } @@ -110,18 +110,18 @@ interface DateCeiling { interface DateFloor { $dateFloor: [RefOrExpression | Date | number, 'y' | 'M' | 'd' | 'h' | 'm' | 's']; } -declare type DateExpression = DateYear | DateMonth | DateWeekday | DateWeekOfYear | DateDay | DateDayOfYear | DateDayOfMonth | DateDayOfWeek | DateDiff | DateCeiling | DateFloor; +type DateExpression = DateYear | DateMonth | DateWeekday | DateWeekOfYear | DateDay | DateDayOfYear | DateDayOfMonth | DateDayOfWeek | DateDiff | DateCeiling | DateFloor; interface StringConcat { $concat: StringType[]; } -declare type StringExpression = StringConcat; +type StringExpression = StringConcat; interface GeoContains { $contains: [RefOrExpression | Geo, RefOrExpression | Geo]; } interface GeoDistance { $distance: [RefOrExpression | Geo, RefOrExpression | Geo]; } -declare type GeoExpression = GeoContains | GeoDistance; +type GeoExpression = GeoContains | GeoDistance; interface AggrCountExpression { $$count: RefOrExpression; } @@ -137,9 +137,9 @@ interface AggrMinExpression { interface AggrAvgExpression { $$avg: RefOrExpression; } -export declare type AggrExpression = AggrAvgExpression | AggrCountExpression | AggrSumExpression | AggrMaxExpression | AggrMinExpression; -export declare type Expression = GeoExpression | DateExpression | LogicExpression | BoolExpression | CompareExpression | MathExpression | StringExpression | AggrExpression; -export declare type ExpressionConstant = Geo | number | Date | string | boolean; +export type AggrExpression = AggrAvgExpression | AggrCountExpression | AggrSumExpression | AggrMaxExpression | AggrMinExpression; +export type Expression = GeoExpression | DateExpression | LogicExpression | BoolExpression | CompareExpression | MathExpression | StringExpression | AggrExpression; +export type ExpressionConstant = Geo | number | Date | string | boolean; export declare function isGeoExpression(expression: any): expression is GeoExpression; export declare function isDateExpression(expression: any): expression is DateExpression; export declare function isLogicExpression(expression: any): expression is LogicExpression; diff --git a/lib/types/Geo.d.ts b/lib/types/Geo.d.ts index 1747c3f..f1ce57e 100644 --- a/lib/types/Geo.d.ts +++ b/lib/types/Geo.d.ts @@ -1,8 +1,8 @@ -export declare type Point = [number, number]; -export declare type Path = Array; -export declare type Polygon = Array; -export declare type Circle = [Point, number]; -export declare type SingleGeo = { +export type Point = [number, number]; +export type Path = Array; +export type Polygon = Array; +export type Circle = [Point, number]; +export type SingleGeo = { type: 'point'; coordinate: Point; } | { @@ -15,4 +15,4 @@ export declare type SingleGeo = { type: 'circle'; coordinate: Circle; }; -export declare type Geo = SingleGeo | SingleGeo[]; +export type Geo = SingleGeo | SingleGeo[]; diff --git a/lib/types/Locale.d.ts b/lib/types/Locale.d.ts index 108740e..190a966 100644 --- a/lib/types/Locale.d.ts +++ b/lib/types/Locale.d.ts @@ -1,17 +1,17 @@ import { EntityShape } from "./Entity"; -declare type Language = 'zh_CN' | 'en_US'; -declare type LocaleOfSchema> = { +type Language = 'zh_CN' | 'en_US'; +type LocaleOfSchema> = { [A in keyof Required>]: string; }; -declare type LocaleOfStringEnum = { +type LocaleOfStringEnum = { [K in A]: string; }; -declare type LocaleOfValue> = { +type LocaleOfValue> = { [K in keyof V]: { [K2 in V[K]]: string; }; }; -export declare type LocaleDef, Ac extends string, R extends string, V extends Record> = { +export type LocaleDef, Ac extends string, R extends string, V extends Record> = { [L in Language]?: { attr: LocaleOfSchema & { [A in keyof V]: string; diff --git a/lib/types/Polyfill.d.ts b/lib/types/Polyfill.d.ts index 7a2dfd8..f096aaa 100644 --- a/lib/types/Polyfill.d.ts +++ b/lib/types/Polyfill.d.ts @@ -1,23 +1,23 @@ -export declare type OmitInferKey = { +export type OmitInferKey = { [K in keyof T as T extends R ? never : K]: T[K]; }; -export declare type OmitInferValue = { +export type OmitInferValue = { [K in keyof T as T extends R ? never : K]: T[K]; }; -export declare type ValueOf = Obj[keyof Obj]; -export declare type OneOnly = { +export type ValueOf = Obj[keyof Obj]; +export type OneOnly = { [key in Exclude]?: undefined; } & Pick; -export declare type OneOfByKey = { +export type OneOfByKey = { [key in keyof Obj]: OneOnly; }; -export declare type OneOf = ValueOf>; -declare type IsOptional = { +export type OneOf = ValueOf>; +type IsOptional = { [K1 in Exclude]: T[K1]; } & { K?: T[K]; } extends T ? K : never; -export declare type OptionalKeys = { +export type OptionalKeys = { [K in keyof T]: IsOptional; }[keyof T]; export {}; diff --git a/lib/types/Port.d.ts b/lib/types/Port.d.ts index 8e0519a..3477304 100644 --- a/lib/types/Port.d.ts +++ b/lib/types/Port.d.ts @@ -1,6 +1,6 @@ import { AsyncContext } from "../store/AsyncRowStore"; import { EntityDict } from "./Entity"; -export declare type Exportation = { +export type Exportation = { name: string; id: string; entity: T; @@ -8,7 +8,7 @@ export declare type Exportation Partial>; }; -export declare type Importation = { +export type Importation = { name: string; id: string; entity: T; diff --git a/lib/types/RowStore.d.ts b/lib/types/RowStore.d.ts index 8c632f0..be4bec2 100644 --- a/lib/types/RowStore.d.ts +++ b/lib/types/RowStore.d.ts @@ -1,6 +1,6 @@ import { OperationResult, EntityDict } from './Entity'; import { StorageSchema } from './Storage'; -export declare type TxnOption = { +export type TxnOption = { isolationLevel: 'repeatable read' | 'serializable'; }; export declare abstract class RowStore { diff --git a/lib/types/Storage.d.ts b/lib/types/Storage.d.ts index 341fabc..99357b4 100644 --- a/lib/types/Storage.d.ts +++ b/lib/types/Storage.d.ts @@ -1,7 +1,7 @@ import { ActionType } from '.'; import { EntityDict, EntityShape, InstinctiveAttributes } from './Entity'; import { DataType, DataTypeParams } from './schema/DataTypes'; -export declare type Ref = 'ref'; +export type Ref = 'ref'; export interface Column { name: keyof SH | `${string}State`; size?: number; @@ -27,12 +27,12 @@ export interface Attribute { unique?: boolean; sequenceStart?: number; } -export declare type Attributes = Omit<{ +export type Attributes = Omit<{ [attrName in keyof SH]: Attribute; }, InstinctiveAttributes>; export interface EntityConfig { } -export declare type UniqConstraint = { +export type UniqConstraint = { attributes: Array; type?: string; }; @@ -51,6 +51,6 @@ export interface StorageDesc { relation?: string[]; view?: true; } -export declare type StorageSchema = { +export type StorageSchema = { [K in keyof ED]: StorageDesc; }; diff --git a/lib/types/Timer.d.ts b/lib/types/Timer.d.ts index c3d869a..ede68e0 100644 --- a/lib/types/Timer.d.ts +++ b/lib/types/Timer.d.ts @@ -1,11 +1,11 @@ import { EntityDict } from './Entity'; import { AsyncContext } from "../store/AsyncRowStore"; -declare type RoutineFn> = (context: Cxt) => Promise; -export declare type Routine> = { +type RoutineFn> = (context: Cxt) => Promise; +export type Routine> = { name: string; fn: RoutineFn; }; -export declare type Timer> = { +export type Timer> = { name: string; cron: string; fn: RoutineFn; diff --git a/lib/types/Trigger.d.ts b/lib/types/Trigger.d.ts index 0015048..4a0f0e6 100644 --- a/lib/types/Trigger.d.ts +++ b/lib/types/Trigger.d.ts @@ -24,7 +24,7 @@ export interface CreateTriggerCrossTxn | SyncContext> = CreateTriggerInTxn | CreateTriggerCrossTxn; +export type CreateTrigger | SyncContext> = CreateTriggerInTxn | CreateTriggerCrossTxn; /** * update trigger如果带有filter,说明只对存在限定条件的行起作用。此时系统在进行相应动作时, * 会判定当前动作的filter条件和trigger所定义的filter是否有交集(即有同时满足两个条件的行) @@ -46,7 +46,7 @@ export interface UpdateTriggerCrossTxn | SyncContext> = UpdateTriggerInTxn | UpdateTriggerCrossTxn; +export type UpdateTrigger | SyncContext> = UpdateTriggerInTxn | UpdateTriggerCrossTxn; /** * 同update trigger一样,remove trigger如果带有filter,说明只对存在限定条件的行起作用。此时系统在进行相应动作时, * 会判定当前动作的filter条件和trigger所定义的filter是否有交集(即有同时满足两个条件的行) @@ -67,7 +67,7 @@ export interface RemoveTriggerCrossTxn | SyncContext> = RemoveTriggerInTxn | RemoveTriggerCrossTxn; +export type RemoveTrigger | SyncContext> = RemoveTriggerInTxn | RemoveTriggerCrossTxn; export interface SelectTriggerBase extends TriggerBase { action: 'select'; } @@ -88,8 +88,8 @@ export interface SelectTriggerAfter[]; }, context: Cxt, params?: SelectOption) => Promise | number; } -export declare type SelectTrigger | SyncContext> = SelectTriggerBefore | SelectTriggerAfter; -export declare type Trigger | SyncContext> = CreateTrigger | UpdateTrigger | RemoveTrigger | SelectTrigger; +export type SelectTrigger | SyncContext> = SelectTriggerBefore | SelectTriggerAfter; +export type Trigger | SyncContext> = CreateTrigger | UpdateTrigger | RemoveTrigger | SelectTrigger; export interface TriggerEntityShape extends EntityShape { $$triggerData$$?: { name: string; diff --git a/lib/types/Watcher.d.ts b/lib/types/Watcher.d.ts index fccbd9c..0fe8135 100644 --- a/lib/types/Watcher.d.ts +++ b/lib/types/Watcher.d.ts @@ -1,6 +1,6 @@ import { AsyncContext } from "../store/AsyncRowStore"; import { EntityDict, OperationResult } from "./Entity"; -declare type ActionData = ED[T]['Update']['data'] | ED[T]['Remove']['data']; +type ActionData = ED[T]['Update']['data'] | ED[T]['Remove']['data']; export interface BBWatcher { name: string; entity: T; @@ -15,5 +15,5 @@ export interface WBWatcher Promise); fn: (context: Cxt, data: Partial[]) => Promise>; } -export declare type Watcher> = BBWatcher | WBWatcher; +export type Watcher> = BBWatcher | WBWatcher; export {}; diff --git a/lib/types/schema/DataTypes.d.ts b/lib/types/schema/DataTypes.d.ts index e3c9fba..fbc2e69 100644 --- a/lib/types/schema/DataTypes.d.ts +++ b/lib/types/schema/DataTypes.d.ts @@ -1,28 +1,28 @@ /** * Column types used for @PrimaryGeneratedColumn() decorator. */ -export declare type PrimaryGeneratedColumnType = "int" | "int2" | "int4" | "int8" | "integer" | "tinyint" | "smallint" | "mediumint" | "bigint" | "dec" | "decimal" | "smalldecimal" | "fixed" | "numeric" | "number"; +export type PrimaryGeneratedColumnType = "int" | "int2" | "int4" | "int8" | "integer" | "tinyint" | "smallint" | "mediumint" | "bigint" | "dec" | "decimal" | "smalldecimal" | "fixed" | "numeric" | "number"; /** * Column types where spatial properties are used. */ -export declare type SpatialColumnType = "geometry" | "geography" | "st_geometry" | "st_point"; +export type SpatialColumnType = "geometry" | "geography" | "st_geometry" | "st_point"; /** * Column types where precision and scale properties are used. */ -export declare type WithPrecisionColumnType = "float" | "double" | "dec" | "decimal" | "smalldecimal" | "fixed" | "numeric" | "real" | "double precision" | "number" | "datetime" | "datetime2" | "datetimeoffset" | "time" | "time with time zone" | "time without time zone" | "timestamp" | "timestamp without time zone" | "timestamp with time zone" | "timestamp with local time zone"; +export type WithPrecisionColumnType = "float" | "double" | "dec" | "decimal" | "smalldecimal" | "fixed" | "numeric" | "real" | "double precision" | "number" | "datetime" | "datetime2" | "datetimeoffset" | "time" | "time with time zone" | "time without time zone" | "timestamp" | "timestamp without time zone" | "timestamp with time zone" | "timestamp with local time zone"; /** * Column types where column length is used. */ -export declare type WithLengthColumnType = "character varying" | "varying character" | "char varying" | "nvarchar" | "national varchar" | "character" | "native character" | "varchar" | "char" | "nchar" | "national char" | "varchar2" | "nvarchar2" | "alphanum" | "shorttext" | "raw" | "binary" | "varbinary" | "string"; -export declare type WithWidthColumnType = "tinyint" | "smallint" | "mediumint" | "int" | "bigint"; +export type WithLengthColumnType = "character varying" | "varying character" | "char varying" | "nvarchar" | "national varchar" | "character" | "native character" | "varchar" | "char" | "nchar" | "national char" | "varchar2" | "nvarchar2" | "alphanum" | "shorttext" | "raw" | "binary" | "varbinary" | "string"; +export type WithWidthColumnType = "tinyint" | "smallint" | "mediumint" | "int" | "bigint"; /** * All other regular column types. */ -export declare type SimpleColumnType = "simple-array" | "simple-json" | "simple-enum" | "int2" | "integer" | "int4" | "int8" | "int64" | "unsigned big int" | "float" | "float4" | "float8" | "smallmoney" | "money" | "boolean" | "bool" | "tinyblob" | "tinytext" | "mediumblob" | "mediumtext" | "blob" | "text" | "ntext" | "citext" | "hstore" | "longblob" | "longtext" | "alphanum" | "shorttext" | "bytes" | "bytea" | "long" | "raw" | "long raw" | "bfile" | "clob" | "nclob" | "image" | "timetz" | "timestamptz" | "timestamp with local time zone" | "smalldatetime" | "date" | "interval year to month" | "interval day to second" | "interval" | "year" | "seconddate" | "point" | "line" | "lseg" | "box" | "circle" | "path" | "polygon" | "geography" | "geometry" | "linestring" | "multipoint" | "multilinestring" | "multipolygon" | "geometrycollection" | "st_geometry" | "st_point" | "int4range" | "int8range" | "numrange" | "tsrange" | "tstzrange" | "daterange" | "enum" | "set" | "cidr" | "inet" | "macaddr" | "bit" | "bit varying" | "varbit" | "tsvector" | "tsquery" | "uuid" | "xml" | "json" | "jsonb" | "varbinary" | "hierarchyid" | "sql_variant" | "rowid" | "urowid" | "uniqueidentifier" | "rowversion" | "array" | "cube" | "ltree" | "object" | "array" | "function" | "sequence"; +export type SimpleColumnType = "simple-array" | "simple-json" | "simple-enum" | "int2" | "integer" | "int4" | "int8" | "int64" | "unsigned big int" | "float" | "float4" | "float8" | "smallmoney" | "money" | "boolean" | "bool" | "tinyblob" | "tinytext" | "mediumblob" | "mediumtext" | "blob" | "text" | "ntext" | "citext" | "hstore" | "longblob" | "longtext" | "alphanum" | "shorttext" | "bytes" | "bytea" | "long" | "raw" | "long raw" | "bfile" | "clob" | "nclob" | "image" | "timetz" | "timestamptz" | "timestamp with local time zone" | "smalldatetime" | "date" | "interval year to month" | "interval day to second" | "interval" | "year" | "seconddate" | "point" | "line" | "lseg" | "box" | "circle" | "path" | "polygon" | "geography" | "geometry" | "linestring" | "multipoint" | "multilinestring" | "multipolygon" | "geometrycollection" | "st_geometry" | "st_point" | "int4range" | "int8range" | "numrange" | "tsrange" | "tstzrange" | "daterange" | "enum" | "set" | "cidr" | "inet" | "macaddr" | "bit" | "bit varying" | "varbit" | "tsvector" | "tsquery" | "uuid" | "xml" | "json" | "jsonb" | "varbinary" | "hierarchyid" | "sql_variant" | "rowid" | "urowid" | "uniqueidentifier" | "rowversion" | "array" | "cube" | "ltree" | "object" | "array" | "function" | "sequence"; /** * Any column type column can be. */ -export declare type DataType = WithPrecisionColumnType | WithLengthColumnType | WithWidthColumnType | SpatialColumnType | SimpleColumnType; +export type DataType = WithPrecisionColumnType | WithLengthColumnType | WithWidthColumnType | SpatialColumnType | SimpleColumnType; export interface DataTypeParams { length?: number; width?: number; diff --git a/lib/utils/concurrent.d.ts b/lib/utils/concurrent.d.ts index c44feca..57d929b 100644 --- a/lib/utils/concurrent.d.ts +++ b/lib/utils/concurrent.d.ts @@ -1,4 +1,4 @@ -declare type Mode = 'S' | 'X'; +type Mode = 'S' | 'X'; /** * 模拟一个读写锁,用于同步。 * 注意,千万不要发生自己等自己 diff --git a/lib/utils/uuid.d.ts b/lib/utils/uuid.d.ts index 1d7ed56..595afb7 100644 --- a/lib/utils/uuid.d.ts +++ b/lib/utils/uuid.d.ts @@ -3,7 +3,7 @@ export declare function sequentialUuid({ random }: { }): string; export declare function shrinkUuidTo32Bytes(uuid: string): string; export declare function expandUuidTo36Bytes(uuidShrinked: string): string; -export declare type GenerateIdOption = { +export type GenerateIdOption = { shuffle?: boolean; }; export declare function generateNewIdAsync(option?: GenerateIdOption): Promise; diff --git a/lib/utils/validator.d.ts b/lib/utils/validator.d.ts index 318c121..bfa8afd 100644 --- a/lib/utils/validator.d.ts +++ b/lib/utils/validator.d.ts @@ -1,5 +1,5 @@ -declare type ValidatorFunction = (text: string, size?: number) => string | boolean; -declare type ValidatorMoneyFunction = (text: string, zero?: boolean) => string | boolean; +type ValidatorFunction = (text: string, size?: number) => string | boolean; +type ValidatorMoneyFunction = (text: string, zero?: boolean) => string | boolean; export declare const isMobile: ValidatorFunction; export declare const isPassword: ValidatorFunction; export declare const isCaptcha: ValidatorFunction; diff --git a/package.json b/package.json index e692dd8..a10d872 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "mocha": "^8.2.1", "ts-node": "~10.9.1", "tslib": "^2.4.0", - "typescript": "~4.7.4" + "typescript": "^4.9.4" }, "dependencies": { "@datasert/cronjs-matcher": "^1.2.0", diff --git a/src/compiler/schemalBuilder.ts b/src/compiler/schemalBuilder.ts index 866087d..4d4f572 100644 --- a/src/compiler/schemalBuilder.ts +++ b/src/compiler/schemalBuilder.ts @@ -2883,10 +2883,6 @@ function constructActions(statements: Array, entity: string) { factory.createTypeReferenceNode( factory.createIdentifier("DeduceAggregation"), [ - factory.createTypeReferenceNode( - factory.createIdentifier("Schema"), - undefined - ), factory.createTypeReferenceNode( factory.createIdentifier("Projection"), undefined @@ -4318,10 +4314,6 @@ function constructActions(statements: Array, entity: string) { factory.createTypeReferenceNode( factory.createIdentifier("RemoveOperation"), undefined - ), - factory.createTypeReferenceNode( - factory.createIdentifier("SelectOperation"), - undefined ) ]) ) @@ -4562,23 +4554,6 @@ const initialStatements = () => [ function outputSubQuery(outputDir: string, printer: ts.Printer) { const statements: ts.Statement[] = []; if (process.env.COMPLING_AS_LIB) { - statements.push( - factory.createImportDeclaration( - undefined, - undefined, - factory.createImportClause( - false, - undefined, - factory.createNamedImports([factory.createImportSpecifier( - false, - undefined, - factory.createIdentifier("Selection") - )]) - ), - factory.createStringLiteral(TYPE_PATH_IN_OAK_DOMAIN(1)), - undefined - ) - ); } for (const entity in Schema) { // import * as User from '../User/Schema'; diff --git a/src/store/CascadeStore.ts b/src/store/CascadeStore.ts index 632747a..52a74cc 100644 --- a/src/store/CascadeStore.ts +++ b/src/store/CascadeStore.ts @@ -1,7 +1,7 @@ import assert from "assert"; import { EntityDict, - OperateOption, SelectOption, OperationResult, DeduceFilter, CreateAtAttribute, UpdateAtAttribute, AggregationResult, DeleteAtAttribute + OperateOption, SelectOption, OperationResult, CreateAtAttribute, UpdateAtAttribute, AggregationResult, DeleteAtAttribute } from "../types/Entity"; import { EntityDict as BaseEntityDict } from '../base-app-domain'; import { RowStore } from '../types/RowStore'; @@ -525,7 +525,7 @@ export abstract class CascadeStore exten operation: ED[T2]['Operation'], context: Cxt, option: OP) => R, - filter?: DeduceFilter + filter?: ED[T]['Update']['filter'] ) { const modiAttr = this.getSchema()[entity].toModi; const option2 = Object.assign({}, option); @@ -830,7 +830,7 @@ export abstract class CascadeStore exten } // 对更新的数据,去掉所有的undefined属性 - protected preProcessDataUpdated(data: ED[T]['Update']['data']) { + protected preProcessDataUpdated(data: Record) { const undefinedKeys = Object.keys(data).filter( ele => data[ele] === undefined ); @@ -852,7 +852,7 @@ export abstract class CascadeStore exten * @param option */ private async doUpdateSingleRowAsync>(entity: T, - operation: ED[T]['Operation'], + operation: ED[T]['CreateSingle'] | ED[T]['Update'] | ED[T]['Remove'], context: Cxt, option: OP ) { @@ -1182,7 +1182,7 @@ export abstract class CascadeStore exten id: { $in: ids, } - } as DeduceFilter, + }, }); } } @@ -1202,7 +1202,7 @@ export abstract class CascadeStore exten id: { $in: ids, } - } as DeduceFilter, + }, }); } } diff --git a/src/store/TriggerExecutor.ts b/src/store/TriggerExecutor.ts index 67a2c61..a250a8f 100644 --- a/src/store/TriggerExecutor.ts +++ b/src/store/TriggerExecutor.ts @@ -1,7 +1,7 @@ import assert from 'assert'; import { pull, unset } from "../utils/lodash"; import { addFilterSegment, checkFilterRepel } from "../store/filter"; -import { DeduceCreateOperation, EntityDict, OperateOption, SelectOption, TriggerDataAttribute, TriggerTimestampAttribute } from "../types/Entity"; +import { EntityDict, OperateOption, SelectOption, TriggerDataAttribute, TriggerTimestampAttribute } from "../types/Entity"; import { EntityDict as BaseEntityDict } from '../base-app-domain'; import { Logger } from "../types/Logger"; import { Checker, CheckerType, LogicalChecker, RelationChecker } from '../types/Auth'; @@ -229,9 +229,9 @@ export class TriggerExecutor { // trigger只对满足条件的前项进行判断,如果确定不满足可以pass assert(operation.action !== 'create'); const { filter } = trigger as UpdateTrigger; - const filterr = typeof filter === 'function' ? filter(operation, context, option) : filter; + const filterr = typeof filter === 'function' ? filter(operation as ED[T]['Update'], context, option) : filter; assert(!(filterr instanceof Promise)); - const filterRepelled = checkFilterRepel(entity, context, filterr, operation.filter) as boolean + const filterRepelled = checkFilterRepel(entity, context, filterr, operation.filter) as boolean if (filterRepelled) { continue; } @@ -253,8 +253,8 @@ export class TriggerExecutor { if ((trigger as UpdateTrigger).filter) { assert(operation.action !== 'create'); const { filter } = trigger as UpdateTrigger; - const filterr = typeof filter === 'function' ? await filter(operation, context, option) : filter; - const filterRepelled = await (checkFilterRepel(entity, context, filterr, operation.filter) as Promise); + const filterr = typeof filter === 'function' ? await filter(operation as ED[T]['Update'], context, option) : filter; + const filterRepelled = await (checkFilterRepel(entity, context, filterr, operation.filter) as Promise); if (filterRepelled) { return execPreTrigger(idx + 1); } @@ -273,8 +273,8 @@ export class TriggerExecutor { if ((trigger as UpdateTrigger).filter) { assert(operation.action !== 'create'); const { filter } = trigger as UpdateTrigger; - const filterr = typeof filter === 'function' ? await filter(operation, context, option) : filter; - const filterRepelled = await (checkFilterRepel(entity, context, filterr, operation.filter) as Promise); + const filterr = typeof filter === 'function' ? await filter(operation as ED[T]['Update'], context, option) : filter; + const filterRepelled = await (checkFilterRepel(entity, context, filterr, operation.filter) as Promise); if (filterRepelled) { return execCommitTrigger(idx + 1); } @@ -295,7 +295,7 @@ export class TriggerExecutor { return async () => { await context.begin(); const number = await (trigger as CreateTrigger>).fn({ - operation: operation as DeduceCreateOperation, + operation: operation as ED[T]['Create'], }, context, option); if ((trigger as CreateTriggerCrossTxn).strict === 'makeSure') { // 如果是必须完成的trigger,在完成成功后要把trigger相关的属性置null; @@ -355,10 +355,10 @@ export class TriggerExecutor { ); if (triggers) { const postTriggers = triggers.filter( - ele => ele.when === 'after' && (!(ele as CreateTrigger).check || (ele as CreateTrigger).check!(operation as DeduceCreateOperation)) + ele => ele.when === 'after' && (!(ele as CreateTrigger).check || (ele as CreateTrigger).check!(operation as ED[T]['Create'])) ); const commitTriggers = (>>triggers).filter( - ele => ele.when === 'commit' && (!ele.check || ele.check(operation as DeduceCreateOperation)) + ele => ele.when === 'commit' && (!ele.check || ele.check(operation as ED[T]['Create'])) ); if (context instanceof SyncContext) { diff --git a/src/store/checker.ts b/src/store/checker.ts index c42639e..ae421d1 100644 --- a/src/store/checker.ts +++ b/src/store/checker.ts @@ -39,13 +39,13 @@ export function translateCheckerInAsyncContext< const { filter, errMsg, inconsistentRows } = checker; const fn = (async ({ operation }, context, option) => { const { filter: operationFilter, action } = operation; - const filter2 = typeof filter === 'function' ? await filter(operation, context, option) : filter; + const filter2 = typeof filter === 'function' ? await (filter as Function)(operation, context, option) : filter; if (['select', 'count', 'stat'].includes(action)) { operation.filter = addFilterSegment(operationFilter || {}, filter2); return 0; } else { - if (await checkFilterContains(entity, context, filter2, operationFilter || {}, true)) { + if (await checkFilterContains(entity, context, filter2, operationFilter || {}, true)) { return 0; } if (inconsistentRows) { @@ -179,7 +179,7 @@ export function translateCheckerInSyncContext< const { filter, errMsg } = checker; const fn = (operation: ED[T]['Operation'], context: Cxt, option: OperateOption | SelectOption) => { const { filter: operationFilter, action } = operation; - const filter2 = typeof filter === 'function' ? filter(operation, context, option) : filter; + 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); diff --git a/src/store/filter.ts b/src/store/filter.ts index fdc672d..b7af2d2 100644 --- a/src/store/filter.ts +++ b/src/store/filter.ts @@ -732,14 +732,14 @@ export function getRelevantIds(filter if (filter?.$and) { const idss = filter.$and.map( - ele => getRelevantIds(ele) + (ele: ED[T]['Selection']['filter']) => getRelevantIds(ele) ); idsAnd = intersection(...idss); } if (filter?.$or) { const idss = filter.$or.map( - ele => getRelevantIds(ele) + (ele: ED[T]['Selection']['filter']) => getRelevantIds(ele) ); idsOr = union(...idss); } diff --git a/src/store/selection.ts b/src/store/selection.ts index 324db85..b1fefe0 100644 --- a/src/store/selection.ts +++ b/src/store/selection.ts @@ -1,7 +1,7 @@ import assert from 'assert'; import { getAttrRefInExpression, StorageSchema } from '../types'; import { EXPRESSION_PREFIX } from '../types/Demand'; -import { DeduceFilter, EntityDict } from '../types/Entity'; +import { EntityDict } from '../types/Entity'; import { getRelevantIds } from './filter'; import { judgeRelation } from './relation'; @@ -29,7 +29,7 @@ export function reinforceSelection(schema: StorageSchema< const toBeAssignNode: Record = {}; // 用来记录在表达式中涉及到的结点 // filter当中所关联到的属性必须在projection中 const filterNodeDict: Record = {}; - const checkFilterNode = (entity2: keyof ED, filterNode: DeduceFilter, projectionNode: ED[keyof ED]['Selection']['data']) => { + const checkFilterNode = (entity2: keyof ED, filterNode: ED[keyof ED]['Selection']['filter'], projectionNode: ED[keyof ED]['Selection']['data']) => { const necessaryAttrs: string[] = ['id']; for (const attr in filterNode) { if (attr === '#id') { diff --git a/src/types/Entity.ts b/src/types/Entity.ts index 92bd6d2..f7f4371 100644 --- a/src/types/Entity.ts +++ b/src/types/Entity.ts @@ -1,6 +1,3 @@ -import { GenericAction } from '../actions/action'; -import { ExpressionKey, ExprOp, FulltextFilter, MakeFilter, NodeId, Q_BooleanValue, Q_NumberValue, Q_StringValue } from './Demand'; -import { OneOf, OptionalKeys } from './Polyfill'; import { PrimaryKey, Sequence } from './DataType'; type TriggerDataAttributeType = '$$triggerData$$'; @@ -22,7 +19,7 @@ export const SeqAttribute = '$$seq$$'; export type InstinctiveAttributes = PrimaryKeyAttributeType | CreateAtAttributeType | UpdateAtAttributeType| DeleteAtAttributeType | TriggerDataAttributeType | TriggerTimestampAttributeType | SeqAttributeType; export const initinctiveAttributes = [PrimaryKeyAttribute, TriggerDataAttribute, TriggerTimestampAttribute, CreateAtAttribute, UpdateAtAttribute, DeleteAtAttribute, SeqAttribute]; -export type Filter = { +type FilterPart = { filter?: A extends 'create' ? undefined : F; indexFrom?: A extends 'create' ? undefined : number; count?: A extends 'create' ? undefined : number; @@ -54,19 +51,15 @@ export type FormUpdateData = Partial<{ export type FormCreateData = Omit & { id: string }; -export type Operation = { +export type Operation = { id?: string; // 为了一致性,每个operation也应当保证唯一id action: A; - data: DATA; - sorter?: SORTER; - } & Filter; - -export type Selection = Operation<'select', DATA, FILTER, SORT>; + data: D; + sorter?: S; + } & FilterPart; export interface EntityShape { id: PrimaryKey; @@ -76,9 +69,6 @@ export interface EntityShape { $$deleteAt$$?: number | Date | null; } -export interface FileCarrierEntityShape extends EntityShape { -}; - interface GeneralEntityShape extends EntityShape { [K: string]: any; } @@ -91,14 +81,14 @@ export interface EntityDef { OpSchema: GeneralEntityShape; Action: string; ParticularAction?: string; - Selection: Omit, 'action'>; - Aggregation: Omit, DeduceFilter, DeduceSorter>, 'action'>; - Operation: DeduceOperation; - Create: DeduceCreateOperation; - CreateSingle: DeduceCreateSingleOperation; - CreateMulti: DeduceCreateMultipleOperation; - Update: DeduceUpdateOperation; - Remove: DeduceRemoveOperation; + Selection: Omit, 'action'>; + Aggregation: Omit, 'action'>; + Operation: CUDOperation; + Create: CreateOperation; + CreateSingle: CreateSingleOperation; + CreateMulti: CreateMultipleOperation; + Update: UpdateOperation; + Remove: RemoveOperation; Relation?: string; }; @@ -106,19 +96,13 @@ export interface EntityDict { [E: string]: EntityDef; }; -export interface OtmSubProjection extends Omit, 'action'> { +export interface OtmSubProjection extends Omit, 'action'> { $entity: string; }; -type DeduceProjection = { - '#id'?: NodeId; -} & { - [K in keyof SH]?: number | OtmSubProjection | any; -} & Partial>; - export type AggregationOp = `#max-${number}` | `#min-${number}` | `#avg-${number}` | `#count-${number}` | `#sum-${number}`; -export type DeduceAggregationData> = { +export type DeduceAggregationData

= { [A in AggregationOp]?: P; } & { '#aggr'?: P; @@ -134,54 +118,55 @@ export type AttrFilter = { [K in keyof SH]?: any; } -export type DeduceFilter = MakeFilter & ExprOp>; +type SortAttr = { + [K: string]: any; +}; -export type DeduceSorterAttr = OneOf<{ - [K: string]: number | object | undefined; -} & ExprOp>; - -export type DeduceSorterItem = { - $attr: DeduceSorterAttr; +type SorterItem = { + $attr: SortAttr $direction?: "asc" | "desc"; }; -export type DeduceSorter = Array>; +type Sorter = Array; -export type DeduceSelection = Selection, DeduceFilter, DeduceSorter>; +type Filter = { + [K: string]: any; +} + +type Projection = { + [K: string]: any; +} export type DeduceAggregation< - SH extends GeneralEntityShape, - P extends DeduceProjection, - F extends DeduceFilter, - S extends DeduceSorter> = Omit, F, S>, 'action'>; + P extends Projection, + F extends Filter, + S extends Sorter> = Omit, F, S>, 'action'>; -export type DeduceCreateOperationData = { +type CreateOperationData = { id: string; -} & { - [k in keyof Omit]?: any; + [K: string]: any; }; -export type DeduceCreateSingleOperation = Operation<'create', DeduceCreateOperationData>; +type CreateSingleOperation = Operation<'create', CreateOperationData, undefined, undefined>; -export type DeduceCreateMultipleOperation = Operation<'create', Array>>; +type CreateMultipleOperation = Operation<'create', Array, undefined, undefined>; -export type DeduceCreateOperation = DeduceCreateSingleOperation | DeduceCreateMultipleOperation; +type CreateOperation = CreateSingleOperation | CreateMultipleOperation; -export type DeduceUpdateOperationData = { - [k in keyof Omit]?: any; -}; +type UpdateOperationData = { + id?: never; + [k: string]: any; +} -export type DeduceUpdateOperation = Operation< - 'update' | string, - DeduceUpdateOperationData, DeduceFilter, DeduceSorter>; +export type UpdateOperation = Operation; -export type DeduceRemoveOperationData = { - [A in keyof Omit]?: any; -}; +type RemoveOperationData = { + [k: string]: any; +} -export type DeduceRemoveOperation = Operation<'remove', DeduceRemoveOperationData, DeduceFilter, DeduceSorter>; +export type RemoveOperation = Operation<'remove', RemoveOperationData, Filter, Sorter>; -export type DeduceOperation = DeduceCreateOperation | DeduceUpdateOperation | DeduceRemoveOperation; +export type CUDOperation = CreateOperation | UpdateOperation | RemoveOperation; export type CreateOpResult = { a: 'c'; @@ -192,14 +177,14 @@ export type CreateOpResult = { export type UpdateOpResult = { a: 'u', e: T; - d: DeduceUpdateOperationData; - f?: DeduceFilter; + d: UpdateOperationData; + f?: Filter; }; export type RemoveOpResult = { a: 'r', e: T; - f?: DeduceFilter; + f?: Filter; }; export type RelationHierarchy = { From 3f04d930e9d42a0accb70e60eb3885e4528ce9c5 Mon Sep 17 00:00:00 2001 From: "Xc@centOs" Date: Thu, 19 Jan 2023 17:20:02 +0800 Subject: [PATCH 16/19] endpoint --- lib/types/Endpoint.d.ts | 10 ++++++++++ lib/types/Endpoint.js | 3 +++ lib/types/index.d.ts | 1 + lib/types/index.js | 1 + src/types/Endpoint.ts | 10 ++++++++++ src/types/index.ts | 3 ++- 6 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 lib/types/Endpoint.d.ts create mode 100644 lib/types/Endpoint.js create mode 100644 src/types/Endpoint.ts diff --git a/lib/types/Endpoint.d.ts b/lib/types/Endpoint.d.ts new file mode 100644 index 0000000..024ec71 --- /dev/null +++ b/lib/types/Endpoint.d.ts @@ -0,0 +1,10 @@ +/// +import { ClientRequest, IncomingHttpHeaders } from "http"; +import { AsyncContext } from "../store/AsyncRowStore"; +import { EntityDict } from "./Entity"; +export interface Endpoint> { + name: string; + params?: string[]; + method: 'get' | 'post' | 'put' | 'delete'; + fn: (context: BackCxt, params: Record, body: any, headers: IncomingHttpHeaders, req: ClientRequest) => Promise; +} diff --git a/lib/types/Endpoint.js b/lib/types/Endpoint.js new file mode 100644 index 0000000..04363ad --- /dev/null +++ b/lib/types/Endpoint.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +; diff --git a/lib/types/index.d.ts b/lib/types/index.d.ts index 99c3b3e..dcb0909 100644 --- a/lib/types/index.d.ts +++ b/lib/types/index.d.ts @@ -18,3 +18,4 @@ export * from './AppLoader'; export * from './Connector'; export * from './Timer'; export * from './Port'; +export * from './Endpoint'; diff --git a/lib/types/index.js b/lib/types/index.js index 3071cfa..986fd63 100644 --- a/lib/types/index.js +++ b/lib/types/index.js @@ -21,3 +21,4 @@ tslib_1.__exportStar(require("./AppLoader"), exports); tslib_1.__exportStar(require("./Connector"), exports); tslib_1.__exportStar(require("./Timer"), exports); tslib_1.__exportStar(require("./Port"), exports); +tslib_1.__exportStar(require("./Endpoint"), exports); diff --git a/src/types/Endpoint.ts b/src/types/Endpoint.ts new file mode 100644 index 0000000..afc715e --- /dev/null +++ b/src/types/Endpoint.ts @@ -0,0 +1,10 @@ +import { ClientRequest, IncomingHttpHeaders } from "http"; +import { AsyncContext } from "../store/AsyncRowStore"; +import { EntityDict } from "./Entity"; + +export interface Endpoint> { + name: string; + params?: string[]; + method: 'get' | 'post' | 'put' | 'delete'; + fn: (context: BackCxt, params: Record, body: any, headers: IncomingHttpHeaders, req: ClientRequest) => Promise; +}; diff --git a/src/types/index.ts b/src/types/index.ts index 9d33733..dcb0909 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -17,4 +17,5 @@ export * from './Watcher'; export * from './AppLoader'; export * from './Connector'; export * from './Timer'; -export * from './Port'; \ No newline at end of file +export * from './Port'; +export * from './Endpoint'; From 93d5edaaef78a4474ddfca43e2532d7f6b55de0e Mon Sep 17 00:00:00 2001 From: Xc Date: Thu, 19 Jan 2023 20:57:31 +0800 Subject: [PATCH 17/19] =?UTF-8?q?=E9=87=8D=E6=96=B0=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E4=BA=86FormCreateData?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/actions/action.d.ts | 16 ++-- lib/actions/relation.d.ts | 2 +- lib/base-app-domain/EntityDict.d.ts | 2 +- lib/base-app-domain/Modi/Action.d.ts | 8 +- lib/base-app-domain/Modi/Schema.d.ts | 48 ++++++------ lib/base-app-domain/ModiEntity/Schema.d.ts | 56 +++++++------- lib/base-app-domain/Oper/Schema.d.ts | 52 ++++++------- lib/base-app-domain/OperEntity/Schema.d.ts | 60 +++++++-------- lib/base-app-domain/User/Schema.d.ts | 48 ++++++------ lib/base-app-domain/_SubQuery.d.ts | 10 +-- lib/store/TriggerExecutor.d.ts | 2 +- lib/types/Action.d.ts | 10 +-- lib/types/Auth.d.ts | 18 ++--- lib/types/DataType.d.ts | 28 +++---- lib/types/Demand.d.ts | 46 +++++------ lib/types/Entity.d.ts | 90 +++++++++++----------- lib/types/Expression.d.ts | 28 +++---- lib/types/Geo.d.ts | 12 +-- lib/types/Locale.d.ts | 10 +-- lib/types/Polyfill.d.ts | 16 ++-- lib/types/Port.d.ts | 4 +- lib/types/RowStore.d.ts | 2 +- lib/types/Storage.d.ts | 8 +- lib/types/Timer.d.ts | 6 +- lib/types/Trigger.d.ts | 10 +-- lib/types/Watcher.d.ts | 4 +- lib/types/schema/DataTypes.d.ts | 14 ++-- lib/utils/concurrent.d.ts | 2 +- lib/utils/uuid.d.ts | 2 +- lib/utils/validator.d.ts | 4 +- src/types/Entity.ts | 2 +- 31 files changed, 310 insertions(+), 310 deletions(-) diff --git a/lib/actions/action.d.ts b/lib/actions/action.d.ts index a2f31d3..05fe2f5 100644 --- a/lib/actions/action.d.ts +++ b/lib/actions/action.d.ts @@ -1,16 +1,16 @@ import { ActionDef } from '../types/Action'; -export type ReadOnlyAction = 'select' | 'count' | 'stat' | 'download'; -export type AppendOnlyAction = ReadOnlyAction | 'create'; -export type ExcludeUpdateAction = AppendOnlyAction | 'remove'; -export type ExcludeRemoveAction = AppendOnlyAction | 'update'; -export type GenericAction = 'update' | ExcludeUpdateAction; -export type RelationAction = 'grant' | 'revoke'; +export declare type ReadOnlyAction = 'select' | 'count' | 'stat' | 'download'; +export declare type AppendOnlyAction = ReadOnlyAction | 'create'; +export declare type ExcludeUpdateAction = AppendOnlyAction | 'remove'; +export declare type ExcludeRemoveAction = AppendOnlyAction | 'update'; +export declare type GenericAction = 'update' | ExcludeUpdateAction; +export declare type RelationAction = 'grant' | 'revoke'; export declare const readOnlyActions: string[]; export declare const appendOnlyActions: string[]; export declare const excludeUpdateActions: string[]; export declare const exludeRemoveActions: string[]; export declare const genericActions: string[]; export declare const relationActions: string[]; -export type AbleAction = 'enable' | 'disable'; -export type AbleState = 'enabled' | 'disabled'; +export declare type AbleAction = 'enable' | 'disable'; +export declare type AbleState = 'enabled' | 'disabled'; export declare const makeAbleActionDef: (initialState?: AbleState) => ActionDef; diff --git a/lib/actions/relation.d.ts b/lib/actions/relation.d.ts index 2f74e02..d012b77 100644 --- a/lib/actions/relation.d.ts +++ b/lib/actions/relation.d.ts @@ -1,5 +1,5 @@ import { CascadeRelationItem, RelationHierarchy } from "../types/Entity"; -export type GenericRelation = 'owner'; +export declare type GenericRelation = 'owner'; export declare function convertHierarchyToAuth(hierarchy: RelationHierarchy): { [K in R]?: CascadeRelationItem; }; diff --git a/lib/base-app-domain/EntityDict.d.ts b/lib/base-app-domain/EntityDict.d.ts index b54b36e..cb81cf2 100644 --- a/lib/base-app-domain/EntityDict.d.ts +++ b/lib/base-app-domain/EntityDict.d.ts @@ -3,7 +3,7 @@ import { EntityDef as ModiEntity } from "./ModiEntity/Schema"; import { EntityDef as Oper } from "./Oper/Schema"; import { EntityDef as OperEntity } from "./OperEntity/Schema"; import { EntityDef as User } from "./User/Schema"; -export type EntityDict = { +export declare type EntityDict = { modi: Modi; modiEntity: ModiEntity; oper: Oper; diff --git a/lib/base-app-domain/Modi/Action.d.ts b/lib/base-app-domain/Modi/Action.d.ts index a114e7c..e22999c 100644 --- a/lib/base-app-domain/Modi/Action.d.ts +++ b/lib/base-app-domain/Modi/Action.d.ts @@ -1,9 +1,9 @@ import { ActionDef } from "../../types/Action"; import { GenericAction } from "../../actions/action"; -export type IState = 'active' | 'applied' | 'abandoned'; -export type IAction = 'apply' | 'abandon'; -export type ParticularAction = IAction; -export type Action = GenericAction | ParticularAction; +export declare type IState = 'active' | 'applied' | 'abandoned'; +export declare type IAction = 'apply' | 'abandon'; +export declare type ParticularAction = IAction; +export declare type Action = GenericAction | ParticularAction; export declare const actions: string[]; export declare const ActionDefDict: { iState: ActionDef; diff --git a/lib/base-app-domain/Modi/Schema.d.ts b/lib/base-app-domain/Modi/Schema.d.ts index 5874a91..d9d6dac 100644 --- a/lib/base-app-domain/Modi/Schema.d.ts +++ b/lib/base-app-domain/Modi/Schema.d.ts @@ -6,7 +6,7 @@ import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOper import { Action, ParticularAction, IState } from "./Action"; import * as ModiEntity from "../ModiEntity/Schema"; import * as OperEntity from "../OperEntity/Schema"; -export type OpSchema = EntityShape & { +export declare type OpSchema = EntityShape & { targetEntity: String<32>; entity: String<32>; entityId: String<64>; @@ -16,8 +16,8 @@ export type OpSchema = EntityShape & { extra?: Object | null; iState?: IState | null; }; -export type OpAttr = keyof OpSchema; -export type Schema = EntityShape & { +export declare type OpAttr = keyof OpSchema; +export declare type Schema = EntityShape & { targetEntity: String<32>; entity: String<32>; entityId: String<64>; @@ -33,7 +33,7 @@ export type Schema = EntityShape & { } & { [A in ExpressionKey]?: any; }; -type AttrFilter = { +declare type AttrFilter = { id: Q_StringValue | SubQuery.ModiIdSubQuery; $$createAt$$: Q_DateValue; $$seq$$: Q_StringValue; @@ -47,8 +47,8 @@ type AttrFilter = { extra: Object; iState: Q_EnumValue; }; -export type Filter = MakeFilter>; -export type Projection = { +export declare type Filter = MakeFilter>; +export declare type Projection = { "#id"?: NodeId; [k: string]: any; id?: number; @@ -76,10 +76,10 @@ export type Projection = { $entity: "operEntity"; }; } & Partial>; -type ModiIdProjection = OneOf<{ +declare type ModiIdProjection = OneOf<{ id: number; }>; -export type SortAttr = { +export declare type SortAttr = { id: number; } | { $$createAt$$: number; @@ -100,15 +100,15 @@ export type SortAttr = { } | { [k: string]: any; } | OneOf>; -export type SortNode = { +export declare type SortNode = { $attr: SortAttr; $direction?: "asc" | "desc"; }; -export type Sorter = SortNode[]; -export type SelectOperation

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

= Omit, "action">; -export type Aggregation = Omit, "id">; -export type CreateOperationData = FormCreateData> & ({ +export declare type Sorter = SortNode[]; +export declare type SelectOperation

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

= Omit, "action">; +export declare type Aggregation = Omit, "id">; +export declare type CreateOperationData = FormCreateData> & ({ entity?: string; entityId?: string; [K: string]: any; @@ -116,20 +116,20 @@ export type CreateOperationData = FormCreateData[]> | Array>>; operEntity$entity?: OakOperation<"create", Omit[]> | Array>>; }; -export type CreateSingleOperation = OakOperation<"create", CreateOperationData>; -export type CreateMultipleOperation = OakOperation<"create", Array>; -export type CreateOperation = CreateSingleOperation | CreateMultipleOperation; -export type UpdateOperationData = FormUpdateData & { +export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>; +export declare type CreateMultipleOperation = OakOperation<"create", Array>; +export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation; +export declare type UpdateOperationData = FormUpdateData & { [k: string]: any; modiEntitys$modi?: OakOperation<"create", Omit[]> | Array>>; operEntitys$entity?: OakOperation<"create", Omit[]> | Array>>; }; -export type UpdateOperation = OakOperation<"update" | ParticularAction | string, UpdateOperationData, Filter, Sorter>; -export type RemoveOperationData = {}; -export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; -export type Operation = CreateOperation | UpdateOperation | RemoveOperation; -export type ModiIdSubQuery = Selection; -export type EntityDef = { +export declare type UpdateOperation = OakOperation<"update" | ParticularAction | string, UpdateOperationData, Filter, Sorter>; +export declare type RemoveOperationData = {}; +export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; +export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation; +export declare type ModiIdSubQuery = Selection; +export declare type EntityDef = { Schema: Schema; OpSchema: OpSchema; Action: OakMakeAction | string; diff --git a/lib/base-app-domain/ModiEntity/Schema.d.ts b/lib/base-app-domain/ModiEntity/Schema.d.ts index 98ea464..c3c0bee 100644 --- a/lib/base-app-domain/ModiEntity/Schema.d.ts +++ b/lib/base-app-domain/ModiEntity/Schema.d.ts @@ -6,13 +6,13 @@ import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOper import { AppendOnlyAction } from "../../actions/action"; import * as Modi from "../Modi/Schema"; import * as User from "../User/Schema"; -export type OpSchema = EntityShape & { +export declare type OpSchema = EntityShape & { modiId: ForeignKey<"modi">; entity: "user" | string; entityId: String<64>; }; -export type OpAttr = keyof OpSchema; -export type Schema = EntityShape & { +export declare type OpAttr = keyof OpSchema; +export declare type Schema = EntityShape & { modiId: ForeignKey<"modi">; entity: "user" | string; entityId: String<64>; @@ -21,7 +21,7 @@ export type Schema = EntityShape & { } & { [A in ExpressionKey]?: any; }; -type AttrFilter = { +declare type AttrFilter = { id: Q_StringValue | SubQuery.ModiEntityIdSubQuery; $$createAt$$: Q_DateValue; $$seq$$: Q_StringValue; @@ -32,8 +32,8 @@ type AttrFilter = { entityId: Q_StringValue; user: User.Filter; }; -export type Filter> = MakeFilter & ExprOp>; -export type Projection = { +export declare type Filter> = MakeFilter & ExprOp>; +export declare type Projection = { "#id"?: NodeId; [k: string]: any; id?: number; @@ -46,16 +46,16 @@ export type Projection = { entityId?: number; user?: User.Projection; } & Partial>; -type ModiEntityIdProjection = OneOf<{ +declare type ModiEntityIdProjection = OneOf<{ id: number; }>; -type ModiIdProjection = OneOf<{ +declare type ModiIdProjection = OneOf<{ modiId: number; }>; -type UserIdProjection = OneOf<{ +declare type UserIdProjection = OneOf<{ entityId: number; }>; -export type SortAttr = { +export declare type SortAttr = { id: number; } | { $$createAt$$: number; @@ -76,15 +76,15 @@ export type SortAttr = { } | { [k: string]: any; } | OneOf>; -export type SortNode = { +export declare type SortNode = { $attr: SortAttr; $direction?: "asc" | "desc"; }; -export type Sorter = SortNode[]; -export type SelectOperation

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

= Omit, "action">; -export type Aggregation = Omit, "id">; -export type CreateOperationData = FormCreateData> & (({ +export declare type Sorter = SortNode[]; +export declare type SelectOperation

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

= Omit, "action">; +export declare type Aggregation = Omit, "id">; +export declare type CreateOperationData = FormCreateData> & (({ modiId?: never; modi: Modi.CreateSingleOperation; } | { @@ -108,10 +108,10 @@ export type CreateOperationData = FormCreateData; -export type CreateMultipleOperation = OakOperation<"create", Array>; -export type CreateOperation = CreateSingleOperation | CreateMultipleOperation; -export type UpdateOperationData = FormUpdateData> & (({ +export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>; +export declare type CreateMultipleOperation = OakOperation<"create", Array>; +export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation; +export declare type UpdateOperationData = FormUpdateData> & (({ modi: Modi.CreateSingleOperation; modiId?: never; } | { @@ -133,20 +133,20 @@ export type UpdateOperationData = FormUpdateData; -export type RemoveOperationData = {} & (({ +export declare type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>; +export declare type RemoveOperationData = {} & (({ modi?: Modi.UpdateOperation | Modi.RemoveOperation; })) & ({ user?: User.UpdateOperation | User.RemoveOperation; } | { [k: string]: any; }); -export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; -export type Operation = CreateOperation | UpdateOperation | RemoveOperation; -export type ModiIdSubQuery = Selection; -export type UserIdSubQuery = Selection; -export type ModiEntityIdSubQuery = Selection; -export type EntityDef = { +export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; +export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation; +export declare type ModiIdSubQuery = Selection; +export declare type UserIdSubQuery = Selection; +export declare type ModiEntityIdSubQuery = Selection; +export declare type EntityDef = { Schema: Schema; OpSchema: OpSchema; Action: OakMakeAction | string; diff --git a/lib/base-app-domain/Oper/Schema.d.ts b/lib/base-app-domain/Oper/Schema.d.ts index 10e71b1..fde88b9 100644 --- a/lib/base-app-domain/Oper/Schema.d.ts +++ b/lib/base-app-domain/Oper/Schema.d.ts @@ -6,15 +6,15 @@ import { FormCreateData, FormUpdateData, DeduceAggregation, Operation as OakOper import { AppendOnlyAction } from "../../actions/action"; import * as User from "../User/Schema"; import * as OperEntity from "../OperEntity/Schema"; -export type OpSchema = EntityShape & { +export declare type OpSchema = EntityShape & { action: String<16>; data: Object; filter?: Object | null; extra?: Object | null; operatorId?: ForeignKey<"user"> | null; }; -export type OpAttr = keyof OpSchema; -export type Schema = EntityShape & { +export declare type OpAttr = keyof OpSchema; +export declare type Schema = EntityShape & { action: String<16>; data: Object; filter?: Object | null; @@ -26,7 +26,7 @@ export type Schema = EntityShape & { } & { [A in ExpressionKey]?: any; }; -type AttrFilter = { +declare type AttrFilter = { id: Q_StringValue | SubQuery.OperIdSubQuery; $$createAt$$: Q_DateValue; $$seq$$: Q_StringValue; @@ -38,8 +38,8 @@ type AttrFilter = { operatorId: Q_StringValue | SubQuery.UserIdSubQuery; operator: User.Filter; }; -export type Filter = MakeFilter>; -export type Projection = { +export declare type Filter = MakeFilter>; +export declare type Projection = { "#id"?: NodeId; [k: string]: any; id?: number; @@ -59,13 +59,13 @@ export type Projection = { $entity: "operEntity"; }; } & Partial>; -type OperIdProjection = OneOf<{ +declare type OperIdProjection = OneOf<{ id: number; }>; -type UserIdProjection = OneOf<{ +declare type UserIdProjection = OneOf<{ operatorId: number; }>; -export type SortAttr = { +export declare type SortAttr = { id: number; } | { $$createAt$$: number; @@ -82,15 +82,15 @@ export type SortAttr = { } | { [k: string]: any; } | OneOf>; -export type SortNode = { +export declare type SortNode = { $attr: SortAttr; $direction?: "asc" | "desc"; }; -export type Sorter = SortNode[]; -export type SelectOperation

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

= Omit, "action">; -export type Aggregation = Omit, "id">; -export type CreateOperationData = FormCreateData> & (({ +export declare type Sorter = SortNode[]; +export declare type SelectOperation

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

= Omit, "action">; +export declare type Aggregation = Omit, "id">; +export declare type CreateOperationData = FormCreateData> & (({ operatorId?: never; operator?: User.CreateSingleOperation; } | { @@ -101,10 +101,10 @@ export type CreateOperationData = FormCreateData> & })) & { operEntity$oper?: OakOperation<"create", Omit[]> | Array>>; }; -export type CreateSingleOperation = OakOperation<"create", CreateOperationData>; -export type CreateMultipleOperation = OakOperation<"create", Array>; -export type CreateOperation = CreateSingleOperation | CreateMultipleOperation; -export type UpdateOperationData = FormUpdateData> & (({ +export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>; +export declare type CreateMultipleOperation = OakOperation<"create", Array>; +export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation; +export declare type UpdateOperationData = FormUpdateData> & (({ operator: User.CreateSingleOperation; operatorId?: never; } | { @@ -120,15 +120,15 @@ export type UpdateOperationData = FormUpdateData> & [k: string]: any; operEntitys$oper?: OakOperation<"create", Omit[]> | Array>>; }; -export type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>; -export type RemoveOperationData = {} & (({ +export declare type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>; +export declare type RemoveOperationData = {} & (({ operator?: User.UpdateOperation | User.RemoveOperation; })); -export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; -export type Operation = CreateOperation | UpdateOperation | RemoveOperation; -export type UserIdSubQuery = Selection; -export type OperIdSubQuery = Selection; -export type EntityDef = { +export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; +export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation; +export declare type UserIdSubQuery = Selection; +export declare type OperIdSubQuery = Selection; +export declare type EntityDef = { Schema: Schema; OpSchema: OpSchema; Action: OakMakeAction | string; diff --git a/lib/base-app-domain/OperEntity/Schema.d.ts b/lib/base-app-domain/OperEntity/Schema.d.ts index a500b12..98d2fc9 100644 --- a/lib/base-app-domain/OperEntity/Schema.d.ts +++ b/lib/base-app-domain/OperEntity/Schema.d.ts @@ -7,13 +7,13 @@ import { AppendOnlyAction } from "../../actions/action"; import * as Oper from "../Oper/Schema"; import * as Modi from "../Modi/Schema"; import * as User from "../User/Schema"; -export type OpSchema = EntityShape & { +export declare type OpSchema = EntityShape & { operId: ForeignKey<"oper">; entity: "modi" | "user" | string; entityId: String<64>; }; -export type OpAttr = keyof OpSchema; -export type Schema = EntityShape & { +export declare type OpAttr = keyof OpSchema; +export declare type Schema = EntityShape & { operId: ForeignKey<"oper">; entity: "modi" | "user" | string; entityId: String<64>; @@ -23,7 +23,7 @@ export type Schema = EntityShape & { } & { [A in ExpressionKey]?: any; }; -type AttrFilter = { +declare type AttrFilter = { id: Q_StringValue | SubQuery.OperEntityIdSubQuery; $$createAt$$: Q_DateValue; $$seq$$: Q_StringValue; @@ -35,8 +35,8 @@ type AttrFilter = { modi: Modi.Filter; user: User.Filter; }; -export type Filter> = MakeFilter & ExprOp>; -export type Projection = { +export declare type Filter> = MakeFilter & ExprOp>; +export declare type Projection = { "#id"?: NodeId; [k: string]: any; id?: number; @@ -50,19 +50,19 @@ export type Projection = { modi?: Modi.Projection; user?: User.Projection; } & Partial>; -type OperEntityIdProjection = OneOf<{ +declare type OperEntityIdProjection = OneOf<{ id: number; }>; -type OperIdProjection = OneOf<{ +declare type OperIdProjection = OneOf<{ operId: number; }>; -type ModiIdProjection = OneOf<{ +declare type ModiIdProjection = OneOf<{ entityId: number; }>; -type UserIdProjection = OneOf<{ +declare type UserIdProjection = OneOf<{ entityId: number; }>; -export type SortAttr = { +export declare type SortAttr = { id: number; } | { $$createAt$$: number; @@ -85,15 +85,15 @@ export type SortAttr = { } | { [k: string]: any; } | OneOf>; -export type SortNode = { +export declare type SortNode = { $attr: SortAttr; $direction?: "asc" | "desc"; }; -export type Sorter = SortNode[]; -export type SelectOperation

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

= Omit, "action">; -export type Aggregation = Omit, "id">; -export type CreateOperationData = FormCreateData> & (({ +export declare type Sorter = SortNode[]; +export declare type SelectOperation

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

= Omit, "action">; +export declare type Aggregation = Omit, "id">; +export declare type CreateOperationData = FormCreateData> & (({ operId?: never; oper: Oper.CreateSingleOperation; } | { @@ -125,10 +125,10 @@ export type CreateOperationData = FormCreateData; -export type CreateMultipleOperation = OakOperation<"create", Array>; -export type CreateOperation = CreateSingleOperation | CreateMultipleOperation; -export type UpdateOperationData = FormUpdateData> & (({ +export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>; +export declare type CreateMultipleOperation = OakOperation<"create", Array>; +export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation; +export declare type UpdateOperationData = FormUpdateData> & (({ oper: Oper.CreateSingleOperation; operId?: never; } | { @@ -148,21 +148,21 @@ export type UpdateOperationData = FormUpdateData; -export type RemoveOperationData = {} & ({ +export declare type UpdateOperation = OakOperation<"update" | string, UpdateOperationData, Filter, Sorter>; +export declare type RemoveOperationData = {} & ({ modi?: Modi.UpdateOperation | Modi.RemoveOperation; } | { user?: User.UpdateOperation | User.RemoveOperation; } | { [k: string]: any; }); -export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; -export type Operation = CreateOperation | UpdateOperation | RemoveOperation; -export type OperIdSubQuery = Selection; -export type ModiIdSubQuery = Selection; -export type UserIdSubQuery = Selection; -export type OperEntityIdSubQuery = Selection; -export type EntityDef = { +export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; +export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation; +export declare type OperIdSubQuery = Selection; +export declare type ModiIdSubQuery = Selection; +export declare type UserIdSubQuery = Selection; +export declare type OperEntityIdSubQuery = Selection; +export declare type EntityDef = { Schema: Schema; OpSchema: OpSchema; Action: OakMakeAction | string; diff --git a/lib/base-app-domain/User/Schema.d.ts b/lib/base-app-domain/User/Schema.d.ts index 3bc5d51..29fc007 100644 --- a/lib/base-app-domain/User/Schema.d.ts +++ b/lib/base-app-domain/User/Schema.d.ts @@ -7,13 +7,13 @@ import { GenericAction, RelationAction } from "../../actions/action"; import * as Oper from "../Oper/Schema"; import * as OperEntity from "../OperEntity/Schema"; import * as ModiEntity from "../ModiEntity/Schema"; -export type OpSchema = EntityShape & { +export declare type OpSchema = EntityShape & { name?: String<16> | null; nickname?: String<64> | null; password?: Text | null; }; -export type OpAttr = keyof OpSchema; -export type Schema = EntityShape & { +export declare type OpAttr = keyof OpSchema; +export declare type Schema = EntityShape & { name?: String<16> | null; nickname?: String<64> | null; password?: Text | null; @@ -26,7 +26,7 @@ export type Schema = EntityShape & { } & { [A in ExpressionKey]?: any; }; -type AttrFilter = { +declare type AttrFilter = { id: Q_StringValue | SubQuery.UserIdSubQuery; $$createAt$$: Q_DateValue; $$seq$$: Q_StringValue; @@ -35,8 +35,8 @@ type AttrFilter = { nickname: Q_StringValue; password: Q_StringValue; }; -export type Filter = MakeFilter>; -export type Projection = { +export declare type Filter = MakeFilter>; +export declare type Projection = { "#id"?: NodeId; [k: string]: any; id?: number; @@ -65,10 +65,10 @@ export type Projection = { $entity: "modiEntity"; }; } & Partial>; -type UserIdProjection = OneOf<{ +declare type UserIdProjection = OneOf<{ id: number; }>; -export type SortAttr = { +export declare type SortAttr = { id: number; } | { $$createAt$$: number; @@ -85,34 +85,34 @@ export type SortAttr = { } | { [k: string]: any; } | OneOf>; -export type SortNode = { +export declare type SortNode = { $attr: SortAttr; $direction?: "asc" | "desc"; }; -export type Sorter = SortNode[]; -export type SelectOperation

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

= Omit, "action">; -export type Aggregation = Omit, "id">; -export type CreateOperationData = FormCreateData & { +export declare type Sorter = SortNode[]; +export declare type SelectOperation

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

= Omit, "action">; +export declare type Aggregation = Omit, "id">; +export declare type CreateOperationData = FormCreateData & { oper$operator?: OakOperation<"create", Omit[]> | Array>>; operEntity$entity?: OakOperation<"create", Omit[]> | Array>>; modiEntity$entity?: OakOperation<"create", Omit[]> | Array>>; }; -export type CreateSingleOperation = OakOperation<"create", CreateOperationData>; -export type CreateMultipleOperation = OakOperation<"create", Array>; -export type CreateOperation = CreateSingleOperation | CreateMultipleOperation; -export type UpdateOperationData = FormUpdateData & { +export declare type CreateSingleOperation = OakOperation<"create", CreateOperationData>; +export declare type CreateMultipleOperation = OakOperation<"create", Array>; +export declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation; +export declare type UpdateOperationData = FormUpdateData & { [k: string]: any; opers$operator?: OakOperation<"create", Omit[]> | Array>>; operEntitys$entity?: OakOperation<"create", Omit[]> | Array>>; modiEntitys$entity?: OakOperation<"create", Omit[]> | Array>>; }; -export type UpdateOperation = OakOperation<"update" | RelationAction | string, UpdateOperationData, Filter, Sorter>; -export type RemoveOperationData = {}; -export type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; -export type Operation = CreateOperation | UpdateOperation | RemoveOperation; -export type UserIdSubQuery = Selection; -export type EntityDef = { +export declare type UpdateOperation = OakOperation<"update" | RelationAction | string, UpdateOperationData, Filter, Sorter>; +export declare type RemoveOperationData = {}; +export declare type RemoveOperation = OakOperation<"remove", RemoveOperationData, Filter, Sorter>; +export declare type Operation = CreateOperation | UpdateOperation | RemoveOperation; +export declare type UserIdSubQuery = Selection; +export declare type EntityDef = { Schema: Schema; OpSchema: OpSchema; Action: OakMakeAction | string; diff --git a/lib/base-app-domain/_SubQuery.d.ts b/lib/base-app-domain/_SubQuery.d.ts index 44e0c13..4b68ed6 100644 --- a/lib/base-app-domain/_SubQuery.d.ts +++ b/lib/base-app-domain/_SubQuery.d.ts @@ -3,31 +3,31 @@ import * as ModiEntity from "./ModiEntity/Schema"; import * as Oper from "./Oper/Schema"; import * as OperEntity from "./OperEntity/Schema"; import * as User from "./User/Schema"; -export type ModiIdSubQuery = { +export declare type ModiIdSubQuery = { [K in "$in" | "$nin"]?: (ModiEntity.ModiIdSubQuery & { entity: "modiEntity"; }) | (Modi.ModiIdSubQuery & { entity: "modi"; }) | any; }; -export type ModiEntityIdSubQuery = { +export declare type ModiEntityIdSubQuery = { [K in "$in" | "$nin"]?: (ModiEntity.ModiEntityIdSubQuery & { entity: "modiEntity"; }) | any; }; -export type OperIdSubQuery = { +export declare type OperIdSubQuery = { [K in "$in" | "$nin"]?: (OperEntity.OperIdSubQuery & { entity: "operEntity"; }) | (Oper.OperIdSubQuery & { entity: "oper"; }) | any; }; -export type OperEntityIdSubQuery = { +export declare type OperEntityIdSubQuery = { [K in "$in" | "$nin"]?: (OperEntity.OperEntityIdSubQuery & { entity: "operEntity"; }) | any; }; -export type UserIdSubQuery = { +export declare type UserIdSubQuery = { [K in "$in" | "$nin"]?: (Oper.UserIdSubQuery & { entity: "oper"; }) | (User.UserIdSubQuery & { diff --git a/lib/store/TriggerExecutor.d.ts b/lib/store/TriggerExecutor.d.ts index 77253f7..d63a7ed 100644 --- a/lib/store/TriggerExecutor.d.ts +++ b/lib/store/TriggerExecutor.d.ts @@ -16,7 +16,7 @@ export declare class TriggerExecutor { private contextBuilder; constructor(contextBuilder: (cxtString: string) => Promise>, logger?: Logger); registerChecker>(checker: Checker): void; - getCheckers(entity: T, action: ED[T]['Action'], checkerTypes?: CheckerType[]): Trigger>[]; + getCheckers(entity: T, action: ED[T]['Action'], checkerTypes?: CheckerType[]): Trigger>[] | undefined; registerTrigger>(trigger: Trigger): void; unregisterTrigger>(trigger: Trigger): void; private preCommitTrigger; diff --git a/lib/types/Action.d.ts b/lib/types/Action.d.ts index 6bba1b7..242e274 100644 --- a/lib/types/Action.d.ts +++ b/lib/types/Action.d.ts @@ -1,18 +1,18 @@ import { CascadeRelationItem, EntityDict } from "./Entity"; import { GenericAction } from '../actions/action'; -export type Action = string; -export type State = string; -export type ActionDef = { +export declare type Action = string; +export declare type State = string; +export declare type ActionDef = { stm: { [a in A]: [p: S | S[], n: S]; }; is?: S; }; -export type ActionDictOfEntityDict = { +export declare type ActionDictOfEntityDict = { [T in keyof E]?: { [A in keyof E[T]['OpSchema']]?: ActionDef; }; }; -export type CascadeActionAuth = { +export declare type CascadeActionAuth = { [K in A | GenericAction]?: CascadeRelationItem | (CascadeRelationItem | CascadeRelationItem[])[]; }; diff --git a/lib/types/Auth.d.ts b/lib/types/Auth.d.ts index 862f12c..cee2d7b 100644 --- a/lib/types/Auth.d.ts +++ b/lib/types/Auth.d.ts @@ -2,12 +2,12 @@ import { CascadeActionAuth, CascadeRelationAuth } from "."; import { AsyncContext } from "../store/AsyncRowStore"; import { SyncContext } from "../store/SyncRowStore"; import { EntityDict, OperateOption, SelectOption } from "../types/Entity"; -export type CheckerType = 'relation' | 'row' | 'data' | 'logical' | 'logicalRelation'; +export declare type CheckerType = 'relation' | 'row' | 'data' | 'logical' | 'logicalRelation'; /** * conditionalFilter是指该action发生时,operation所操作的行中有满足conditionalFilter的行 * 被转化成trigger的filter条件,详细可看trigger中的说明 */ -export type DataChecker | SyncContext> = { +export declare type DataChecker | SyncContext> = { priority?: number; type: 'data'; entity: T; @@ -15,7 +15,7 @@ export type DataChecker void | Promise; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter'] | Promise); }; -export type RowChecker | SyncContext> = { +export declare type RowChecker | SyncContext> = { priority?: number; type: 'row'; entity: T; @@ -28,7 +28,7 @@ export type RowChecker ED[T]['Update']['filter'] | Promise); }; -export type RelationChecker | SyncContext> = { +export declare type RelationChecker | SyncContext> = { priority?: number; type: 'relation'; entity: T; @@ -38,7 +38,7 @@ export type RelationChecker ED[T]['Update']['filter'] | Promise); }; -export type LogicalChecker | SyncContext> = { +export declare type LogicalChecker | SyncContext> = { priority?: number; type: 'logical'; when?: 'after'; @@ -47,7 +47,7 @@ export type LogicalChecker void | Promise; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); }; -export type LogicalRelationChecker | SyncContext> = { +export declare type LogicalRelationChecker | SyncContext> = { priority?: number; type: 'logicalRelation'; when?: 'after'; @@ -56,11 +56,11 @@ export type LogicalRelationChecker void | Promise; conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']); }; -export type Checker | SyncContext> = DataChecker | RowChecker | RelationChecker | LogicalChecker | LogicalRelationChecker; -export type AuthDef = { +export declare type Checker | SyncContext> = DataChecker | RowChecker | RelationChecker | LogicalChecker | LogicalRelationChecker; +export declare type AuthDef = { relationAuth?: CascadeRelationAuth>; actionAuth?: CascadeActionAuth; }; -export type AuthDefDict = { +export declare type AuthDefDict = { [K in keyof ED]?: AuthDef; }; diff --git a/lib/types/DataType.d.ts b/lib/types/DataType.d.ts index 63eaa1e..1c81265 100644 --- a/lib/types/DataType.d.ts +++ b/lib/types/DataType.d.ts @@ -1,18 +1,18 @@ import { Geo, SingleGeo } from "./Geo"; -export type Int = number; -export type Uint = number; -export type Double

= number; -export type Float

= number; -export type String = string; -export type Text = string; -export type Image = string; -export type File = string; -export type Datetime = number | Date; -export type Boolean = boolean; -export type PrimaryKey = string; -export type ForeignKey = string; -export type Sequence = string; +export declare type Int = number; +export declare type Uint = number; +export declare type Double

= number; +export declare type Float

= number; +export declare type String = string; +export declare type Text = string; +export declare type Image = string; +export declare type File = string; +export declare type Datetime = number | Date; +export declare type Boolean = boolean; +export declare type PrimaryKey = string; +export declare type ForeignKey = string; +export declare type Sequence = string; export { Geo, SingleGeo } from './Geo'; -export type DataTypes = number | string | Datetime | Geo | Object | SingleGeo; +export declare type DataTypes = number | string | Datetime | Geo | Object | SingleGeo; export declare const types: string[]; export declare const unIndexedTypes: string[]; diff --git a/lib/types/Demand.d.ts b/lib/types/Demand.d.ts index 041672f..c2605fe 100644 --- a/lib/types/Demand.d.ts +++ b/lib/types/Demand.d.ts @@ -1,12 +1,12 @@ import { RefOrExpression } from "./Expression"; import { OneOf } from "./Polyfill"; export declare const EXPRESSION_PREFIX = "$expr"; -export type NodeId = `node-${number}`; -export type ExpressionKey = '$expr' | '$expr1' | '$expr2' | '$expr3' | '$expr4' | '$expr5' | '$expr6' | '$expr7' | '$expr8' | '$expr9' | '$expr10' | '$expr11' | '$expr12' | '$expr13' | '$expr14' | '$expr15' | '$expr16' | '$expr17' | '$expr18' | '$expr19' | '$expr20'; -export type ExprOp = { +export declare type NodeId = `node-${number}`; +export declare type ExpressionKey = '$expr' | '$expr1' | '$expr2' | '$expr3' | '$expr4' | '$expr5' | '$expr6' | '$expr7' | '$expr8' | '$expr9' | '$expr10' | '$expr11' | '$expr12' | '$expr13' | '$expr14' | '$expr15' | '$expr16' | '$expr17' | '$expr18' | '$expr19' | '$expr20'; +export declare type ExprOp = { [K in ExpressionKey]: RefOrExpression; }; -export type Q_NumberComparisonValue = number | OneOf<{ +export declare type Q_NumberComparisonValue = number | OneOf<{ $gt: number; $lt: number; $gte: number; @@ -17,7 +17,7 @@ export type Q_NumberComparisonValue = number | OneOf<{ $nin: number[]; $between: [number, number]; }>; -export type Q_StringComparisonValue = string | OneOf<{ +export declare type Q_StringComparisonValue = string | OneOf<{ $gt: string; $lt: string; $gte: string; @@ -30,44 +30,44 @@ export type Q_StringComparisonValue = string | OneOf<{ $in: string[]; $nin: string[]; }>; -export type Q_BooleanComparisonValue = boolean; -export type Q_DateComparisonValue = Q_NumberComparisonValue; -export type Q_EnumComparisonValue = E | OneOf<{ +export declare type Q_BooleanComparisonValue = boolean; +export declare type Q_DateComparisonValue = Q_NumberComparisonValue; +export declare type Q_EnumComparisonValue = E | OneOf<{ $in: E[]; $nin: E[]; }>; -export type Q_ExistsValue = { +export declare type Q_ExistsValue = { $exists: boolean; }; -export type Q_NumberValue = Q_NumberComparisonValue | Q_ExistsValue; -export type Q_StringValue = Q_StringComparisonValue | Q_ExistsValue; -export type Q_BooleanValue = Q_BooleanComparisonValue | Q_ExistsValue; -export type Q_DateValue = Q_DateComparisonValue | Q_ExistsValue; -export type Q_EnumValue = Q_EnumComparisonValue | Q_ExistsValue; -export type Q_State = S | { +export declare type Q_NumberValue = Q_NumberComparisonValue | Q_ExistsValue; +export declare type Q_StringValue = Q_StringComparisonValue | Q_ExistsValue; +export declare type Q_BooleanValue = Q_BooleanComparisonValue | Q_ExistsValue; +export declare type Q_DateValue = Q_DateComparisonValue | Q_ExistsValue; +export declare type Q_EnumValue = Q_EnumComparisonValue | Q_ExistsValue; +export declare type Q_State = S | { $in: S[]; } | { $nin: S[]; } | Q_ExistsValue; -export type Q_FullTextValue = { +export declare type Q_FullTextValue = { $search: string; $language?: 'zh_CN' | 'en_US'; }; -export type Q_FullTextKey = '$text'; -export type FulltextFilter = { +export declare type Q_FullTextKey = '$text'; +export declare type FulltextFilter = { [F in Q_FullTextKey]?: Q_FullTextValue; }; -type Q_LogicKey = '$and' | '$or'; -type Q_LinearLogicKey = '$not'; -export type MakeFilterWrapper = { +declare type Q_LogicKey = '$and' | '$or'; +declare type Q_LinearLogicKey = '$not'; +export declare type MakeFilterWrapper = { [Q in Q_LogicKey]?: Array>; } & { [Q in Q_LinearLogicKey]?: MakeFilterWrapper; } & Partial; -export type MakeFilter = { +export declare type MakeFilter = { '#id'?: NodeId; } & MakeFilterWrapper; -export type RefAttr = { +export declare type RefAttr = { '#attr': A; } | { '#refId': NodeId; diff --git a/lib/types/Entity.d.ts b/lib/types/Entity.d.ts index 8c000d2..84060eb 100644 --- a/lib/types/Entity.d.ts +++ b/lib/types/Entity.d.ts @@ -1,11 +1,11 @@ import { PrimaryKey, Sequence } from './DataType'; -type TriggerDataAttributeType = '$$triggerData$$'; -type TriggerTimestampAttributeType = '$$triggerTimestamp$$'; -type PrimaryKeyAttributeType = 'id'; -type CreateAtAttributeType = '$$createAt$$'; -type UpdateAtAttributeType = '$$updateAt$$'; -type DeleteAtAttributeType = '$$deleteAt$$'; -type SeqAttributeType = '$$seq$$'; +declare type TriggerDataAttributeType = '$$triggerData$$'; +declare type TriggerTimestampAttributeType = '$$triggerTimestamp$$'; +declare type PrimaryKeyAttributeType = 'id'; +declare type CreateAtAttributeType = '$$createAt$$'; +declare type UpdateAtAttributeType = '$$updateAt$$'; +declare type DeleteAtAttributeType = '$$deleteAt$$'; +declare type SeqAttributeType = '$$seq$$'; export declare const TriggerDataAttribute = "$$triggerData$$"; export declare const TriggerTimestampAttribute = "$$triggerTimestamp$$"; export declare const PrimaryKeyAttribute = "id"; @@ -13,14 +13,14 @@ export declare const CreateAtAttribute = "$$createAt$$"; export declare const UpdateAtAttribute = "$$updateAt$$"; export declare const DeleteAtAttribute = "$$deleteAt$$"; export declare const SeqAttribute = "$$seq$$"; -export type InstinctiveAttributes = PrimaryKeyAttributeType | CreateAtAttributeType | UpdateAtAttributeType | DeleteAtAttributeType | TriggerDataAttributeType | TriggerTimestampAttributeType | SeqAttributeType; +export declare type InstinctiveAttributes = PrimaryKeyAttributeType | CreateAtAttributeType | UpdateAtAttributeType | DeleteAtAttributeType | TriggerDataAttributeType | TriggerTimestampAttributeType | SeqAttributeType; export declare const initinctiveAttributes: string[]; -type FilterPart = { +declare type FilterPart = { filter?: A extends 'create' ? undefined : F; indexFrom?: A extends 'create' ? undefined : number; count?: A extends 'create' ? undefined : number; }; -export type SelectOption = { +export declare type SelectOption = { dontCollect?: boolean; blockTrigger?: true; obscure?: boolean; @@ -28,7 +28,7 @@ export type SelectOption = { includedDeleted?: true; dummy?: 1; }; -export type OperateOption = { +export declare type OperateOption = { blockTrigger?: true; dontCollect?: boolean; dontCreateOper?: boolean; @@ -38,13 +38,13 @@ export type OperateOption = { modiParentEntity?: string; dummy?: 1; }; -export type FormUpdateData = Partial<{ +export declare type FormUpdateData = Partial<{ [K in keyof Omit]: SH[K] | null; }>; -export type FormCreateData = Omit & { +export declare type FormCreateData = Partial> & { id: string; }; -export type Operation = { +export declare type Operation = { id?: string; action: A; data: D; @@ -60,7 +60,7 @@ export interface EntityShape { interface GeneralEntityShape extends EntityShape { [K: string]: any; } -export type MakeAction = A; +export declare type MakeAction = A; export interface EntityDef { Schema: GeneralEntityShape; OpSchema: GeneralEntityShape; @@ -82,79 +82,79 @@ export interface EntityDict { export interface OtmSubProjection extends Omit, 'action'> { $entity: string; } -export type AggregationOp = `#max-${number}` | `#min-${number}` | `#avg-${number}` | `#count-${number}` | `#sum-${number}`; -export type DeduceAggregationData

= { +export declare type AggregationOp = `#max-${number}` | `#min-${number}` | `#avg-${number}` | `#count-${number}` | `#sum-${number}`; +export declare type DeduceAggregationData

= { [A in AggregationOp]?: P; } & { '#aggr'?: P; }; -export type AggregationResult = Array<{ +export declare type AggregationResult = Array<{ [A in AggregationOp]?: number | string; } & { '#data'?: Partial; }>; -export type AttrFilter = { +export declare type AttrFilter = { [K in keyof SH]?: any; }; -type SortAttr = { +declare type SortAttr = { [K: string]: any; }; -type SorterItem = { +declare type SorterItem = { $attr: SortAttr; $direction?: "asc" | "desc"; }; -type Sorter = Array; -type Filter = { +declare type Sorter = Array; +declare type Filter = { [K: string]: any; }; -type Projection = { +declare type Projection = { [K: string]: any; }; -export type DeduceAggregation

= Omit, F, S>, 'action'>; -type CreateOperationData = { +export declare type DeduceAggregation

= Omit, F, S>, 'action'>; +declare type CreateOperationData = { id: string; [K: string]: any; }; -type CreateSingleOperation = Operation<'create', CreateOperationData, undefined, undefined>; -type CreateMultipleOperation = Operation<'create', Array, undefined, undefined>; -type CreateOperation = CreateSingleOperation | CreateMultipleOperation; -type UpdateOperationData = { +declare type CreateSingleOperation = Operation<'create', CreateOperationData, undefined, undefined>; +declare type CreateMultipleOperation = Operation<'create', Array, undefined, undefined>; +declare type CreateOperation = CreateSingleOperation | CreateMultipleOperation; +declare type UpdateOperationData = { id?: never; [k: string]: any; }; -export type UpdateOperation = Operation; -type RemoveOperationData = { +export declare type UpdateOperation = Operation; +declare type RemoveOperationData = { [k: string]: any; }; -export type RemoveOperation = Operation<'remove', RemoveOperationData, Filter, Sorter>; -export type CUDOperation = CreateOperation | UpdateOperation | RemoveOperation; -export type CreateOpResult = { +export declare type RemoveOperation = Operation<'remove', RemoveOperationData, Filter, Sorter>; +export declare type CUDOperation = CreateOperation | UpdateOperation | RemoveOperation; +export declare type CreateOpResult = { a: 'c'; e: T; d: ED[T]['OpSchema'] | ED[T]['OpSchema'][]; }; -export type UpdateOpResult = { +export declare type UpdateOpResult = { a: 'u'; e: T; d: UpdateOperationData; f?: Filter; }; -export type RemoveOpResult = { +export declare type RemoveOpResult = { a: 'r'; e: T; f?: Filter; }; -export type RelationHierarchy = { +export declare type RelationHierarchy = { [K in R]?: R[]; }; -export type CascadeRelationItem = { +export declare type CascadeRelationItem = { cascadePath: string; relations?: string[]; }; -export type CascadeRelationAuth = { +export declare type CascadeRelationAuth = { [K in R]?: CascadeRelationItem | (CascadeRelationItem | CascadeRelationItem[])[]; }; -export type SelectOpResult = { +export declare type SelectOpResult = { a: 's'; d: { [T in keyof ED]?: { @@ -162,14 +162,14 @@ export type SelectOpResult = { }; }; }; -export type OpRecord = CreateOpResult | UpdateOpResult | RemoveOpResult | SelectOpResult; -export type OperationResult = { +export declare type OpRecord = CreateOpResult | UpdateOpResult | RemoveOpResult | SelectOpResult; +export declare type OperationResult = { [K in keyof ED]?: { [A in ED[K]['Action']]?: number; }; }; -export type ActionType = 'readOnly' | 'appendOnly' | 'excludeUpdate' | 'excludeRemove' | 'crud'; -export type Configuration = { +export declare type ActionType = 'readOnly' | 'appendOnly' | 'excludeUpdate' | 'excludeRemove' | 'crud'; +export declare type Configuration = { actionType?: ActionType; static?: boolean; }; diff --git a/lib/types/Expression.d.ts b/lib/types/Expression.d.ts index a379eb8..cdeb126 100644 --- a/lib/types/Expression.d.ts +++ b/lib/types/Expression.d.ts @@ -1,8 +1,8 @@ import { RefAttr } from "./Demand"; import { Geo } from "./Geo"; -export type RefOrExpression = RefAttr | Expression; -type MathType = RefOrExpression | number; -type StringType = RefOrExpression | string; +export declare type RefOrExpression = RefAttr | Expression; +declare type MathType = RefOrExpression | number; +declare type StringType = RefOrExpression | string; interface Add { $add: (MathType)[]; } @@ -30,8 +30,8 @@ interface Ceil { interface Pow { $pow: [MathType, MathType]; } -type MathExpression = Add | Subtract | Multiply | Divide | Abs | Round | Floor | Ceil | Pow; -type CmpType = RefOrExpression | string | number; +declare type MathExpression = Add | Subtract | Multiply | Divide | Abs | Round | Floor | Ceil | Pow; +declare type CmpType = RefOrExpression | string | number; interface Gt { $gt: [CmpType, CmpType]; } @@ -59,14 +59,14 @@ interface EndsWith { interface Includes { $includes: [RefOrExpression | string, RefOrExpression | string]; } -type CompareExpression = Lt | Gt | Lte | Gte | Eq | Ne | StartsWith | EndsWith | Includes; +declare type CompareExpression = Lt | Gt | Lte | Gte | Eq | Ne | StartsWith | EndsWith | Includes; interface BoolTrue { $true: Expression; } interface BoolFalse { $false: Expression; } -type BoolExpression = BoolTrue | BoolFalse; +declare type BoolExpression = BoolTrue | BoolFalse; interface LogicAnd { $and: Expression[]; } @@ -76,7 +76,7 @@ interface LogicOr { interface LogicNot { $not: Expression; } -type LogicExpression = LogicAnd | LogicOr | LogicNot; +declare type LogicExpression = LogicAnd | LogicOr | LogicNot; interface DateYear { $year: RefOrExpression | Date | number; } @@ -110,18 +110,18 @@ interface DateCeiling { interface DateFloor { $dateFloor: [RefOrExpression | Date | number, 'y' | 'M' | 'd' | 'h' | 'm' | 's']; } -type DateExpression = DateYear | DateMonth | DateWeekday | DateWeekOfYear | DateDay | DateDayOfYear | DateDayOfMonth | DateDayOfWeek | DateDiff | DateCeiling | DateFloor; +declare type DateExpression = DateYear | DateMonth | DateWeekday | DateWeekOfYear | DateDay | DateDayOfYear | DateDayOfMonth | DateDayOfWeek | DateDiff | DateCeiling | DateFloor; interface StringConcat { $concat: StringType[]; } -type StringExpression = StringConcat; +declare type StringExpression = StringConcat; interface GeoContains { $contains: [RefOrExpression | Geo, RefOrExpression | Geo]; } interface GeoDistance { $distance: [RefOrExpression | Geo, RefOrExpression | Geo]; } -type GeoExpression = GeoContains | GeoDistance; +declare type GeoExpression = GeoContains | GeoDistance; interface AggrCountExpression { $$count: RefOrExpression; } @@ -137,9 +137,9 @@ interface AggrMinExpression { interface AggrAvgExpression { $$avg: RefOrExpression; } -export type AggrExpression = AggrAvgExpression | AggrCountExpression | AggrSumExpression | AggrMaxExpression | AggrMinExpression; -export type Expression = GeoExpression | DateExpression | LogicExpression | BoolExpression | CompareExpression | MathExpression | StringExpression | AggrExpression; -export type ExpressionConstant = Geo | number | Date | string | boolean; +export declare type AggrExpression = AggrAvgExpression | AggrCountExpression | AggrSumExpression | AggrMaxExpression | AggrMinExpression; +export declare type Expression = GeoExpression | DateExpression | LogicExpression | BoolExpression | CompareExpression | MathExpression | StringExpression | AggrExpression; +export declare type ExpressionConstant = Geo | number | Date | string | boolean; export declare function isGeoExpression(expression: any): expression is GeoExpression; export declare function isDateExpression(expression: any): expression is DateExpression; export declare function isLogicExpression(expression: any): expression is LogicExpression; diff --git a/lib/types/Geo.d.ts b/lib/types/Geo.d.ts index f1ce57e..1747c3f 100644 --- a/lib/types/Geo.d.ts +++ b/lib/types/Geo.d.ts @@ -1,8 +1,8 @@ -export type Point = [number, number]; -export type Path = Array; -export type Polygon = Array; -export type Circle = [Point, number]; -export type SingleGeo = { +export declare type Point = [number, number]; +export declare type Path = Array; +export declare type Polygon = Array; +export declare type Circle = [Point, number]; +export declare type SingleGeo = { type: 'point'; coordinate: Point; } | { @@ -15,4 +15,4 @@ export type SingleGeo = { type: 'circle'; coordinate: Circle; }; -export type Geo = SingleGeo | SingleGeo[]; +export declare type Geo = SingleGeo | SingleGeo[]; diff --git a/lib/types/Locale.d.ts b/lib/types/Locale.d.ts index 190a966..108740e 100644 --- a/lib/types/Locale.d.ts +++ b/lib/types/Locale.d.ts @@ -1,17 +1,17 @@ import { EntityShape } from "./Entity"; -type Language = 'zh_CN' | 'en_US'; -type LocaleOfSchema> = { +declare type Language = 'zh_CN' | 'en_US'; +declare type LocaleOfSchema> = { [A in keyof Required>]: string; }; -type LocaleOfStringEnum = { +declare type LocaleOfStringEnum = { [K in A]: string; }; -type LocaleOfValue> = { +declare type LocaleOfValue> = { [K in keyof V]: { [K2 in V[K]]: string; }; }; -export type LocaleDef, Ac extends string, R extends string, V extends Record> = { +export declare type LocaleDef, Ac extends string, R extends string, V extends Record> = { [L in Language]?: { attr: LocaleOfSchema & { [A in keyof V]: string; diff --git a/lib/types/Polyfill.d.ts b/lib/types/Polyfill.d.ts index f096aaa..7a2dfd8 100644 --- a/lib/types/Polyfill.d.ts +++ b/lib/types/Polyfill.d.ts @@ -1,23 +1,23 @@ -export type OmitInferKey = { +export declare type OmitInferKey = { [K in keyof T as T extends R ? never : K]: T[K]; }; -export type OmitInferValue = { +export declare type OmitInferValue = { [K in keyof T as T extends R ? never : K]: T[K]; }; -export type ValueOf = Obj[keyof Obj]; -export type OneOnly = { +export declare type ValueOf = Obj[keyof Obj]; +export declare type OneOnly = { [key in Exclude]?: undefined; } & Pick; -export type OneOfByKey = { +export declare type OneOfByKey = { [key in keyof Obj]: OneOnly; }; -export type OneOf = ValueOf>; -type IsOptional = { +export declare type OneOf = ValueOf>; +declare type IsOptional = { [K1 in Exclude]: T[K1]; } & { K?: T[K]; } extends T ? K : never; -export type OptionalKeys = { +export declare type OptionalKeys = { [K in keyof T]: IsOptional; }[keyof T]; export {}; diff --git a/lib/types/Port.d.ts b/lib/types/Port.d.ts index 3477304..8e0519a 100644 --- a/lib/types/Port.d.ts +++ b/lib/types/Port.d.ts @@ -1,6 +1,6 @@ import { AsyncContext } from "../store/AsyncRowStore"; import { EntityDict } from "./Entity"; -export type Exportation = { +export declare type Exportation = { name: string; id: string; entity: T; @@ -8,7 +8,7 @@ export type Exportation Partial>; }; -export type Importation = { +export declare type Importation = { name: string; id: string; entity: T; diff --git a/lib/types/RowStore.d.ts b/lib/types/RowStore.d.ts index be4bec2..8c632f0 100644 --- a/lib/types/RowStore.d.ts +++ b/lib/types/RowStore.d.ts @@ -1,6 +1,6 @@ import { OperationResult, EntityDict } from './Entity'; import { StorageSchema } from './Storage'; -export type TxnOption = { +export declare type TxnOption = { isolationLevel: 'repeatable read' | 'serializable'; }; export declare abstract class RowStore { diff --git a/lib/types/Storage.d.ts b/lib/types/Storage.d.ts index 99357b4..341fabc 100644 --- a/lib/types/Storage.d.ts +++ b/lib/types/Storage.d.ts @@ -1,7 +1,7 @@ import { ActionType } from '.'; import { EntityDict, EntityShape, InstinctiveAttributes } from './Entity'; import { DataType, DataTypeParams } from './schema/DataTypes'; -export type Ref = 'ref'; +export declare type Ref = 'ref'; export interface Column { name: keyof SH | `${string}State`; size?: number; @@ -27,12 +27,12 @@ export interface Attribute { unique?: boolean; sequenceStart?: number; } -export type Attributes = Omit<{ +export declare type Attributes = Omit<{ [attrName in keyof SH]: Attribute; }, InstinctiveAttributes>; export interface EntityConfig { } -export type UniqConstraint = { +export declare type UniqConstraint = { attributes: Array; type?: string; }; @@ -51,6 +51,6 @@ export interface StorageDesc { relation?: string[]; view?: true; } -export type StorageSchema = { +export declare type StorageSchema = { [K in keyof ED]: StorageDesc; }; diff --git a/lib/types/Timer.d.ts b/lib/types/Timer.d.ts index ede68e0..c3d869a 100644 --- a/lib/types/Timer.d.ts +++ b/lib/types/Timer.d.ts @@ -1,11 +1,11 @@ import { EntityDict } from './Entity'; import { AsyncContext } from "../store/AsyncRowStore"; -type RoutineFn> = (context: Cxt) => Promise; -export type Routine> = { +declare type RoutineFn> = (context: Cxt) => Promise; +export declare type Routine> = { name: string; fn: RoutineFn; }; -export type Timer> = { +export declare type Timer> = { name: string; cron: string; fn: RoutineFn; diff --git a/lib/types/Trigger.d.ts b/lib/types/Trigger.d.ts index 4a0f0e6..0015048 100644 --- a/lib/types/Trigger.d.ts +++ b/lib/types/Trigger.d.ts @@ -24,7 +24,7 @@ export interface CreateTriggerCrossTxn | SyncContext> = CreateTriggerInTxn | CreateTriggerCrossTxn; +export declare type CreateTrigger | SyncContext> = CreateTriggerInTxn | CreateTriggerCrossTxn; /** * update trigger如果带有filter,说明只对存在限定条件的行起作用。此时系统在进行相应动作时, * 会判定当前动作的filter条件和trigger所定义的filter是否有交集(即有同时满足两个条件的行) @@ -46,7 +46,7 @@ export interface UpdateTriggerCrossTxn | SyncContext> = UpdateTriggerInTxn | UpdateTriggerCrossTxn; +export declare type UpdateTrigger | SyncContext> = UpdateTriggerInTxn | UpdateTriggerCrossTxn; /** * 同update trigger一样,remove trigger如果带有filter,说明只对存在限定条件的行起作用。此时系统在进行相应动作时, * 会判定当前动作的filter条件和trigger所定义的filter是否有交集(即有同时满足两个条件的行) @@ -67,7 +67,7 @@ export interface RemoveTriggerCrossTxn | SyncContext> = RemoveTriggerInTxn | RemoveTriggerCrossTxn; +export declare type RemoveTrigger | SyncContext> = RemoveTriggerInTxn | RemoveTriggerCrossTxn; export interface SelectTriggerBase extends TriggerBase { action: 'select'; } @@ -88,8 +88,8 @@ export interface SelectTriggerAfter[]; }, context: Cxt, params?: SelectOption) => Promise | number; } -export type SelectTrigger | SyncContext> = SelectTriggerBefore | SelectTriggerAfter; -export type Trigger | SyncContext> = CreateTrigger | UpdateTrigger | RemoveTrigger | SelectTrigger; +export declare type SelectTrigger | SyncContext> = SelectTriggerBefore | SelectTriggerAfter; +export declare type Trigger | SyncContext> = CreateTrigger | UpdateTrigger | RemoveTrigger | SelectTrigger; export interface TriggerEntityShape extends EntityShape { $$triggerData$$?: { name: string; diff --git a/lib/types/Watcher.d.ts b/lib/types/Watcher.d.ts index 0fe8135..fccbd9c 100644 --- a/lib/types/Watcher.d.ts +++ b/lib/types/Watcher.d.ts @@ -1,6 +1,6 @@ import { AsyncContext } from "../store/AsyncRowStore"; import { EntityDict, OperationResult } from "./Entity"; -type ActionData = ED[T]['Update']['data'] | ED[T]['Remove']['data']; +declare type ActionData = ED[T]['Update']['data'] | ED[T]['Remove']['data']; export interface BBWatcher { name: string; entity: T; @@ -15,5 +15,5 @@ export interface WBWatcher Promise); fn: (context: Cxt, data: Partial[]) => Promise>; } -export type Watcher> = BBWatcher | WBWatcher; +export declare type Watcher> = BBWatcher | WBWatcher; export {}; diff --git a/lib/types/schema/DataTypes.d.ts b/lib/types/schema/DataTypes.d.ts index fbc2e69..e3c9fba 100644 --- a/lib/types/schema/DataTypes.d.ts +++ b/lib/types/schema/DataTypes.d.ts @@ -1,28 +1,28 @@ /** * Column types used for @PrimaryGeneratedColumn() decorator. */ -export type PrimaryGeneratedColumnType = "int" | "int2" | "int4" | "int8" | "integer" | "tinyint" | "smallint" | "mediumint" | "bigint" | "dec" | "decimal" | "smalldecimal" | "fixed" | "numeric" | "number"; +export declare type PrimaryGeneratedColumnType = "int" | "int2" | "int4" | "int8" | "integer" | "tinyint" | "smallint" | "mediumint" | "bigint" | "dec" | "decimal" | "smalldecimal" | "fixed" | "numeric" | "number"; /** * Column types where spatial properties are used. */ -export type SpatialColumnType = "geometry" | "geography" | "st_geometry" | "st_point"; +export declare type SpatialColumnType = "geometry" | "geography" | "st_geometry" | "st_point"; /** * Column types where precision and scale properties are used. */ -export type WithPrecisionColumnType = "float" | "double" | "dec" | "decimal" | "smalldecimal" | "fixed" | "numeric" | "real" | "double precision" | "number" | "datetime" | "datetime2" | "datetimeoffset" | "time" | "time with time zone" | "time without time zone" | "timestamp" | "timestamp without time zone" | "timestamp with time zone" | "timestamp with local time zone"; +export declare type WithPrecisionColumnType = "float" | "double" | "dec" | "decimal" | "smalldecimal" | "fixed" | "numeric" | "real" | "double precision" | "number" | "datetime" | "datetime2" | "datetimeoffset" | "time" | "time with time zone" | "time without time zone" | "timestamp" | "timestamp without time zone" | "timestamp with time zone" | "timestamp with local time zone"; /** * Column types where column length is used. */ -export type WithLengthColumnType = "character varying" | "varying character" | "char varying" | "nvarchar" | "national varchar" | "character" | "native character" | "varchar" | "char" | "nchar" | "national char" | "varchar2" | "nvarchar2" | "alphanum" | "shorttext" | "raw" | "binary" | "varbinary" | "string"; -export type WithWidthColumnType = "tinyint" | "smallint" | "mediumint" | "int" | "bigint"; +export declare type WithLengthColumnType = "character varying" | "varying character" | "char varying" | "nvarchar" | "national varchar" | "character" | "native character" | "varchar" | "char" | "nchar" | "national char" | "varchar2" | "nvarchar2" | "alphanum" | "shorttext" | "raw" | "binary" | "varbinary" | "string"; +export declare type WithWidthColumnType = "tinyint" | "smallint" | "mediumint" | "int" | "bigint"; /** * All other regular column types. */ -export type SimpleColumnType = "simple-array" | "simple-json" | "simple-enum" | "int2" | "integer" | "int4" | "int8" | "int64" | "unsigned big int" | "float" | "float4" | "float8" | "smallmoney" | "money" | "boolean" | "bool" | "tinyblob" | "tinytext" | "mediumblob" | "mediumtext" | "blob" | "text" | "ntext" | "citext" | "hstore" | "longblob" | "longtext" | "alphanum" | "shorttext" | "bytes" | "bytea" | "long" | "raw" | "long raw" | "bfile" | "clob" | "nclob" | "image" | "timetz" | "timestamptz" | "timestamp with local time zone" | "smalldatetime" | "date" | "interval year to month" | "interval day to second" | "interval" | "year" | "seconddate" | "point" | "line" | "lseg" | "box" | "circle" | "path" | "polygon" | "geography" | "geometry" | "linestring" | "multipoint" | "multilinestring" | "multipolygon" | "geometrycollection" | "st_geometry" | "st_point" | "int4range" | "int8range" | "numrange" | "tsrange" | "tstzrange" | "daterange" | "enum" | "set" | "cidr" | "inet" | "macaddr" | "bit" | "bit varying" | "varbit" | "tsvector" | "tsquery" | "uuid" | "xml" | "json" | "jsonb" | "varbinary" | "hierarchyid" | "sql_variant" | "rowid" | "urowid" | "uniqueidentifier" | "rowversion" | "array" | "cube" | "ltree" | "object" | "array" | "function" | "sequence"; +export declare type SimpleColumnType = "simple-array" | "simple-json" | "simple-enum" | "int2" | "integer" | "int4" | "int8" | "int64" | "unsigned big int" | "float" | "float4" | "float8" | "smallmoney" | "money" | "boolean" | "bool" | "tinyblob" | "tinytext" | "mediumblob" | "mediumtext" | "blob" | "text" | "ntext" | "citext" | "hstore" | "longblob" | "longtext" | "alphanum" | "shorttext" | "bytes" | "bytea" | "long" | "raw" | "long raw" | "bfile" | "clob" | "nclob" | "image" | "timetz" | "timestamptz" | "timestamp with local time zone" | "smalldatetime" | "date" | "interval year to month" | "interval day to second" | "interval" | "year" | "seconddate" | "point" | "line" | "lseg" | "box" | "circle" | "path" | "polygon" | "geography" | "geometry" | "linestring" | "multipoint" | "multilinestring" | "multipolygon" | "geometrycollection" | "st_geometry" | "st_point" | "int4range" | "int8range" | "numrange" | "tsrange" | "tstzrange" | "daterange" | "enum" | "set" | "cidr" | "inet" | "macaddr" | "bit" | "bit varying" | "varbit" | "tsvector" | "tsquery" | "uuid" | "xml" | "json" | "jsonb" | "varbinary" | "hierarchyid" | "sql_variant" | "rowid" | "urowid" | "uniqueidentifier" | "rowversion" | "array" | "cube" | "ltree" | "object" | "array" | "function" | "sequence"; /** * Any column type column can be. */ -export type DataType = WithPrecisionColumnType | WithLengthColumnType | WithWidthColumnType | SpatialColumnType | SimpleColumnType; +export declare type DataType = WithPrecisionColumnType | WithLengthColumnType | WithWidthColumnType | SpatialColumnType | SimpleColumnType; export interface DataTypeParams { length?: number; width?: number; diff --git a/lib/utils/concurrent.d.ts b/lib/utils/concurrent.d.ts index 57d929b..c44feca 100644 --- a/lib/utils/concurrent.d.ts +++ b/lib/utils/concurrent.d.ts @@ -1,4 +1,4 @@ -type Mode = 'S' | 'X'; +declare type Mode = 'S' | 'X'; /** * 模拟一个读写锁,用于同步。 * 注意,千万不要发生自己等自己 diff --git a/lib/utils/uuid.d.ts b/lib/utils/uuid.d.ts index 595afb7..1d7ed56 100644 --- a/lib/utils/uuid.d.ts +++ b/lib/utils/uuid.d.ts @@ -3,7 +3,7 @@ export declare function sequentialUuid({ random }: { }): string; export declare function shrinkUuidTo32Bytes(uuid: string): string; export declare function expandUuidTo36Bytes(uuidShrinked: string): string; -export type GenerateIdOption = { +export declare type GenerateIdOption = { shuffle?: boolean; }; export declare function generateNewIdAsync(option?: GenerateIdOption): Promise; diff --git a/lib/utils/validator.d.ts b/lib/utils/validator.d.ts index bfa8afd..318c121 100644 --- a/lib/utils/validator.d.ts +++ b/lib/utils/validator.d.ts @@ -1,5 +1,5 @@ -type ValidatorFunction = (text: string, size?: number) => string | boolean; -type ValidatorMoneyFunction = (text: string, zero?: boolean) => string | boolean; +declare type ValidatorFunction = (text: string, size?: number) => string | boolean; +declare type ValidatorMoneyFunction = (text: string, zero?: boolean) => string | boolean; export declare const isMobile: ValidatorFunction; export declare const isPassword: ValidatorFunction; export declare const isCaptcha: ValidatorFunction; diff --git a/src/types/Entity.ts b/src/types/Entity.ts index f7f4371..a0eb88a 100644 --- a/src/types/Entity.ts +++ b/src/types/Entity.ts @@ -49,7 +49,7 @@ export type FormUpdateData = Partial<{ [K in keyof Omit]: SH[K] | null; }>; -export type FormCreateData = Omit & { id: string }; +export type FormCreateData = Partial> & { id: string }; export type Operation Date: Thu, 19 Jan 2023 22:48:33 +0800 Subject: [PATCH 18/19] =?UTF-8?q?endpoint=E5=AE=9A=E4=B9=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/store/relation.js | 2 +- lib/types/Endpoint.d.ts | 4 ++-- src/store/relation.ts | 2 +- src/types/Endpoint.ts | 5 +++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/store/relation.js b/lib/store/relation.js index bb01df9..9338ae4 100644 --- a/lib/store/relation.js +++ b/lib/store/relation.js @@ -59,7 +59,7 @@ function judgeRelation(schema, entity, attr) { return 2; } else { - (0, assert_1.default)(Entity_1.initinctiveAttributes.includes(attr), "".concat(attr, "\u5C5E\u6027\u627E\u4E0D\u5230")); + (0, assert_1.default)(Entity_1.initinctiveAttributes.includes(attr), "".concat(entity, "\u5BF9\u8C61\u4E2D\u7684").concat(attr, "\u5C5E\u6027\u627E\u4E0D\u5230")); return 1; } } diff --git a/lib/types/Endpoint.d.ts b/lib/types/Endpoint.d.ts index 024ec71..df3f727 100644 --- a/lib/types/Endpoint.d.ts +++ b/lib/types/Endpoint.d.ts @@ -1,10 +1,10 @@ /// -import { ClientRequest, IncomingHttpHeaders } from "http"; +import { IncomingHttpHeaders, IncomingMessage } from "http"; import { AsyncContext } from "../store/AsyncRowStore"; import { EntityDict } from "./Entity"; export interface Endpoint> { name: string; params?: string[]; method: 'get' | 'post' | 'put' | 'delete'; - fn: (context: BackCxt, params: Record, body: any, headers: IncomingHttpHeaders, req: ClientRequest) => Promise; + fn: (context: BackCxt, params: Record, headers: IncomingHttpHeaders, req: IncomingMessage, body?: any) => Promise; } diff --git a/src/store/relation.ts b/src/store/relation.ts index 79cc5a0..7a65389 100644 --- a/src/store/relation.ts +++ b/src/store/relation.ts @@ -63,7 +63,7 @@ export function judgeRelation, body: any, headers: IncomingHttpHeaders, req: ClientRequest) => Promise; + fn: (context: BackCxt, params: Record, headers: IncomingHttpHeaders, + req: IncomingMessage, body?: any) => Promise; }; From 5c6da1dc6c03e5544fc4f5e5cb0ac1a77114666b Mon Sep 17 00:00:00 2001 From: Xc Date: Fri, 20 Jan 2023 19:43:14 +0800 Subject: [PATCH 19/19] 2.4.0-publish --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a10d872..21e882f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oak-domain", - "version": "2.3.3", + "version": "2.4.0", "author": { "name": "XuChang" },