oak-domain 2.2.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/base-app-domain/Modi/Schema.d.ts +10 -23
- package/lib/base-app-domain/ModiEntity/Schema.d.ts +4 -16
- package/lib/base-app-domain/Oper/Schema.d.ts +6 -18
- package/lib/base-app-domain/OperEntity/Schema.d.ts +4 -17
- package/lib/base-app-domain/User/Schema.d.ts +14 -21
- package/lib/checkers/index.d.ts +2 -2
- package/lib/checkers/index.js +6 -1
- package/lib/compiler/schemalBuilder.js +145 -31
- package/lib/store/AsyncRowStore.d.ts +3 -1
- package/lib/store/AsyncRowStore.js +3 -0
- package/lib/store/CascadeStore.d.ts +4 -2
- package/lib/store/CascadeStore.js +141 -62
- package/lib/store/SyncRowStore.d.ts +3 -1
- package/lib/store/SyncRowStore.js +3 -0
- package/lib/store/TriggerExecutor.js +43 -5
- package/lib/store/checker.d.ts +2 -1
- package/lib/store/checker.js +193 -23
- package/lib/store/filter.d.ts +1 -0
- package/lib/store/filter.js +49 -26
- package/lib/store/modi.js +39 -5
- package/lib/store/relation.js +4 -2
- package/lib/store/selection.js +2 -2
- package/lib/types/Auth.d.ts +11 -2
- package/lib/types/Entity.d.ts +32 -1
- package/lib/types/Expression.js +19 -4
- package/lib/types/Storage.d.ts +4 -3
- package/lib/types/Timer.d.ts +1 -2
- package/lib/types/Trigger.d.ts +12 -0
- package/lib/utils/SimpleConnector.js +15 -0
- package/lib/utils/cron.d.ts +1 -0
- package/lib/utils/cron.js +18 -0
- package/lib/utils/lodash.d.ts +16 -1
- package/lib/utils/lodash.js +48 -31
- package/lib/utils/uuid.js +18 -6
- package/package.json +2 -2
package/lib/store/checker.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.translateCheckerInSyncContext = exports.translateCheckerInAsyncContext = void 0;
|
|
3
|
+
exports.createRelationHierarchyCheckers = exports.translateCheckerInSyncContext = exports.translateCheckerInAsyncContext = void 0;
|
|
4
4
|
var tslib_1 = require("tslib");
|
|
5
5
|
var assert_1 = tslib_1.__importDefault(require("assert"));
|
|
6
6
|
var filter_1 = require("../store/filter");
|
|
7
7
|
var Exception_1 = require("../types/Exception");
|
|
8
8
|
var actionDef_1 = require("./actionDef");
|
|
9
|
+
var string_1 = require("../utils/string");
|
|
9
10
|
function translateCheckerInAsyncContext(checker) {
|
|
10
11
|
var _this = this;
|
|
11
12
|
var entity = checker.entity, type = checker.type;
|
|
@@ -35,12 +36,11 @@ function translateCheckerInAsyncContext(checker) {
|
|
|
35
36
|
switch (_d.label) {
|
|
36
37
|
case 0:
|
|
37
38
|
operationFilter = operation.filter, action = operation.action;
|
|
38
|
-
(0, assert_1.default)(operationFilter);
|
|
39
39
|
filter2 = typeof filter_2 === 'function' ? filter_2(operation, context, option) : filter_2;
|
|
40
40
|
if (!['select', 'count', 'stat'].includes(action)) return [3 /*break*/, 1];
|
|
41
|
-
operation.filter = (0, filter_1.addFilterSegment)(operationFilter, filter2);
|
|
41
|
+
operation.filter = (0, filter_1.addFilterSegment)(operationFilter || {}, filter2);
|
|
42
42
|
return [2 /*return*/, 0];
|
|
43
|
-
case 1: return [4 /*yield*/, (0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter)];
|
|
43
|
+
case 1: return [4 /*yield*/, (0, filter_1.checkFilterContains)(entity, context, filter2, operationFilter || {})];
|
|
44
44
|
case 2:
|
|
45
45
|
if (_d.sent()) {
|
|
46
46
|
return [2 /*return*/, 0];
|
|
@@ -117,27 +117,35 @@ function translateCheckerInAsyncContext(checker) {
|
|
|
117
117
|
return (function (_a, context, option) {
|
|
118
118
|
var operation = _a.operation;
|
|
119
119
|
return tslib_1.__awaiter(_this, void 0, void 0, function () {
|
|
120
|
-
var
|
|
121
|
-
return tslib_1.__generator(this, function (
|
|
122
|
-
switch (
|
|
120
|
+
var exprResult, expressionEntity, expr, expressionFilter, _b, result;
|
|
121
|
+
return tslib_1.__generator(this, function (_c) {
|
|
122
|
+
switch (_c.label) {
|
|
123
123
|
case 0:
|
|
124
124
|
if (context.isRoot() && type === 'expressionRelation') {
|
|
125
125
|
return [2 /*return*/, 0];
|
|
126
126
|
}
|
|
127
|
-
|
|
127
|
+
exprResult = expression_1(operation, context, option);
|
|
128
|
+
if (!(typeof exprResult === 'string')) return [3 /*break*/, 1];
|
|
129
|
+
throw new Exception_1.OakUserUnpermittedException(exprResult || errMsg_2);
|
|
130
|
+
case 1:
|
|
131
|
+
if (!(exprResult === undefined)) return [3 /*break*/, 2];
|
|
132
|
+
return [2 /*return*/, 0];
|
|
133
|
+
case 2:
|
|
134
|
+
expressionEntity = exprResult.entity, expr = exprResult.expr, expressionFilter = exprResult.filter;
|
|
128
135
|
return [4 /*yield*/, context.select(expressionEntity, {
|
|
129
136
|
data: {
|
|
130
137
|
$expr: expr,
|
|
131
138
|
},
|
|
132
139
|
filter: expressionFilter,
|
|
133
140
|
}, Object.assign({}, option, { dontCollect: true }))];
|
|
134
|
-
case
|
|
135
|
-
|
|
141
|
+
case 3:
|
|
142
|
+
_b = tslib_1.__read.apply(void 0, [_c.sent(), 1]), result = _b[0];
|
|
136
143
|
if (!result) {
|
|
137
144
|
// 条件判定为假,抛异常
|
|
138
|
-
throw new Exception_1.
|
|
145
|
+
throw new Exception_1.OakUserUnpermittedException(errMsg_2);
|
|
139
146
|
}
|
|
140
|
-
|
|
147
|
+
_c.label = 4;
|
|
148
|
+
case 4: return [2 /*return*/, 0];
|
|
141
149
|
}
|
|
142
150
|
});
|
|
143
151
|
});
|
|
@@ -196,18 +204,27 @@ function translateCheckerInSyncContext(checker) {
|
|
|
196
204
|
if (context.isRoot() && type === 'expressionRelation') {
|
|
197
205
|
return;
|
|
198
206
|
}
|
|
199
|
-
var
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
207
|
+
var exprResult = expression_2(operation, context, option);
|
|
208
|
+
if (typeof exprResult === 'string') {
|
|
209
|
+
throw new Exception_1.OakUserUnpermittedException(exprResult || errMsg_5);
|
|
210
|
+
}
|
|
211
|
+
else if (exprResult === undefined) {
|
|
212
|
+
return 0;
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
var expressionEntity = exprResult.entity, expr = exprResult.expr, expressionFilter = exprResult.filter;
|
|
216
|
+
var _a = tslib_1.__read(context.select(expressionEntity, {
|
|
217
|
+
data: {
|
|
218
|
+
$expr: expr,
|
|
219
|
+
},
|
|
220
|
+
filter: expressionFilter,
|
|
221
|
+
}, Object.assign({}, option, { dontCollect: true })), 1), result = _a[0];
|
|
222
|
+
if (!result.$expr) {
|
|
223
|
+
// 条件判定为假,抛异常
|
|
224
|
+
throw new Exception_1.OakRowInconsistencyException(undefined, errMsg_5);
|
|
225
|
+
}
|
|
226
|
+
return;
|
|
209
227
|
}
|
|
210
|
-
return;
|
|
211
228
|
};
|
|
212
229
|
}
|
|
213
230
|
default: {
|
|
@@ -216,3 +233,156 @@ function translateCheckerInSyncContext(checker) {
|
|
|
216
233
|
}
|
|
217
234
|
}
|
|
218
235
|
exports.translateCheckerInSyncContext = translateCheckerInSyncContext;
|
|
236
|
+
function createRelationHierarchyCheckers(schema) {
|
|
237
|
+
var checkers = [];
|
|
238
|
+
var _loop_1 = function (entity) {
|
|
239
|
+
var e_1, _a;
|
|
240
|
+
var relationHierarchy = schema[entity].relationHierarchy;
|
|
241
|
+
if (relationHierarchy) {
|
|
242
|
+
// 先build反向hierarchy的map
|
|
243
|
+
var reverseHierarchy_1 = {};
|
|
244
|
+
for (var r in relationHierarchy) {
|
|
245
|
+
try {
|
|
246
|
+
for (var _b = (e_1 = void 0, tslib_1.__values(relationHierarchy[r])), _c = _b.next(); !_c.done; _c = _b.next()) {
|
|
247
|
+
var r2 = _c.value;
|
|
248
|
+
if (!reverseHierarchy_1[r2]) {
|
|
249
|
+
reverseHierarchy_1[r2] = [r];
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
reverseHierarchy_1[r2].push(r);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
257
|
+
finally {
|
|
258
|
+
try {
|
|
259
|
+
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
|
260
|
+
}
|
|
261
|
+
finally { if (e_1) throw e_1.error; }
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// 对userEntity对象的授权和回收建立checker
|
|
265
|
+
var userEntityName_1 = "user".concat((0, string_1.firstLetterUpperCase)(entity));
|
|
266
|
+
var entityIdAttr_1 = "".concat(entity, "Id");
|
|
267
|
+
checkers.push({
|
|
268
|
+
entity: userEntityName_1,
|
|
269
|
+
action: 'create',
|
|
270
|
+
type: 'expressionRelation',
|
|
271
|
+
expression: function (operation, context) {
|
|
272
|
+
var _a;
|
|
273
|
+
var data = operation.data;
|
|
274
|
+
var _b = data, relation = _b.relation, _c = entityIdAttr_1, entityId = _b[_c];
|
|
275
|
+
var legalRelations = reverseHierarchy_1[relation];
|
|
276
|
+
if (!legalRelations) {
|
|
277
|
+
return undefined;
|
|
278
|
+
}
|
|
279
|
+
if (legalRelations.length === 0) {
|
|
280
|
+
return '这是不应该跑出来的情况,请杀程序员祭天';
|
|
281
|
+
}
|
|
282
|
+
var userId = context.getCurrentUserId();
|
|
283
|
+
return {
|
|
284
|
+
entity: userEntityName_1,
|
|
285
|
+
expr: {
|
|
286
|
+
$gt: [{
|
|
287
|
+
'#attr': '$$createAt$$',
|
|
288
|
+
}, 0]
|
|
289
|
+
},
|
|
290
|
+
filter: (_a = {
|
|
291
|
+
userId: userId
|
|
292
|
+
},
|
|
293
|
+
_a[entityIdAttr_1] = entityId,
|
|
294
|
+
_a.relation = {
|
|
295
|
+
$in: legalRelations,
|
|
296
|
+
},
|
|
297
|
+
_a)
|
|
298
|
+
};
|
|
299
|
+
},
|
|
300
|
+
errMsg: '越权操作',
|
|
301
|
+
});
|
|
302
|
+
var _loop_2 = function (r) {
|
|
303
|
+
checkers.push({
|
|
304
|
+
entity: userEntityName_1,
|
|
305
|
+
action: 'remove',
|
|
306
|
+
type: 'expressionRelation',
|
|
307
|
+
expression: function (operation, context) {
|
|
308
|
+
var _a, _b;
|
|
309
|
+
var userId = context.getCurrentUserId();
|
|
310
|
+
var filter = operation.filter;
|
|
311
|
+
var legalRelations = reverseHierarchy_1[r];
|
|
312
|
+
if (legalRelations.length === 0) {
|
|
313
|
+
return '这是不应该跑出来的情况,请杀程序员祭天';
|
|
314
|
+
}
|
|
315
|
+
return {
|
|
316
|
+
entity: userEntityName_1,
|
|
317
|
+
expr: {
|
|
318
|
+
$gt: [{
|
|
319
|
+
'#attr': '$$createAt$$',
|
|
320
|
+
}, 0]
|
|
321
|
+
},
|
|
322
|
+
filter: (_a = {
|
|
323
|
+
userId: userId
|
|
324
|
+
},
|
|
325
|
+
_a[entityIdAttr_1] = {
|
|
326
|
+
$in: {
|
|
327
|
+
entity: userEntityName_1,
|
|
328
|
+
data: (_b = {},
|
|
329
|
+
_b[entityIdAttr_1] = 1,
|
|
330
|
+
_b),
|
|
331
|
+
filter: filter,
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
_a.relation = {
|
|
335
|
+
$in: legalRelations,
|
|
336
|
+
},
|
|
337
|
+
_a),
|
|
338
|
+
};
|
|
339
|
+
},
|
|
340
|
+
errMsg: '越权操作',
|
|
341
|
+
});
|
|
342
|
+
};
|
|
343
|
+
for (var r in reverseHierarchy_1) {
|
|
344
|
+
_loop_2(r);
|
|
345
|
+
}
|
|
346
|
+
/* // 一个人不能授权给自己,也不能删除自己的授权
|
|
347
|
+
checkers.push({
|
|
348
|
+
entity: userEntityName as keyof ED,
|
|
349
|
+
action: 'create' as ED[keyof ED]['Action'],
|
|
350
|
+
type: 'data',
|
|
351
|
+
checker: (data, context) => {
|
|
352
|
+
assert(!(data instanceof Array));
|
|
353
|
+
const { userId } = data as ED[keyof ED]['CreateSingle']['data'];
|
|
354
|
+
const userId2 = context.getCurrentUserId(true);
|
|
355
|
+
if (userId === userId2) {
|
|
356
|
+
throw new OakDataException('不允许授权给自己');
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
checkers.push({
|
|
362
|
+
entity: userEntityName as keyof ED,
|
|
363
|
+
action: 'remove' as ED[keyof ED]['Action'],
|
|
364
|
+
type: 'row',
|
|
365
|
+
filter: (operation, context) => {
|
|
366
|
+
const userId = context.getCurrentUserId(true);
|
|
367
|
+
if (userId) {
|
|
368
|
+
return {
|
|
369
|
+
userId: {
|
|
370
|
+
$ne: userId,
|
|
371
|
+
},
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
console.warn(`没有当前用户但在删除权限,请检查。对象是${entity}`);
|
|
375
|
+
return {};
|
|
376
|
+
},
|
|
377
|
+
errMsg: '不允许回收自己的授权',
|
|
378
|
+
}); */
|
|
379
|
+
// 转让权限现在用update动作,只允许update userId给其它人
|
|
380
|
+
// todo 等实现的时候再写
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
for (var entity in schema) {
|
|
384
|
+
_loop_1(entity);
|
|
385
|
+
}
|
|
386
|
+
return checkers;
|
|
387
|
+
}
|
|
388
|
+
exports.createRelationHierarchyCheckers = createRelationHierarchyCheckers;
|
package/lib/store/filter.d.ts
CHANGED
|
@@ -97,3 +97,4 @@ export declare function makeTreeAncestorFilter<ED extends EntityDict, T extends
|
|
|
97
97
|
*/
|
|
98
98
|
export declare function makeTreeDescendantFilter<ED extends EntityDict, T extends keyof ED>(entity: T, parentKey: string, filter: ED[T]['Selection']['filter'], level?: number, includeAll?: boolean, includeSelf?: boolean): ED[T]['Selection']['filter'];
|
|
99
99
|
export declare function checkFilterContains<ED extends EntityDict, T extends keyof ED, Cxt extends SyncContext<ED> | AsyncContext<ED>>(entity: T, context: Cxt, contained: ED[T]['Selection']['filter'], filter?: ED[T]['Selection']['filter']): boolean | Promise<boolean>;
|
|
100
|
+
export declare function checkFilterRepel<ED extends EntityDict, T extends keyof ED, Cxt extends SyncContext<ED> | AsyncContext<ED>>(entity: T, context: Cxt, filter1: ED[T]['Selection']['filter'], filter2: ED[T]['Selection']['filter']): boolean | Promise<boolean>;
|
package/lib/store/filter.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.checkFilterContains = exports.makeTreeDescendantFilter = exports.makeTreeAncestorFilter = exports.same = exports.getRelevantIds = exports.repel = exports.contains = exports.judgeValueRelation = exports.combineFilters = exports.unionFilterSegment = exports.addFilterSegment = void 0;
|
|
3
|
+
exports.checkFilterRepel = exports.checkFilterContains = exports.makeTreeDescendantFilter = exports.makeTreeAncestorFilter = exports.same = exports.getRelevantIds = exports.repel = exports.contains = exports.judgeValueRelation = exports.combineFilters = exports.unionFilterSegment = exports.addFilterSegment = void 0;
|
|
4
4
|
var tslib_1 = require("tslib");
|
|
5
5
|
var assert_1 = tslib_1.__importDefault(require("assert"));
|
|
6
6
|
var types_1 = require("../types");
|
|
@@ -502,7 +502,7 @@ function judgeFilter2ValueRelation(entity, schema, attr, filter, conditionalFilt
|
|
|
502
502
|
var logicQueries = filter[attr2];
|
|
503
503
|
var results = logicQueries.map(function (logicQuery) { return judgeFilter2ValueRelation(entity, schema, attr, logicQuery, conditionalFilterAttrValue, contained); });
|
|
504
504
|
// 如果filter的多个算子是and关系,则只要有一个包含此条件就是包含,只要有一个与此条件相斥就是相斥
|
|
505
|
-
// 如果filter的多个算子是or关系,则必须所有的条件都包含此条件才是包含,必须所有的条件都与此条件相斥才是相斥
|
|
505
|
+
// 如果filter的多个算子是or关系,则必须所有的条件都包含此条件才是包含,必须所有的条件都与此条件相斥才是相斥
|
|
506
506
|
if (attr2 === '$and') {
|
|
507
507
|
if (results.includes(true)) {
|
|
508
508
|
return true;
|
|
@@ -520,25 +520,17 @@ function judgeFilter2ValueRelation(entity, schema, attr, filter, conditionalFilt
|
|
|
520
520
|
}
|
|
521
521
|
case '$not': {
|
|
522
522
|
/*
|
|
523
|
-
* 若filter的not条件被conditionalFilterAttrValue
|
|
524
|
-
*
|
|
525
|
-
* 但两条规则都没法应用,会无限递归
|
|
523
|
+
* 若filter的not条件被conditionalFilterAttrValue条件包容,则说明两者互斥
|
|
524
|
+
* filter包容conditionalFilterAttrValue条件暂时无法由其not条件推论出来
|
|
526
525
|
*/
|
|
527
526
|
var logicQuery = filter[attr2];
|
|
528
|
-
|
|
529
|
-
[attr2]: {
|
|
530
|
-
$not: conditionalFilterAttrValue
|
|
531
|
-
}
|
|
532
|
-
}, logicQuery, contained)) {
|
|
533
|
-
return true;
|
|
534
|
-
} */
|
|
535
|
-
if (!contained && judgeFilterRelation(entity, schema, (_a = {}, _a[attr2] = conditionalFilterAttrValue, _a), logicQuery, contained)) {
|
|
527
|
+
if (!contained && judgeFilterRelation(entity, schema, logicQuery, (_a = {}, _a[attr] = conditionalFilterAttrValue, _a), true)) {
|
|
536
528
|
return true;
|
|
537
529
|
}
|
|
538
530
|
break;
|
|
539
531
|
}
|
|
540
532
|
default: {
|
|
541
|
-
|
|
533
|
+
(0, assert_1.default)(false);
|
|
542
534
|
}
|
|
543
535
|
}
|
|
544
536
|
}
|
|
@@ -566,6 +558,7 @@ function judgeFilter2ValueRelation(entity, schema, attr, filter, conditionalFilt
|
|
|
566
558
|
}
|
|
567
559
|
}
|
|
568
560
|
}
|
|
561
|
+
// 到这里说明无法判断相容或者相斥,安全起见全返回false
|
|
569
562
|
return false;
|
|
570
563
|
}
|
|
571
564
|
/**
|
|
@@ -584,15 +577,15 @@ function judgeFilterRelation(entity, schema, filter, conditionalFilter, containe
|
|
|
584
577
|
var logicQueries = conditionalFilter[attr];
|
|
585
578
|
var results = logicQueries.map(function (logicQuery) { return judgeFilterRelation(entity, schema, filter, logicQuery, contained); });
|
|
586
579
|
if (contained) {
|
|
587
|
-
//
|
|
580
|
+
// 如果是包容关系,or和and需要全部被包容
|
|
588
581
|
if (results.includes(false)) {
|
|
589
582
|
return false;
|
|
590
583
|
}
|
|
591
584
|
}
|
|
592
585
|
else if (!contained) {
|
|
593
|
-
//
|
|
594
|
-
if (
|
|
595
|
-
return
|
|
586
|
+
// 如果是相斥关系,and只需要和一个相斥,or需要和全部相斥
|
|
587
|
+
if (attr === '$and' && results.includes(true) || attr === '$or' && !results.includes(false)) {
|
|
588
|
+
return true;
|
|
596
589
|
}
|
|
597
590
|
}
|
|
598
591
|
else {
|
|
@@ -602,12 +595,19 @@ function judgeFilterRelation(entity, schema, filter, conditionalFilter, containe
|
|
|
602
595
|
}
|
|
603
596
|
case '$not': {
|
|
604
597
|
/**
|
|
605
|
-
* 若filter与not
|
|
606
|
-
* 若filter
|
|
598
|
+
* 若filter与conditionalFilter not所定义的部分相斥,则filter与conditionalFilter相容
|
|
599
|
+
* 若filter将conditionalFilter not所定义的部分包容,则filter与conditionalFilter相斥
|
|
607
600
|
*/
|
|
608
601
|
var logicQuery = conditionalFilter[attr];
|
|
609
|
-
if (
|
|
610
|
-
|
|
602
|
+
if (contained) {
|
|
603
|
+
if (!judgeFilterRelation(entity, schema, filter, logicQuery, false)) {
|
|
604
|
+
return false;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
else {
|
|
608
|
+
if (judgeFilterRelation(entity, schema, filter, logicQuery, true)) {
|
|
609
|
+
return true;
|
|
610
|
+
}
|
|
611
611
|
}
|
|
612
612
|
break;
|
|
613
613
|
}
|
|
@@ -655,8 +655,8 @@ function judgeFilterRelation(entity, schema, filter, conditionalFilter, containe
|
|
|
655
655
|
* @returns
|
|
656
656
|
*/
|
|
657
657
|
function contains(entity, schema, filter, conditionalFilter) {
|
|
658
|
-
|
|
659
|
-
return false;
|
|
658
|
+
return judgeFilterRelation(entity, schema, filter, conditionalFilter, true);
|
|
659
|
+
// return false;
|
|
660
660
|
}
|
|
661
661
|
exports.contains = contains;
|
|
662
662
|
/**
|
|
@@ -675,8 +675,8 @@ exports.contains = contains;
|
|
|
675
675
|
*/
|
|
676
676
|
function repel(entity, schema, filter1, filter2) {
|
|
677
677
|
// todo
|
|
678
|
-
|
|
679
|
-
return false;
|
|
678
|
+
return judgeFilterRelation(entity, schema, filter1, filter2, false);
|
|
679
|
+
// return false;
|
|
680
680
|
}
|
|
681
681
|
exports.repel = repel;
|
|
682
682
|
/**
|
|
@@ -853,3 +853,26 @@ function checkFilterContains(entity, context, contained, filter) {
|
|
|
853
853
|
return count === 0;
|
|
854
854
|
}
|
|
855
855
|
exports.checkFilterContains = checkFilterContains;
|
|
856
|
+
function checkFilterRepel(entity, context, filter1, filter2) {
|
|
857
|
+
if (!filter2) {
|
|
858
|
+
throw new types_1.OakRowInconsistencyException();
|
|
859
|
+
}
|
|
860
|
+
var schema = context.getSchema();
|
|
861
|
+
// 优先判断两个条件是否相容
|
|
862
|
+
if (repel(entity, schema, filter2, filter1)) {
|
|
863
|
+
return true;
|
|
864
|
+
}
|
|
865
|
+
// 再判断两者同时成立时取得的行数是否为0
|
|
866
|
+
var filter3 = combineFilters([filter2, filter1]);
|
|
867
|
+
var count = context.count(entity, {
|
|
868
|
+
filter: filter3,
|
|
869
|
+
}, {
|
|
870
|
+
dontCollect: true,
|
|
871
|
+
blockTrigger: true,
|
|
872
|
+
});
|
|
873
|
+
if (count instanceof Promise) {
|
|
874
|
+
return count.then(function (count2) { return count2 !== 0; });
|
|
875
|
+
}
|
|
876
|
+
return count !== 0;
|
|
877
|
+
}
|
|
878
|
+
exports.checkFilterRepel = checkFilterRepel;
|
package/lib/store/modi.js
CHANGED
|
@@ -5,6 +5,7 @@ var tslib_1 = require("tslib");
|
|
|
5
5
|
var action_1 = require("../actions/action");
|
|
6
6
|
var lodash_1 = require("../utils/lodash");
|
|
7
7
|
var uuid_1 = require("../utils/uuid");
|
|
8
|
+
var assert_1 = tslib_1.__importDefault(require("assert"));
|
|
8
9
|
function createOperationsFromModies(modies) {
|
|
9
10
|
return modies.map(function (modi) {
|
|
10
11
|
return {
|
|
@@ -86,12 +87,45 @@ function createModiRelatedCheckers(schema) {
|
|
|
86
87
|
action: restActions,
|
|
87
88
|
type: 'row',
|
|
88
89
|
filter: function (operation, context, option) {
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
/**
|
|
91
|
+
* 只有一种情况可以通过,即当前是在更新和active的modi所指向同一个父更新对象。
|
|
92
|
+
* 比如:先申请了一个公司(company),再申请修改公司(companyApplyment),这时所有的active modi都指向此条companyApplyment
|
|
93
|
+
* 这时:
|
|
94
|
+
* 1)再申请一条新的修改公司(create companyApplyment),应被拒绝
|
|
95
|
+
* 2)申请修改原来的companyApplyment(update companyApplyment),可以通过
|
|
96
|
+
* 3)在其它路径上对此company对象进行直接的更新,应被拒绝
|
|
97
|
+
*/
|
|
98
|
+
if (option.modiParentEntity) {
|
|
99
|
+
var _a = option, modiParentEntity = _a.modiParentEntity, modiParentId = _a.modiParentId;
|
|
100
|
+
(0, assert_1.default)(modiParentEntity);
|
|
101
|
+
(0, assert_1.default)(modiParentId);
|
|
91
102
|
return {
|
|
92
103
|
id: {
|
|
93
|
-
$
|
|
94
|
-
|
|
104
|
+
$nin: {
|
|
105
|
+
entity: 'modiEntity',
|
|
106
|
+
data: {
|
|
107
|
+
entityId: 1,
|
|
108
|
+
},
|
|
109
|
+
filter: {
|
|
110
|
+
entity: entity,
|
|
111
|
+
modi: {
|
|
112
|
+
iState: 'active',
|
|
113
|
+
$or: [
|
|
114
|
+
{
|
|
115
|
+
entity: {
|
|
116
|
+
$ne: modiParentEntity,
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
entityId: {
|
|
121
|
+
$ne: modiParentId,
|
|
122
|
+
},
|
|
123
|
+
}
|
|
124
|
+
],
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
}
|
|
95
129
|
};
|
|
96
130
|
}
|
|
97
131
|
return {
|
|
@@ -111,7 +145,7 @@ function createModiRelatedCheckers(schema) {
|
|
|
111
145
|
}
|
|
112
146
|
};
|
|
113
147
|
},
|
|
114
|
-
errMsg:
|
|
148
|
+
errMsg: '您请求的更新对象上还有正在申请的更新,请等该更新结束后再试',
|
|
115
149
|
});
|
|
116
150
|
};
|
|
117
151
|
for (var entity in schema) {
|
package/lib/store/relation.js
CHANGED
|
@@ -24,9 +24,11 @@ function judgeRelation(schema, entity, attr) {
|
|
|
24
24
|
return 1;
|
|
25
25
|
}
|
|
26
26
|
if (attr.includes('$')) {
|
|
27
|
-
var
|
|
27
|
+
var firstDelimiter = attr.indexOf('$');
|
|
28
|
+
var entity2 = attr.slice(0, firstDelimiter);
|
|
28
29
|
(0, assert_1.default)(schema.hasOwnProperty(entity2));
|
|
29
|
-
var
|
|
30
|
+
var secondDelemiter = attr.indexOf('$', firstDelimiter + 1);
|
|
31
|
+
var foreignKey = attr.slice(firstDelimiter + 1, secondDelemiter > 0 ? secondDelemiter : attr.length);
|
|
30
32
|
var _c = schema, _d = entity2, attributes2 = _c[_d].attributes;
|
|
31
33
|
if (foreignKey === 'entity') {
|
|
32
34
|
// 基于反指对象的反向关联
|
package/lib/store/selection.js
CHANGED
|
@@ -181,7 +181,7 @@ function reinforceSelection(schema, entity, selection) {
|
|
|
181
181
|
necessaryAttrs.push("".concat(attr, "Id"));
|
|
182
182
|
checkProjectionNode(rel, projectionNode[attr]);
|
|
183
183
|
}
|
|
184
|
-
else if (rel instanceof Array) {
|
|
184
|
+
else if (rel instanceof Array && !attr.endsWith('$$aggr')) {
|
|
185
185
|
var data_1 = projectionNode[attr].data;
|
|
186
186
|
if (rel[1]) {
|
|
187
187
|
checkNode(data_1, [rel[1]]);
|
|
@@ -189,7 +189,7 @@ function reinforceSelection(schema, entity, selection) {
|
|
|
189
189
|
else {
|
|
190
190
|
checkNode(data_1, ['entity', 'entityId']);
|
|
191
191
|
}
|
|
192
|
-
|
|
192
|
+
reinforceSelection(schema, rel[0], projectionNode[attr]);
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
195
|
}
|
package/lib/types/Auth.d.ts
CHANGED
|
@@ -3,12 +3,17 @@ import { SyncContext } from "../store/SyncRowStore";
|
|
|
3
3
|
import { EntityDict, OperateOption, SelectOption } from "../types/Entity";
|
|
4
4
|
import { RefOrExpression } from "./Expression";
|
|
5
5
|
export declare type CheckerType = 'relation' | 'row' | 'data' | 'expression' | 'expressionRelation';
|
|
6
|
+
/**
|
|
7
|
+
* conditionalFilter是指该action发生时,operation所操作的行中有满足conditionalFilter的行
|
|
8
|
+
* 被转化成trigger的filter条件,详细可看trigger中的说明
|
|
9
|
+
*/
|
|
6
10
|
export declare type DataChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
|
|
7
11
|
priority?: number;
|
|
8
12
|
type: 'data';
|
|
9
13
|
entity: T;
|
|
10
14
|
action: Omit<ED[T]['Action'], 'remove'> | Array<Omit<ED[T]['Action'], 'remove'>>;
|
|
11
15
|
checker: (data: ED[T]['Create']['data'] | ED[T]['Update']['data'], context: Cxt) => void;
|
|
16
|
+
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
|
|
12
17
|
};
|
|
13
18
|
export declare type RowChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
|
|
14
19
|
priority?: number;
|
|
@@ -21,6 +26,7 @@ export declare type RowChecker<ED extends EntityDict, T extends keyof ED, Cxt ex
|
|
|
21
26
|
entity: keyof ED;
|
|
22
27
|
selection: (filter?: ED[T]['Selection']['filter']) => ED[keyof ED]['Selection'];
|
|
23
28
|
};
|
|
29
|
+
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
|
|
24
30
|
};
|
|
25
31
|
export declare type RelationChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
|
|
26
32
|
priority?: number;
|
|
@@ -29,6 +35,7 @@ export declare type RelationChecker<ED extends EntityDict, T extends keyof ED, C
|
|
|
29
35
|
action: Omit<ED[T]['Action'], 'create'> | Array<Omit<ED[T]['Action'], 'create'>>;
|
|
30
36
|
relationFilter: (operation: ED[T]['Operation'] | ED[T]['Selection'], context: Cxt, option: OperateOption | SelectOption) => ED[T]['Selection']['filter'];
|
|
31
37
|
errMsg: string;
|
|
38
|
+
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
|
|
32
39
|
};
|
|
33
40
|
export declare type ExpressionChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
|
|
34
41
|
priority?: number;
|
|
@@ -39,8 +46,9 @@ export declare type ExpressionChecker<ED extends EntityDict, T extends keyof ED,
|
|
|
39
46
|
entity: T2;
|
|
40
47
|
expr: RefOrExpression<keyof ED[T2]['OpSchema']>;
|
|
41
48
|
filter: ED[T2]['Selection']['filter'];
|
|
42
|
-
};
|
|
49
|
+
} | undefined | string;
|
|
43
50
|
errMsg: string;
|
|
51
|
+
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
|
|
44
52
|
};
|
|
45
53
|
export declare type ExpressionRelationChecker<ED extends EntityDict, T extends keyof ED, Cxt extends AsyncContext<ED> | SyncContext<ED>> = {
|
|
46
54
|
priority?: number;
|
|
@@ -51,7 +59,8 @@ export declare type ExpressionRelationChecker<ED extends EntityDict, T extends k
|
|
|
51
59
|
entity: T2;
|
|
52
60
|
expr: RefOrExpression<keyof ED[T2]['OpSchema']>;
|
|
53
61
|
filter: ED[T2]['Selection']['filter'];
|
|
54
|
-
};
|
|
62
|
+
} | undefined | string;
|
|
55
63
|
errMsg: string;
|
|
64
|
+
conditionalFilter?: ED[T]['Update']['filter'] | ((operation: ED[T]['Operation'], context: Cxt, option: OperateOption) => ED[T]['Update']['filter']);
|
|
56
65
|
};
|
|
57
66
|
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>;
|
package/lib/types/Entity.d.ts
CHANGED
|
@@ -73,6 +73,7 @@ export interface EntityDef {
|
|
|
73
73
|
Action: string;
|
|
74
74
|
ParticularAction?: string;
|
|
75
75
|
Selection: Omit<DeduceSelection<this['Schema']>, 'action'>;
|
|
76
|
+
Aggregation: Omit<DeduceAggregation<this['Schema'], DeduceProjection<this['Schema']>, DeduceFilter<this['Schema']>, DeduceSorter<this['Schema']>>, 'action'>;
|
|
76
77
|
Operation: DeduceOperation<this['Schema']>;
|
|
77
78
|
Create: DeduceCreateOperation<this['Schema']>;
|
|
78
79
|
CreateSingle: DeduceCreateSingleOperation<this['Schema']>;
|
|
@@ -90,7 +91,18 @@ declare type DeduceProjection<SH extends GeneralEntityShape> = {
|
|
|
90
91
|
'#id'?: NodeId;
|
|
91
92
|
} & {
|
|
92
93
|
[K in keyof SH]?: number | OtmSubProjection | any;
|
|
93
|
-
} & Partial<ExprOp<keyof SH>>;
|
|
94
|
+
} & Partial<ExprOp<keyof SH | string>>;
|
|
95
|
+
export declare type AggregationOp = `#max-${number}` | `#min-${number}` | `#avg-${number}` | `#count-${number}` | `#sum-${number}`;
|
|
96
|
+
export declare type DeduceAggregationData<SH extends GeneralEntityShape, P extends DeduceProjection<SH>> = {
|
|
97
|
+
[A in AggregationOp]?: P;
|
|
98
|
+
} & {
|
|
99
|
+
'#aggr'?: P;
|
|
100
|
+
};
|
|
101
|
+
export declare type AggregationResult<SH extends GeneralEntityShape> = Array<{
|
|
102
|
+
[A in AggregationOp]?: number | string;
|
|
103
|
+
} & {
|
|
104
|
+
'#data'?: Partial<SH>;
|
|
105
|
+
}>;
|
|
94
106
|
export declare type AttrFilter<SH extends GeneralEntityShape> = {
|
|
95
107
|
[K in keyof SH]: any;
|
|
96
108
|
};
|
|
@@ -104,6 +116,7 @@ export declare type DeduceSorterItem<SH extends GeneralEntityShape> = {
|
|
|
104
116
|
};
|
|
105
117
|
export declare type DeduceSorter<SH extends GeneralEntityShape> = Array<DeduceSorterItem<SH>>;
|
|
106
118
|
export declare type DeduceSelection<SH extends GeneralEntityShape> = Selection<DeduceProjection<SH>, DeduceFilter<SH>, DeduceSorter<SH>>;
|
|
119
|
+
export declare type DeduceAggregation<SH extends GeneralEntityShape, P extends DeduceProjection<SH>, F extends DeduceFilter<SH>, S extends DeduceSorter<SH>> = Omit<Operation<'aggregate', DeduceAggregationData<SH, P>, F, S>, 'action'>;
|
|
107
120
|
export declare type DeduceCreateOperationData<SH extends GeneralEntityShape> = {
|
|
108
121
|
id: string;
|
|
109
122
|
} & {
|
|
@@ -137,6 +150,9 @@ export declare type RemoveOpResult<ED extends EntityDict, T extends keyof ED> =
|
|
|
137
150
|
e: T;
|
|
138
151
|
f?: DeduceFilter<ED[T]['Schema']>;
|
|
139
152
|
};
|
|
153
|
+
export declare type RelationHierarchy<R extends string> = {
|
|
154
|
+
[K in R]?: R[];
|
|
155
|
+
};
|
|
140
156
|
export declare type SelectOpResult<ED extends EntityDict> = {
|
|
141
157
|
a: 's';
|
|
142
158
|
d: {
|
|
@@ -156,4 +172,19 @@ export declare type Configuration = {
|
|
|
156
172
|
actionType?: ActionType;
|
|
157
173
|
static?: boolean;
|
|
158
174
|
};
|
|
175
|
+
export declare type Exportation<ED extends EntityDict, T extends keyof ED, K extends string> = {
|
|
176
|
+
name: string;
|
|
177
|
+
id: string;
|
|
178
|
+
entity: T;
|
|
179
|
+
projection: ED[T]['Selection']['data'];
|
|
180
|
+
headers: K[];
|
|
181
|
+
fn: (data: ED[T]['Schema']) => Partial<Record<K, string | number | boolean | null>>;
|
|
182
|
+
};
|
|
183
|
+
export declare type Importation<ED extends EntityDict, T extends keyof ED, K extends string> = {
|
|
184
|
+
name: string;
|
|
185
|
+
id: string;
|
|
186
|
+
entity: T;
|
|
187
|
+
headers: K[];
|
|
188
|
+
fn: (data: Partial<Record<K, string | number | boolean>>) => ED[T]['CreateSingle']['data'];
|
|
189
|
+
};
|
|
159
190
|
export {};
|