实现了authDef中的cascadeRemove

This commit is contained in:
Xu Chang 2023-02-05 22:15:55 +08:00
parent f9b664460d
commit 2571e6f818
7 changed files with 277 additions and 14 deletions

View File

@ -7,7 +7,7 @@ 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));
checkers.push.apply(checkers, tslib_1.__spreadArray([], tslib_1.__read((0, checker_1.createRemoveCheckers)(schema)), false));
checkers.push.apply(checkers, tslib_1.__spreadArray([], tslib_1.__read((0, checker_1.createRemoveCheckers)(schema, authDict)), false));
if (authDict) {
checkers.push.apply(checkers, tslib_1.__spreadArray([], tslib_1.__read((0, checker_1.createAuthCheckers)(schema, authDict)), false));
}

View File

@ -23,4 +23,4 @@ export declare function createAuthCheckers<ED extends EntityDict & BaseEntityDic
* @returns
* 使trigger来处理其相关联的外键对象trigger写作beforechecker之前执行
*/
export declare function createRemoveCheckers<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED> | SyncContext<ED>>(schema: StorageSchema<ED>): Checker<ED, keyof ED, Cxt>[];
export declare function createRemoveCheckers<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED> | SyncContext<ED>>(schema: StorageSchema<ED>, authDict?: AuthDefDict<ED>): Checker<ED, keyof ED, Cxt>[];

View File

