oak-domain 5.1.23 → 5.1.25
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/store/CascadeStore.d.ts +1 -1
- package/lib/store/CascadeStore.js +21 -15
- package/lib/store/IntrinsicCheckers.js +40 -28
- package/lib/types/Configuration.d.ts +6 -0
- package/lib/types/Entity.d.ts +1 -0
- package/lib/types/EntityDesc.d.ts +10 -2
- package/lib/utils/SimpleConnector.js +1 -1
- package/package.json +1 -1
|
@@ -33,7 +33,7 @@ export declare abstract class CascadeStore<ED extends EntityDict & BaseEntityDic
|
|
|
33
33
|
protected abstract updateAbjointRowAsync<T extends keyof ED, OP extends OperateOption, Cxt extends AsyncContext<ED>>(entity: T, operation: ED[T]['Create'] | ED[T]['Update'] | ED[T]['Remove'], context: Cxt, option: OP): Promise<number>;
|
|
34
34
|
protected abstract aggregateAbjointRowSync<T extends keyof ED, OP extends SelectOption, Cxt extends SyncContext<ED>>(entity: T, aggregation: ED[T]['Aggregation'], context: Cxt, option: OP): AggregationResult<ED[T]['Schema']>;
|
|
35
35
|
protected abstract aggregateAbjointRowAsync<T extends keyof ED, OP extends SelectOption, Cxt extends AsyncContext<ED>>(entity: T, aggregation: ED[T]['Aggregation'], context: Cxt, option: OP): Promise<AggregationResult<ED[T]['Schema']>>;
|
|
36
|
-
protected destructCascadeSelect<T extends keyof ED, OP extends SelectOption, Cxt extends SyncContext<ED> | AsyncContext<ED>>(entity: T, projection2: ED[T]['Projection'], context: Cxt, cascadeSelectFn: <T2 extends keyof ED>(entity2: T2, selection: ED[T2]['Selection'], context: Cxt, op: OP) => Partial<ED[T2]['Schema']>[] | Promise<Partial<ED[T2]['Schema']>[]>, aggregateFn: <T2 extends keyof ED>(entity2: T2, aggregation: ED[T2]['Aggregation'], context: Cxt, op: OP) => AggregationResult<ED[T2]['Schema']> | Promise<AggregationResult<ED[T2]['Schema']>>, option: OP): {
|
|
36
|
+
protected destructCascadeSelect<T extends keyof ED, OP extends SelectOption, Cxt extends SyncContext<ED> | AsyncContext<ED>>(entity: T, projection2: ED[T]['Projection'], context: Cxt, cascadeSelectFn: <T2 extends keyof ED>(entity2: T2, selection: ED[T2]['Selection'], context: Cxt, op: OP) => Partial<ED[T2]['Schema']>[] | Promise<Partial<ED[T2]['Schema']>[]>, aggregateFn: <T2 extends keyof ED>(entity2: T2, aggregation: ED[T2]['Aggregation'], context: Cxt, op: OP) => AggregationResult<ED[T2]['Schema']> | Promise<AggregationResult<ED[T2]['Schema']>>, option: OP, selectionId?: string): {
|
|
37
37
|
projection: ED[T]["Projection"];
|
|
38
38
|
cascadeSelectionFns: ((result: Partial<ED[T]['Schema']>[]) => Promise<void> | void)[];
|
|
39
39
|
};
|
|
@@ -317,7 +317,7 @@ class CascadeStore extends RowStore_1.RowStore {
|
|
|
317
317
|
registerSelectionRewriter(rewriter) {
|
|
318
318
|
this.selectionRewriters.push(rewriter);
|
|
319
319
|
}
|
|
320
|
-
destructCascadeSelect(entity, projection2, context, cascadeSelectFn, aggregateFn, option) {
|
|
320
|
+
destructCascadeSelect(entity, projection2, context, cascadeSelectFn, aggregateFn, option, selectionId) {
|
|
321
321
|
const cascadeSelectionFns = [];
|
|
322
322
|
const supportMtoJoin = this.supportManyToOneJoin();
|
|
323
323
|
const { toModi } = this.getSchema()[entity];
|
|
@@ -352,7 +352,7 @@ class CascadeStore extends RowStore_1.RowStore {
|
|
|
352
352
|
});
|
|
353
353
|
}
|
|
354
354
|
});
|
|
355
|
-
const { projection: subProjection, cascadeSelectionFns: subCascadeSelectionFns, } = this.destructCascadeSelect(attr, projection2[attr], context, cascadeSelectFn, aggregateFn, option);
|
|
355
|
+
const { projection: subProjection, cascadeSelectionFns: subCascadeSelectionFns, } = this.destructCascadeSelect(attr, projection2[attr], context, cascadeSelectFn, aggregateFn, option, selectionId);
|
|
356
356
|
subCascadeSelectionFns.forEach(ele => cascadeSelectionFns.push((result) => {
|
|
357
357
|
return ele(result.map(ele2 => ele2[attr]).filter(ele2 => !!ele2));
|
|
358
358
|
}));
|
|
@@ -372,6 +372,7 @@ class CascadeStore extends RowStore_1.RowStore {
|
|
|
372
372
|
throw new types_1.OakRowUnexistedException([{
|
|
373
373
|
entity: attr,
|
|
374
374
|
selection: {
|
|
375
|
+
id: selectionId,
|
|
375
376
|
data: projection2[attr],
|
|
376
377
|
filter: {
|
|
377
378
|
id: {
|
|
@@ -400,6 +401,7 @@ class CascadeStore extends RowStore_1.RowStore {
|
|
|
400
401
|
};
|
|
401
402
|
if (entityIds.length > 0) {
|
|
402
403
|
const subRows = cascadeSelectFn.call(this, attr, {
|
|
404
|
+
id: selectionId,
|
|
403
405
|
data: projection2[attr],
|
|
404
406
|
filter: {
|
|
405
407
|
id: {
|
|
@@ -440,7 +442,7 @@ class CascadeStore extends RowStore_1.RowStore {
|
|
|
440
442
|
}
|
|
441
443
|
});
|
|
442
444
|
}
|
|
443
|
-
const { projection: subProjection, cascadeSelectionFns: subCascadeSelectionFns, } = this.destructCascadeSelect(relation, projection2[attr], context, cascadeSelectFn, aggregateFn, option);
|
|
445
|
+
const { projection: subProjection, cascadeSelectionFns: subCascadeSelectionFns, } = this.destructCascadeSelect(relation, projection2[attr], context, cascadeSelectFn, aggregateFn, option, selectionId);
|
|
444
446
|
subCascadeSelectionFns.forEach(ele => cascadeSelectionFns.push((result) => {
|
|
445
447
|
return ele(result.map(ele2 => ele2[attr]).filter(ele2 => !!ele2));
|
|
446
448
|
}));
|
|
@@ -489,6 +491,7 @@ class CascadeStore extends RowStore_1.RowStore {
|
|
|
489
491
|
};
|
|
490
492
|
if (ids.length > 0) {
|
|
491
493
|
const subRows = cascadeSelectFn.call(this, relation, {
|
|
494
|
+
id: selectionId,
|
|
492
495
|
data: projection2[attr],
|
|
493
496
|
filter: {
|
|
494
497
|
id: {
|
|
@@ -506,7 +509,7 @@ class CascadeStore extends RowStore_1.RowStore {
|
|
|
506
509
|
}
|
|
507
510
|
else {
|
|
508
511
|
(0, assert_1.default)(relation instanceof Array);
|
|
509
|
-
const { data: subProjection, filter: subFilter, indexFrom, count, sorter: subSorter, total, randomRange } = projection2[attr];
|
|
512
|
+
const { data: subProjection, filter: subFilter, indexFrom, count, sorter: subSorter, total, randomRange, id: subSelectionId } = projection2[attr];
|
|
510
513
|
const [entity2, foreignKey] = relation;
|
|
511
514
|
const isAggr = attr.endsWith('$$aggr');
|
|
512
515
|
const otmAggrFn = (result) => {
|
|
@@ -573,6 +576,7 @@ class CascadeStore extends RowStore_1.RowStore {
|
|
|
573
576
|
},
|
|
574
577
|
}, subFilter]);
|
|
575
578
|
const subRows = cascadeSelectFn.call(this, entity2, {
|
|
579
|
+
id: subSelectionId || selectionId,
|
|
576
580
|
data: subProjection,
|
|
577
581
|
filter: filter2,
|
|
578
582
|
sorter: subSorter,
|
|
@@ -600,6 +604,7 @@ class CascadeStore extends RowStore_1.RowStore {
|
|
|
600
604
|
entityId: row.id,
|
|
601
605
|
}, subFilter]);
|
|
602
606
|
const subRows = cascadeSelectFn.call(this, entity2, {
|
|
607
|
+
id: subSelectionId || selectionId,
|
|
603
608
|
data: subProjection,
|
|
604
609
|
filter: filter2,
|
|
605
610
|
sorter: subSorter,
|
|
@@ -1662,7 +1667,7 @@ class CascadeStore extends RowStore_1.RowStore {
|
|
|
1662
1667
|
* @param rows
|
|
1663
1668
|
* @param context
|
|
1664
1669
|
*/
|
|
1665
|
-
addToResultSelections(entity, rows, context) {
|
|
1670
|
+
addToResultSelections(entity, rows, context, id) {
|
|
1666
1671
|
if (this.supportManyToOneJoin()) {
|
|
1667
1672
|
// 这里的外键连接有可能为空,需要使用所有的行的attr的并集来测试
|
|
1668
1673
|
const attrs = (0, lodash_1.uniq)(rows.map(ele => Object.keys(ele)).flat());
|
|
@@ -1671,29 +1676,29 @@ class CascadeStore extends RowStore_1.RowStore {
|
|
|
1671
1676
|
const data = {};
|
|
1672
1677
|
const rel = this.judgeRelation(entity, attr);
|
|
1673
1678
|
if (rel === 2) {
|
|
1674
|
-
this.addToResultSelections(attr, rows.map(ele => ele[attr]).filter(ele => !!ele), context);
|
|
1679
|
+
this.addToResultSelections(attr, rows.map(ele => ele[attr]).filter(ele => !!ele), context, id);
|
|
1675
1680
|
}
|
|
1676
1681
|
else if (typeof rel === 'string') {
|
|
1677
|
-
this.addToResultSelections(rel, rows.map(ele => ele[attr]).filter(ele => !!ele), context);
|
|
1682
|
+
this.addToResultSelections(rel, rows.map(ele => ele[attr]).filter(ele => !!ele), context, id);
|
|
1678
1683
|
}
|
|
1679
1684
|
else if (rel instanceof Array) {
|
|
1680
|
-
this.addToResultSelections(rel[0], rows.map(ele => ele[attr]).reduce((prev, current) => prev.concat(current), []), context);
|
|
1685
|
+
this.addToResultSelections(rel[0], rows.map(ele => ele[attr]).reduce((prev, current) => prev.concat(current), []), context, id);
|
|
1681
1686
|
}
|
|
1682
1687
|
else {
|
|
1683
1688
|
attrsToPick.push(attr);
|
|
1684
1689
|
}
|
|
1685
1690
|
}
|
|
1686
1691
|
const originRows = rows.map(ele => (0, lodash_1.pick)(ele, attrsToPick));
|
|
1687
|
-
this.addSingleRowToResultSelections(entity, originRows, context);
|
|
1692
|
+
this.addSingleRowToResultSelections(entity, originRows, context, id);
|
|
1688
1693
|
}
|
|
1689
1694
|
else {
|
|
1690
|
-
this.addSingleRowToResultSelections(entity, rows, context);
|
|
1695
|
+
this.addSingleRowToResultSelections(entity, rows, context, id);
|
|
1691
1696
|
}
|
|
1692
1697
|
}
|
|
1693
|
-
addSingleRowToResultSelections(entity, rows, context) {
|
|
1698
|
+
addSingleRowToResultSelections(entity, rows, context, id) {
|
|
1694
1699
|
const { opRecords } = context;
|
|
1695
1700
|
let lastOperation = opRecords[opRecords.length - 1];
|
|
1696
|
-
if (lastOperation && lastOperation.a === 's') {
|
|
1701
|
+
if (lastOperation && lastOperation.a === 's' && id === lastOperation.id) {
|
|
1697
1702
|
const entityBranch = lastOperation.d[entity];
|
|
1698
1703
|
if (entityBranch) {
|
|
1699
1704
|
rows.forEach((row) => {
|
|
@@ -1714,6 +1719,7 @@ class CascadeStore extends RowStore_1.RowStore {
|
|
|
1714
1719
|
}
|
|
1715
1720
|
else {
|
|
1716
1721
|
lastOperation = {
|
|
1722
|
+
id,
|
|
1717
1723
|
a: 's',
|
|
1718
1724
|
d: {},
|
|
1719
1725
|
};
|
|
@@ -1733,8 +1739,8 @@ class CascadeStore extends RowStore_1.RowStore {
|
|
|
1733
1739
|
});
|
|
1734
1740
|
}
|
|
1735
1741
|
async cascadeSelectAsync(entity, selection, context, option) {
|
|
1736
|
-
const { data, filter, indexFrom, count, sorter, total, randomRange, distinct } = selection;
|
|
1737
|
-
const { projection, cascadeSelectionFns } = this.destructCascadeSelect(entity, data, context, this.cascadeSelectAsync, this.aggregateAsync, option);
|
|
1742
|
+
const { data, filter, indexFrom, count, sorter, total, randomRange, distinct, id: selectionId } = selection;
|
|
1743
|
+
const { projection, cascadeSelectionFns } = this.destructCascadeSelect(entity, data, context, this.cascadeSelectAsync, this.aggregateAsync, option, selectionId);
|
|
1738
1744
|
const rows2 = await this.selectAbjointRowAsync(entity, {
|
|
1739
1745
|
data: projection,
|
|
1740
1746
|
filter,
|
|
@@ -1758,7 +1764,7 @@ class CascadeStore extends RowStore_1.RowStore {
|
|
|
1758
1764
|
});
|
|
1759
1765
|
}
|
|
1760
1766
|
if (!option.dontCollect) {
|
|
1761
|
-
this.addToResultSelections(entity, rows, context);
|
|
1767
|
+
this.addToResultSelections(entity, rows, context, selection.id);
|
|
1762
1768
|
}
|
|
1763
1769
|
if (cascadeSelectionFns.length > 0) {
|
|
1764
1770
|
const ruException = [];
|
|
@@ -262,9 +262,19 @@ function createActionTransformerCheckers(actionDefDict) {
|
|
|
262
262
|
* @param filters
|
|
263
263
|
* @param context
|
|
264
264
|
*/
|
|
265
|
-
function cascadelyCheckUpdateFilters(entity, schema, data, filter, matrix, restAttrs, context) {
|
|
265
|
+
function cascadelyCheckUpdateFilters(entity, schema, action, data, filter, matrix, restAttrs, context) {
|
|
266
266
|
const successAttrs = (0, lodash_1.difference)(Object.keys(data), restAttrs);
|
|
267
267
|
const successAttrFilter = (0, lodash_1.pick)(data, successAttrs);
|
|
268
|
+
const checkConditionalFilter = (cf) => {
|
|
269
|
+
// 此时看应用了success的attributes更新后,能否消除掉f中的部分条件
|
|
270
|
+
const result = (0, filter_1.analyzeFilterRelation)(entity, schema, successAttrFilter, cf, true);
|
|
271
|
+
if (typeof result === 'boolean') {
|
|
272
|
+
return result;
|
|
273
|
+
}
|
|
274
|
+
const { sureAttributes } = result;
|
|
275
|
+
const f2 = (0, lodash_1.omit)(cf, sureAttributes);
|
|
276
|
+
return (0, filter_1.checkFilterContains)(entity, context, f2, filter, true);
|
|
277
|
+
};
|
|
268
278
|
/**
|
|
269
279
|
* 先找到能直接更新成功的属性
|
|
270
280
|
*/
|
|
@@ -273,15 +283,14 @@ function cascadelyCheckUpdateFilters(entity, schema, data, filter, matrix, restA
|
|
|
273
283
|
if (!f) {
|
|
274
284
|
return true;
|
|
275
285
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
286
|
+
if (typeof f === 'function') {
|
|
287
|
+
const cf = f({ action, data, filter }, context);
|
|
288
|
+
if (cf instanceof Promise) {
|
|
289
|
+
return cf.then((cf2) => cf2 ? checkConditionalFilter(cf2) : true);
|
|
290
|
+
}
|
|
291
|
+
return cf ? checkConditionalFilter(cf) : true;
|
|
281
292
|
}
|
|
282
|
-
|
|
283
|
-
const f2 = (0, lodash_1.omit)(f, sureAttributes);
|
|
284
|
-
return (0, filter_1.checkFilterContains)(entity, context, f2, filter, true);
|
|
293
|
+
return checkConditionalFilter(f);
|
|
285
294
|
});
|
|
286
295
|
const checkResult1 = (lar) => {
|
|
287
296
|
const legalAttrs = [];
|
|
@@ -301,7 +310,7 @@ function cascadelyCheckUpdateFilters(entity, schema, data, filter, matrix, restA
|
|
|
301
310
|
if (legalAttrs.length === 0) {
|
|
302
311
|
throw new types_1.OakAttrCantUpdateException(entity, illegalAttrs, '更新的行当前属性不满足约束,请仔细检查数据');
|
|
303
312
|
}
|
|
304
|
-
return cascadelyCheckUpdateFilters(entity, schema, data, filter, matrix, illegalAttrs, context);
|
|
313
|
+
return cascadelyCheckUpdateFilters(entity, schema, action, data, filter, matrix, illegalAttrs, context);
|
|
305
314
|
};
|
|
306
315
|
if (legalAttrResult.find(ele => ele instanceof Promise)) {
|
|
307
316
|
return Promise.all(legalAttrResult).then((lar) => checkResult1(lar));
|
|
@@ -341,30 +350,33 @@ function createAttrUpdateCheckers(schema, attrUpdateMatrix) {
|
|
|
341
350
|
}
|
|
342
351
|
const filters = condition.map(ele => {
|
|
343
352
|
if (typeof ele?.filter === 'function') {
|
|
344
|
-
return ele.filter(action || 'select');
|
|
353
|
+
return (ele.filter)({ action: action || 'select', data: data, filter }, context);
|
|
345
354
|
}
|
|
346
355
|
return ele?.filter;
|
|
347
|
-
})
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
const
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
if (
|
|
354
|
-
|
|
355
|
-
return cascadelyCheckUpdateFilters(entity, schema, data, filter, matrix, attrs, context);
|
|
356
|
-
}
|
|
357
|
-
throw new types_1.OakAttrCantUpdateException(entity, attrs);
|
|
356
|
+
});
|
|
357
|
+
const checkFiltersInner = (filters2) => {
|
|
358
|
+
const filters3 = filters2.filter(ele => !!ele);
|
|
359
|
+
const f = filters3.length > 0 && (0, filter_1.combineFilters)(entity, schema, filters3);
|
|
360
|
+
const checkResultInner = (result2) => {
|
|
361
|
+
if (!result2) {
|
|
362
|
+
if (attrs.length > 1) {
|
|
363
|
+
return cascadelyCheckUpdateFilters(entity, schema, action || 'select', data, filter, matrix, attrs, context);
|
|
358
364
|
}
|
|
359
|
-
|
|
360
|
-
}
|
|
361
|
-
if (!result) {
|
|
362
|
-
if (attrs.length > 1) {
|
|
363
|
-
return cascadelyCheckUpdateFilters(entity, schema, data, filter, matrix, attrs, context);
|
|
365
|
+
throw new types_1.OakAttrCantUpdateException(entity, attrs);
|
|
364
366
|
}
|
|
365
|
-
|
|
367
|
+
};
|
|
368
|
+
if (f) {
|
|
369
|
+
const result = (0, filter_1.checkFilterContains)(entity, context, f, filter, true);
|
|
370
|
+
if (result instanceof Promise) {
|
|
371
|
+
return result.then((r) => checkResultInner(r));
|
|
372
|
+
}
|
|
373
|
+
return checkResultInner(result);
|
|
366
374
|
}
|
|
375
|
+
};
|
|
376
|
+
if (filters.find(ele => ele instanceof Promise)) {
|
|
377
|
+
return Promise.all(filters).then((ff) => checkFiltersInner(ff));
|
|
367
378
|
}
|
|
379
|
+
return checkFiltersInner(filters);
|
|
368
380
|
}
|
|
369
381
|
};
|
|
370
382
|
checkers.push(updateChecker);
|
|
@@ -45,6 +45,12 @@ export type ServerConfiguration = {
|
|
|
45
45
|
headers?: string[];
|
|
46
46
|
methods?: string[];
|
|
47
47
|
};
|
|
48
|
+
ui?: {
|
|
49
|
+
path?: string;
|
|
50
|
+
disable?: boolean;
|
|
51
|
+
username?: string;
|
|
52
|
+
password?: string;
|
|
53
|
+
};
|
|
48
54
|
internalExceptionMask?: string;
|
|
49
55
|
koaBody?: IKoaBodyOptions;
|
|
50
56
|
socket?: (ctx: Koa.ParameterizedContext<any, KoaRouter.IRouterParamContext<any, {}>, any>) => {
|
package/lib/types/Entity.d.ts
CHANGED
|
@@ -182,6 +182,7 @@ export type CascadeRelationAuth<R extends string> = {
|
|
|
182
182
|
[K in R]?: CascadeRelationItem | (CascadeRelationItem | CascadeRelationItem[])[];
|
|
183
183
|
};
|
|
184
184
|
export type SelectOpResult<ED extends EntityDict> = {
|
|
185
|
+
id?: string;
|
|
185
186
|
a: 's';
|
|
186
187
|
d: {
|
|
187
188
|
[T in keyof ED]?: {
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { LocaleDef } from './Locale';
|
|
2
2
|
import { Index } from './Storage';
|
|
3
3
|
import { EntityShape, Configuration, EntityDict } from './Entity';
|
|
4
|
+
import { EntityDict as BaseEntityDict } from '../base-app-domain';
|
|
4
5
|
import { StyleDesc } from './Style';
|
|
6
|
+
import { AsyncContext } from '../store/AsyncRowStore';
|
|
7
|
+
import { SyncContext } from '../store/SyncRowStore';
|
|
8
|
+
import { SyncOrAsync } from './Polyfill';
|
|
5
9
|
export type EntityDesc<Schema extends EntityShape, Action extends string = '', Relation extends string = '', V extends Record<string, string> = {
|
|
6
10
|
['##oak_illegal##']: '';
|
|
7
11
|
}> = {
|
|
@@ -14,11 +18,15 @@ export type EntityDesc<Schema extends EntityShape, Action extends string = '', R
|
|
|
14
18
|
}) : {
|
|
15
19
|
style: StyleDesc<Action, V>;
|
|
16
20
|
});
|
|
17
|
-
export type AttrUpdateMatrix<ED extends EntityDict> = {
|
|
21
|
+
export type AttrUpdateMatrix<ED extends EntityDict & BaseEntityDict> = {
|
|
18
22
|
[T in keyof ED]?: {
|
|
19
23
|
[A in keyof ED[T]['Update']['data']]?: {
|
|
20
24
|
actions?: ED[T]['Action'][];
|
|
21
|
-
filter?: (NonNullable<ED[T]['Filter']>) | ((
|
|
25
|
+
filter?: (NonNullable<ED[T]['Filter']>) | ((option: {
|
|
26
|
+
action: ED[T]['Action'];
|
|
27
|
+
data: ED[T]['Update']['data'];
|
|
28
|
+
filter?: ED[T]['Update']['filter'];
|
|
29
|
+
}, context: AsyncContext<ED> | SyncContext<ED>) => SyncOrAsync<ED[T]['Filter'] | undefined>);
|
|
22
30
|
};
|
|
23
31
|
};
|
|
24
32
|
};
|
|
@@ -189,7 +189,7 @@ class SimpleConnector {
|
|
|
189
189
|
};
|
|
190
190
|
}
|
|
191
191
|
async serializeResult(result, opRecords, headers, body, message) {
|
|
192
|
-
if (result instanceof stream_1.Stream || result instanceof Buffer
|
|
192
|
+
if (result instanceof stream_1.Stream || result instanceof Buffer) {
|
|
193
193
|
return {
|
|
194
194
|
body: result,
|
|
195
195
|
headers: {
|