简化了checker定义

This commit is contained in:
Xu Chang 2023-01-18 10:58:43 +08:00
parent c1eae2142f
commit a49e37a5fe
8 changed files with 120 additions and 218 deletions

View File

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

View File

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

19
lib/types/Auth.d.ts vendored
View File

@ -33,7 +33,8 @@ export declare type RelationChecker<ED extends EntityDict, T extends keyof ED, C
priority?: number;
type: 'relation';
entity: T;
action: Omit<ED[T]['Action'], 'create'> | Array<Omit<ED[T]['Action'], 'create'>>;
when?: 'after';
action: ED[T]['Action'] | Array<ED[T]['Action']>;
relationFilter: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ED[T]['Selection']['filter'] | Promise<ED[T]['Selection']['filter']>;
errMsg: string;
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter'] | Promise<ED[T]['Selection']['filter']>);
@ -44,27 +45,25 @@ export declare type ExpressionTask<ED extends EntityDict, T extends keyof ED> =
filter: ED[T]['Selection']['filter'];
};
export declare type ExpressionTaskCombination<ED extends EntityDict> = ExpressionTask<ED, keyof ED>;
export declare type ExpressionChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
export declare type LogicalChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
priority?: number;
type: 'expression';
type: 'logical';
when?: 'after';
entity: T;
action: ED[T]['Action'] | Array<ED[T]['Action']>;
expression: <T2 extends keyof ED>(operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ExpressionTaskCombination<ED> | undefined | string | Promise<ExpressionTaskCombination<ED> | string | undefined>;
errMsg: string;
checker: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => void | Promise<void>;
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
};
export declare type ExpressionRelationChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
export declare type LogicalRelationChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
priority?: number;
type: 'expressionRelation';
type: 'logicalRelation';
when?: 'after';
entity: T;
action: ED[T]['Action'] | Array<ED[T]['Action']>;
expression: <T2 extends keyof ED>(operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ExpressionTaskCombination<ED> | undefined | string | Promise<ExpressionTaskCombination<ED> | string | undefined>;
errMsg: string;
checker: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => void | Promise<void>;
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
};
export declare type Checker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = DataChecker<ED, T, Cxt> | RowChecker<ED, T, Cxt> | RelationChecker<ED, T, Cxt> | ExpressionChecker<ED, T, Cxt> | ExpressionRelationChecker<ED, T, Cxt>;
export declare type Checker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = DataChecker<ED, T, Cxt> | RowChecker<ED, T, Cxt> | RelationChecker<ED, T, Cxt> | LogicalChecker<ED, T, Cxt> | LogicalRelationChecker<ED, T, Cxt>;
export declare type AuthDef<ED extends EntityDict, T extends keyof ED> = {
relationAuth?: CascadeRelationAuth<NonNullable<ED[T]['Relation']>>;
actionAuth?: CascadeActionAuth<ED[T]['Action']>;

View File

@ -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"),

View File

@ -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<ED extends EntityDict & BaseEntityDict> {
entity,
action: action as 'update',
fn,
when: (checker as ExpressionChecker<ED, T, Cxt>).when || 'before',
when: (checker as LogicalChecker<ED, T, Cxt>).when || 'before',
filter: conditionalFilter,
} as UpdateTrigger<ED, T, Cxt>;
this.registerTrigger(trigger);

View File

@ -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<ED, keyof ED, Cxt>['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<ED, keyof ED, Cxt>['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<ED extends EntityDict & BaseEntityDict, Cxt e
checkers.push({
entity: userEntityName as keyof ED,
action: 'create',
type: 'expressionRelation',
expression: (operation, context) => {
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<ED extends EntityDict & BaseEntityDict, Cxt e
return;
}
const filter = raFilterMakerDict[relation]!(userId!);
return {
entity,
filter: combineFilters([filter, { id: entityId }]),
expr: {
$gt: [{
'#attr': '$$createAt$$',
}, 0]
},
}
return filter;
},
errMsg: '越权操作',
});
@ -465,7 +406,7 @@ export function createAuthCheckers<ED extends EntityDict & BaseEntityDict, Cxt e
* create动作所增加的auth约束只可能在外键的对象上
*/
const { } = actionAuth[a as ED[keyof ED]['Action']]!;
checkers.push({
/* checkers.push({
entity,
action: a,
type: 'expressionRelation',
@ -492,7 +433,7 @@ export function createAuthCheckers<ED extends EntityDict & BaseEntityDict, Cxt e
return makeExprInner(data);
},
errMsg: '定义的actionAuth中检查出来越权操作',
});
}); */
}
else {
checkers.push({

View File

@ -1,6 +1,6 @@
import { EntityDict as BaseEntityDict } from '../base-app-domain';
import { OpSchema as Modi, Filter } from '../base-app-domain/Modi/Schema';
import { Checker, Operation, StorageSchema, RowChecker, EntityDict, OakRowLockedException, Context, OperateOption, Trigger, RemoveTrigger, RelationChecker, ExpressionChecker, ExpressionRelationChecker, OakUserUnpermittedException } from '../types';
import { Checker, Operation, StorageSchema, RowChecker, EntityDict, OakRowLockedException, Context, OperateOption, Trigger, RemoveTrigger, RelationChecker, LogicalChecker, LogicalRelationChecker, OakUserUnpermittedException } from '../types';
import { appendOnlyActions } from '../actions/action';
import { difference } from '../utils/lodash';
import { AsyncContext } from './AsyncRowStore';

View File

@ -43,7 +43,8 @@ export type RelationChecker<ED extends EntityDict, T extends keyof ED, Cxt exten
priority?: number;
type: 'relation';
entity: T;
action: Omit<ED[T]['Action'], 'create'> | Array<Omit<ED[T]['Action'], 'create'>>;
when?: 'after';
action: ED[T]['Action'] | Array<ED[T]['Action']>;
relationFilter: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ED[T]['Selection']['filter'] | Promise<ED[T]['Selection']['filter']>; // 生成一个额外的relation相关的filter加在原先的filter上
errMsg: string;
conditionalFilter?: ED[T]['Update']['filter'] | (
@ -59,39 +60,37 @@ export type ExpressionTask<ED extends EntityDict, T extends keyof ED> = {
export type ExpressionTaskCombination<ED extends EntityDict> = ExpressionTask<ED, keyof ED>;
export type ExpressionChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
export type LogicalChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
priority?: number;
type: 'expression';
type: 'logical';
when?: 'after';
entity: T;
action: ED[T]['Action'] | Array<ED[T]['Action']>;
expression: <T2 extends keyof ED>(
checker: (
operation: ED[T]['Operation'] | ED[T]['Selection'],
context: Cxt,
option: OperateOption | SelectOption
) => ExpressionTaskCombination<ED> | undefined | string | Promise<ExpressionTaskCombination<ED> | string | undefined> ; // 生成一个带表达式的查询任务数组表达式结果为true代表可以过or关系。如果返回undefined直接过返回string直接挂
errMsg: string;
) => void | Promise<void>;
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
};
export type ExpressionRelationChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
export type LogicalRelationChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
priority?: number;
type: 'expressionRelation';
type: 'logicalRelation';
when?: 'after';
entity: T;
action: ED[T]['Action'] | Array<ED[T]['Action']>;
expression: <T2 extends keyof ED>(
checker: (
operation: ED[T]['Operation'] | ED[T]['Selection'],
context: Cxt,
option: OperateOption | SelectOption
) => ExpressionTaskCombination<ED> | undefined | string | Promise<ExpressionTaskCombination<ED> | string | undefined> ; // 生成一个带表达式的查询任务数组表达式结果为true代表可以过or关系。如果返回undefined直接过返回string直接挂
errMsg: string;
) => void | Promise<void>;
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
};
export type Checker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> =
DataChecker<ED, T, Cxt> | RowChecker<ED, T, Cxt> | RelationChecker<ED, T, Cxt> | ExpressionChecker<ED, T, Cxt> | ExpressionRelationChecker<ED, T, Cxt>;
DataChecker<ED, T, Cxt> | RowChecker<ED, T, Cxt> | RelationChecker<ED, T, Cxt> | LogicalChecker<ED, T, Cxt> | LogicalRelationChecker<ED, T, Cxt>;
export type AuthDef<ED extends EntityDict, T extends keyof ED> = {