@ -5,10 +5,12 @@ var tslib_1 = require("tslib");
var assert_1 = tslib_1.__importDefault(require("assert"));
var filter_1 = require("../store/filter");
var Exception_1 = require("../types/Exception");
var types_1 = require("../types");
var actionDef_1 = require("./actionDef");
var string_1 = require("../utils/string");
var lodash_1 = require("../utils/lodash");
var relation_1 = require("./relation");
var uuid_1 = require("../utils/uuid");
function translateCheckerInAsyncContext(checker) {
var _this = this;
var entity = checker.entity, type = checker.type, action = checker.action;
@ -508,7 +510,7 @@ exports.createAuthCheckers = createAuthCheckers;
* @returns
* 如果有的对象允许删除需要使用trigger来处理其相关联的外键对象这些trigger写作before则会在checker之前执行仍然可以删除成功
*/
function createRemoveCheckers(schema) {
function createRemoveCheckers(schema, authDict) {
var e_1, _a;
var checkers = [];
// 先建立所有的一对多的关系
@ -575,7 +577,7 @@ function createRemoveCheckers(schema) {
var e_3, _a, e_4, _b;
var promises = [];
if (OneToManyMatrix[entity]) {
var _loop_4 = function (otm) {
var _loop_5 = function (otm) {
var _g, _h, _j, _k;
var _l = tslib_1.__read(otm, 2), e = _l[0], attr = _l[1];
var proj = (_g = {
@ -627,7 +629,7 @@ function createRemoveCheckers(schema) {
try {
for (var _c = (e_3 = void 0, tslib_1.__values(OneToManyMatrix[entity])), _d = _c.next(); !_d.done; _d = _c.next()) {
var otm = _d.value;
_loop_4(otm);
_loop_5(otm);
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
@ -639,7 +641,7 @@ function createRemoveCheckers(schema) {
}
}
if (OneToManyOnEntityMatrix[entity]) {
var _loop_5 = function (otm) {
var _loop_6 = function (otm) {
var _o, _p, _q;
var proj = {
id: 1,
@ -690,7 +692,7 @@ function createRemoveCheckers(schema) {
try {
for (var _e = (e_4 = void 0, tslib_1.__values(OneToManyOnEntityMatrix[entity])), _f = _e.next(); !_f.done; _f = _e.next()) {
var otm = _f.value;
_loop_5(otm);
_loop_6(otm);
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
@ -720,6 +722,146 @@ function createRemoveCheckers(schema) {
}
finally { if (e_1) throw e_1.error; }
}
var _loop_4 = function (entity) {
var e_5, _b;
var cascadeRemove = authDict[entity].cascadeRemove;
if (cascadeRemove) {
var entitiesOnEntityAttr = [];
var hasAllEntity = false;
var _loop_7 = function (attr) {
if (attr === '@entity') {
hasAllEntity = true;
return "continue";
}
var rel = (0, relation_1.judgeRelation)(schema, entity, attr);
if (rel === 2) {
entitiesOnEntityAttr.push(attr);
checkers.push({
entity: attr,
action: 'remove',
type: 'logical',
priority: types_1.REMOVE_CASCADE_PRIORITY,
checker: function (operation, context) {
var _a, _b;
var filter = operation.filter;
if (cascadeRemove[attr] === 'remove') {
return context.operate(entity, {
id: (0, uuid_1.generateNewId)(),
action: 'remove',
data: {},
filter: filter ? (_a = {},
_a[attr] = filter,
_a) : undefined,
}, { dontCollect: true });
}
return context.operate(entity, {
id: (0, uuid_1.generateNewId)(),
action: 'update',
data: {
entity: null,
entityId: null,
},
filter: filter ? (_b = {},
_b[attr] = filter,
_b) : undefined,
}, { dontCollect: true });
}
});
}
else {
(0, assert_1.default)(typeof rel === 'string');
checkers.push({
entity: rel,
action: 'remove',
type: 'logical',
priority: types_1.REMOVE_CASCADE_PRIORITY,
checker: function (operation, context) {
var _a, _b, _c;
var filter = operation.filter;
if (cascadeRemove[attr] === 'remove') {
return context.operate(entity, {
id: (0, uuid_1.generateNewId)(),
action: 'remove',
data: {},
filter: filter ? (_a = {},
_a[attr] = filter,
_a) : undefined,
}, { dontCollect: true });
}
return context.operate(entity, {
id: (0, uuid_1.generateNewId)(),
action: 'update',
data: (_b = {},
_b["".concat(attr, "Id")] = null,
_b),
filter: filter ? (_c = {},
_c[attr] = filter,
_c) : undefined,
}, { dontCollect: true });
}
});
}
};
for (var attr in cascadeRemove) {
_loop_7(attr);
}
if (hasAllEntity) {
var attributes = schema[entity].attributes;
var ref = attributes.entity.ref;
var restEntities = (0, lodash_1.difference)(ref, entitiesOnEntityAttr);
var _loop_8 = function (e) {
checkers.push({
entity: e,
action: 'remove',
type: 'logical',
priority: types_1.REMOVE_CASCADE_PRIORITY,
checker: function (operation, context) {
var _a, _b;
var filter = operation.filter;
if (cascadeRemove['@entity'] === 'remove') {
return context.operate(entity, {
id: (0, uuid_1.generateNewId)(),
action: 'remove',
data: {},
filter: filter ? (_a = {},
_a[e] = filter,
_a) : undefined,
}, { dontCollect: true });
}
return context.operate(entity, {
id: (0, uuid_1.generateNewId)(),
action: 'update',
data: {
entity: null,
entityId: null,
},
filter: filter ? (_b = {},
_b[e] = filter,
_b) : undefined,
}, { dontCollect: true });
}
});
};
try {
for (var restEntities_1 = (e_5 = void 0, tslib_1.__values(restEntities)), restEntities_1_1 = restEntities_1.next(); !restEntities_1_1.done; restEntities_1_1 = restEntities_1.next()) {
var e = restEntities_1_1.value;
_loop_8(e);
}
}
catch (e_5_1) { e_5 = { error: e_5_1 }; }
finally {
try {
if (restEntities_1_1 && !restEntities_1_1.done && (_b = restEntities_1.return)) _b.call(restEntities_1);
}
finally { if (e_5) throw e_5.error; }
}
}
}
};
// 注入声明的cascade删除时的外键处理动作
for (var entity in authDict) {
_loop_4(entity);
}
return checkers;
}
exports.createRemoveCheckers = createRemoveCheckers;

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

@ -60,8 +60,8 @@ export declare type Checker<ED extends EntityDict, T extends keyof ED, Cxt exten
export declare type AuthDef<ED extends EntityDict, T extends keyof ED> = {
relationAuth?: CascadeRelationAuth<NonNullable<ED[T]['Relation']>>;
actionAuth?: CascadeActionAuth<ED[T]['Action']>;
onCasadeRemove?: {
[E in keyof ED[T]['OpSchema'] | '@all']?: ActionOnRemove;
cascadeRemove?: {
[E in keyof ED[T]['OpSchema'] | '@entity']?: ActionOnRemove;
};
};
export declare type AuthDefDict<ED extends EntityDict> = {

View File

@ -8,7 +8,7 @@ import { StorageSchema, EntityDict as BaseEntityDict, Checker, AuthDef, AuthDefD
export function createDynamicCheckers<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED> | SyncContext<ED>>(schema: StorageSchema<ED>, authDict?: AuthDefDict<ED>){
const checkers: Checker<ED, keyof ED, Cxt>[] = [];
checkers.push(...createModiRelatedCheckers<ED, Cxt>(schema));
checkers.push(...createRemoveCheckers<ED, Cxt>(schema));
checkers.push(...createRemoveCheckers<ED, Cxt>(schema, authDict));
if (authDict) {
checkers.push(...createAuthCheckers<ED, Cxt>(schema, authDict));
}

View File

@ -3,7 +3,7 @@ import { addFilterSegment, checkFilterContains, combineFilters } from "../store/
import { OakRowInconsistencyException, OakUserUnpermittedException } from '../types/Exception';
import {
AuthDefDict, CascadeRelationItem, Checker, CreateTriggerInTxn,
EntityDict, OperateOption, SelectOption, StorageSchema, Trigger, UpdateTriggerInTxn, RelationHierarchy, SelectOpResult
EntityDict, OperateOption, SelectOption, StorageSchema, Trigger, UpdateTriggerInTxn, RelationHierarchy, SelectOpResult, REMOVE_CASCADE_PRIORITY
} from "../types";
import { EntityDict as BaseEntityDict } from '../base-app-domain';
import { AsyncContext } from "./AsyncRowStore";
@ -12,6 +12,7 @@ import { SyncContext } from './SyncRowStore';
import { firstLetterUpperCase } from '../utils/string';
import { union, uniq, difference } from '../utils/lodash';
import { judgeRelation } from './relation';
import { generateNewId } from '../utils/uuid';
export function translateCheckerInAsyncContext<
ED extends EntityDict & BaseEntityDict,
@ -490,7 +491,7 @@ export function createAuthCheckers<ED extends EntityDict & BaseEntityDict, Cxt e
* @returns
* 使trigger来处理其相关联的外键对象trigger写作beforechecker之前执行
*/
export function createRemoveCheckers<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED> | SyncContext<ED>>(schema: StorageSchema<ED>) {
export function createRemoveCheckers<ED extends EntityDict & BaseEntityDict, Cxt extends AsyncContext<ED> | SyncContext<ED>>(schema: StorageSchema<ED>, authDict?: AuthDefDict<ED>) {
const checkers: Checker<ED, keyof ED, Cxt>[] = [];
// 先建立所有的一对多的关系
@ -657,5 +658,125 @@ export function createRemoveCheckers<ED extends EntityDict & BaseEntityDict, Cxt
})
}
// 注入声明的cascade删除时的外键处理动作
for (const entity in authDict) {
const { cascadeRemove } = authDict[entity]!;
if (cascadeRemove) {
const entitiesOnEntityAttr = [] as Array<keyof ED>;
let hasAllEntity = false;
for (const attr in cascadeRemove) {
if (attr === '@entity') {
hasAllEntity = true;
continue;
}
const rel = judgeRelation(schema, entity, attr);
if (rel === 2) {
entitiesOnEntityAttr.push(attr);
checkers.push({
entity: attr,
action: 'remove',
type: 'logical',
priority: REMOVE_CASCADE_PRIORITY, // 这个checker必须在检查外键不为空的checker之前执行否则无法完成
checker: (operation, context) => {
const { filter } = operation;
if (cascadeRemove[attr] === 'remove') {
return context.operate(entity, {
id: generateNewId(),
action: 'remove',
data: {},
filter: filter ? {
[attr]: filter,
}: undefined,
}, { dontCollect: true });
}
return context.operate(entity, {
id: generateNewId(),
action: 'update',
data: {
entity: null,
entityId: null,
},
filter: filter ? {
[attr]: filter,
}: undefined,
}, { dontCollect: true });
}
});
}
else {
assert(typeof rel === 'string');
checkers.push({
entity: rel,
action: 'remove',
type: 'logical',
priority: REMOVE_CASCADE_PRIORITY, // 这个checker必须在检查外键不为空的checker之前执行否则无法完成
checker: (operation, context) => {
const { filter } = operation;
if (cascadeRemove[attr] === 'remove') {
return context.operate(entity, {
id: generateNewId(),
action: 'remove',
data: {},
filter: filter ? {
[attr]: filter,
}: undefined,
}, { dontCollect: true });
}
return context.operate(entity, {
id: generateNewId(),
action: 'update',
data: {
[`${attr}Id`]: null,
},
filter: filter ? {
[attr]: filter,
}: undefined,
}, { dontCollect: true });
}
});
}
}
if (hasAllEntity) {
const { attributes } = schema[entity];
const { ref } = attributes.entity;
const restEntities = difference(ref, entitiesOnEntityAttr);
for (const e of restEntities) {
checkers.push({
entity: e,
action: 'remove',
type: 'logical',
priority: REMOVE_CASCADE_PRIORITY, // 这个checker必须在检查外键不为空的checker之前执行否则无法完成
checker: (operation, context) => {
const { filter } = operation;
if (cascadeRemove['@entity'] === 'remove') {
return context.operate(entity, {
id: generateNewId(),
action: 'remove',
data: {},
filter: filter ? {
[e]: filter,
}: undefined,
}, { dontCollect: true });
}
return context.operate(entity, {
id: generateNewId(),
action: 'update',
data: {
entity: null,
entityId: null,
},
filter: filter ? {
[e]: filter,
}: undefined,
}, { dontCollect: true });
}
});
}
}
}
}
return checkers;
}

View File

@ -88,8 +88,8 @@ export type Checker<ED extends EntityDict, T extends keyof ED, Cxt extends Async
export type AuthDef<ED extends EntityDict, T extends keyof ED> = {
relationAuth?: CascadeRelationAuth<NonNullable<ED[T]['Relation']>>;
actionAuth?: CascadeActionAuth<ED[T]['Action']>;
onCasadeRemove?: {
[E in keyof ED[T]['OpSchema'] | '@all']?: ActionOnRemove;
cascadeRemove?: {
[E in keyof ED[T]['OpSchema'] | '@entity']?: ActionOnRemove;
}
};