oak-domain 5.1.22 → 5.1.24
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/compiler/schemalBuilder.d.ts +22 -0
- package/lib/compiler/schemalBuilder.js +153 -1
- package/lib/store/CascadeStore.d.ts +1 -1
- package/lib/store/CascadeStore.js +21 -15
- package/lib/store/IntrinsicCheckers.js +21 -12
- package/lib/store/RelationAuth.js +5 -3
- package/lib/types/Configuration.d.ts +5 -0
- package/lib/types/Entity.d.ts +1 -0
- package/lib/types/EntityDesc.d.ts +10 -2
- package/lib/types/Exception.d.ts +1 -0
- package/lib/types/Exception.js +1 -0
- package/lib/utils/SimpleConnector.d.ts +2 -2
- package/lib/utils/SimpleConnector.js +16 -12
- package/package.json +1 -1
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
import * as ts from 'typescript';
|
|
2
|
+
declare const Schema: Record<string, {
|
|
3
|
+
schemaAttrs: Array<ts.PropertySignature>;
|
|
4
|
+
fulltextIndex?: true;
|
|
5
|
+
indexes?: ts.ArrayLiteralExpression;
|
|
6
|
+
sourceFile: ts.SourceFile;
|
|
7
|
+
enumAttributes: Record<string, string[]>;
|
|
8
|
+
locale: ts.ObjectLiteralExpression;
|
|
9
|
+
toModi: boolean;
|
|
10
|
+
toLog: boolean;
|
|
11
|
+
actionType: string;
|
|
12
|
+
static: boolean;
|
|
13
|
+
inModi: boolean;
|
|
14
|
+
relations: false | string[];
|
|
15
|
+
extendsFrom: string[];
|
|
16
|
+
importAttrFrom: Record<string, [string, string | undefined]>;
|
|
17
|
+
}>;
|
|
18
|
+
export declare function constructAttributes(entity: string): ts.PropertyAssignment[];
|
|
19
|
+
export declare function translateLocaleObject(locale: ts.ObjectLiteralExpression): Record<string, any>;
|
|
1
20
|
/**
|
|
2
21
|
* 此函数不再使用
|
|
3
22
|
* @param map
|
|
@@ -23,6 +42,9 @@ export declare function registerFixedDestinationPathMap(map: Record<string, stri
|
|
|
23
42
|
* @param map
|
|
24
43
|
*/
|
|
25
44
|
export declare function registerDeducedRelationMap(map: Record<string, string>): void;
|
|
45
|
+
export declare const getAnalizedSchema: () => typeof Schema;
|
|
26
46
|
export declare function analyzeEntities(inputDir: string, relativePath?: string): void;
|
|
27
47
|
export declare function buildSchemaBackup(outputDir: string): void;
|
|
48
|
+
export declare function getProjectionKeys(entity: string): string[];
|
|
28
49
|
export declare function buildSchema(outputDir: string): void;
|
|
50
|
+
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.buildSchema = exports.buildSchemaBackup = exports.analyzeEntities = exports.registerDeducedRelationMap = exports.registerFixedDestinationPathMap = exports.registerIgnoredRelationPathMap = exports.registerFreeEntities = exports.registerIgnoredForeignKeyMap = void 0;
|
|
3
|
+
exports.buildSchema = exports.getProjectionKeys = exports.buildSchemaBackup = exports.analyzeEntities = exports.getAnalizedSchema = exports.registerDeducedRelationMap = exports.registerFixedDestinationPathMap = exports.registerIgnoredRelationPathMap = exports.registerFreeEntities = exports.registerIgnoredForeignKeyMap = exports.translateLocaleObject = exports.constructAttributes = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
6
6
|
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
@@ -2256,6 +2256,64 @@ function _constructOpProjection(statements, entity) {
|
|
|
2256
2256
|
exprNode,
|
|
2257
2257
|
])));
|
|
2258
2258
|
}
|
|
2259
|
+
function getOpProjectionKeys(entity) {
|
|
2260
|
+
const { schemaAttrs, enumAttributes } = Schema[entity];
|
|
2261
|
+
const { [entity]: manyToOneSet } = ManyToOne;
|
|
2262
|
+
const result = [
|
|
2263
|
+
'id',
|
|
2264
|
+
'$$createAt$$',
|
|
2265
|
+
'$$updateAt$$',
|
|
2266
|
+
'$$seq$$',
|
|
2267
|
+
];
|
|
2268
|
+
for (const attr of schemaAttrs) {
|
|
2269
|
+
const { type, name } = attr;
|
|
2270
|
+
const attrName = name.text;
|
|
2271
|
+
if (ts.isTypeReferenceNode(type)) {
|
|
2272
|
+
const { typeName } = type;
|
|
2273
|
+
if (ts.isIdentifier(typeName)) {
|
|
2274
|
+
const typeStr = typeName.text;
|
|
2275
|
+
switch (typeStr) {
|
|
2276
|
+
case 'String':
|
|
2277
|
+
case 'Text':
|
|
2278
|
+
case 'Int':
|
|
2279
|
+
case 'Uint':
|
|
2280
|
+
case 'Float':
|
|
2281
|
+
case 'Double':
|
|
2282
|
+
case 'Boolean':
|
|
2283
|
+
case 'Datetime':
|
|
2284
|
+
case 'Image':
|
|
2285
|
+
case 'File':
|
|
2286
|
+
case 'SingleGeo':
|
|
2287
|
+
case 'Geo':
|
|
2288
|
+
case 'Price':
|
|
2289
|
+
case 'Decimal':
|
|
2290
|
+
result.push(attrName);
|
|
2291
|
+
break;
|
|
2292
|
+
case 'Object':
|
|
2293
|
+
result.push(attrName);
|
|
2294
|
+
break;
|
|
2295
|
+
default: {
|
|
2296
|
+
const refEntity = typeStr === 'Schema' ? entity : typeStr;
|
|
2297
|
+
const isManyToOne = manyToOneSet?.some(([e]) => e === refEntity);
|
|
2298
|
+
if (isManyToOne) {
|
|
2299
|
+
result.push(`${attrName}Id`);
|
|
2300
|
+
}
|
|
2301
|
+
else if (!enumAttributes?.[attrName]) {
|
|
2302
|
+
result.push(attrName);
|
|
2303
|
+
}
|
|
2304
|
+
else {
|
|
2305
|
+
result.push(attrName);
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
else {
|
|
2312
|
+
result.push(attrName);
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
return result;
|
|
2316
|
+
}
|
|
2259
2317
|
/**
|
|
2260
2318
|
* 构造Query
|
|
2261
2319
|
* @param statements
|
|
@@ -3951,6 +4009,26 @@ function constructAttributes(entity) {
|
|
|
3951
4009
|
});
|
|
3952
4010
|
return result;
|
|
3953
4011
|
}
|
|
4012
|
+
exports.constructAttributes = constructAttributes;
|
|
4013
|
+
function translateLocaleObject(locale) {
|
|
4014
|
+
const result = {};
|
|
4015
|
+
locale.properties.forEach((ele) => {
|
|
4016
|
+
(0, assert_1.default)(ts.isPropertyAssignment(ele) && (ts.isIdentifier(ele.name) || ts.isStringLiteral(ele.name)), `locale对象中的属性定义不正确`);
|
|
4017
|
+
const name = ele.name.text;
|
|
4018
|
+
if (ts.isStringLiteral(ele.initializer)) {
|
|
4019
|
+
result[name] = ele.initializer.text;
|
|
4020
|
+
}
|
|
4021
|
+
else if (ts.isObjectLiteralExpression(ele.initializer)) {
|
|
4022
|
+
const subObj = translateLocaleObject(ele.initializer);
|
|
4023
|
+
result[name] = subObj;
|
|
4024
|
+
}
|
|
4025
|
+
else {
|
|
4026
|
+
throw new Error(`locale对象中的属性${name}的定义不正确`);
|
|
4027
|
+
}
|
|
4028
|
+
});
|
|
4029
|
+
return result;
|
|
4030
|
+
}
|
|
4031
|
+
exports.translateLocaleObject = translateLocaleObject;
|
|
3954
4032
|
function outputLocale(outputDir, printer) {
|
|
3955
4033
|
const locales = {};
|
|
3956
4034
|
const entities = [];
|
|
@@ -4768,6 +4846,10 @@ function outputStyleDict(outputDir, printer) {
|
|
|
4768
4846
|
const filename = path_1.default.join(outputDir, 'StyleDict.ts');
|
|
4769
4847
|
(0, fs_1.writeFileSync)(filename, result, { flag: 'w' });
|
|
4770
4848
|
}
|
|
4849
|
+
const getAnalizedSchema = () => {
|
|
4850
|
+
return Schema;
|
|
4851
|
+
};
|
|
4852
|
+
exports.getAnalizedSchema = getAnalizedSchema;
|
|
4771
4853
|
function analyzeEntities(inputDir, relativePath) {
|
|
4772
4854
|
const files = (0, fs_1.readdirSync)(inputDir);
|
|
4773
4855
|
const fullFilenames = files.map(ele => {
|
|
@@ -5474,6 +5556,76 @@ function _outputEntityDict(outputDir, printer) {
|
|
|
5474
5556
|
const fileName = path_1.default.join(outputDir, 'EntityDict.ts');
|
|
5475
5557
|
(0, fs_1.writeFileSync)(fileName, result, { flag: 'w' });
|
|
5476
5558
|
}
|
|
5559
|
+
function getProjectionKeys(entity) {
|
|
5560
|
+
const keys = [];
|
|
5561
|
+
const { schemaAttrs } = Schema[entity];
|
|
5562
|
+
const { [entity]: manyToOneSet = [] } = ManyToOne;
|
|
5563
|
+
for (const attr of schemaAttrs) {
|
|
5564
|
+
const { type, name } = attr;
|
|
5565
|
+
const attrName = name.text;
|
|
5566
|
+
if (ts.isTypeReferenceNode(type)) {
|
|
5567
|
+
const typeName = type.typeName;
|
|
5568
|
+
if (ts.isIdentifier(typeName)) {
|
|
5569
|
+
const text = typeName.text;
|
|
5570
|
+
switch (text) {
|
|
5571
|
+
case 'String':
|
|
5572
|
+
case 'Text':
|
|
5573
|
+
case 'Int':
|
|
5574
|
+
case 'Uint':
|
|
5575
|
+
case 'Float':
|
|
5576
|
+
case 'Double':
|
|
5577
|
+
case 'Boolean':
|
|
5578
|
+
case 'Datetime':
|
|
5579
|
+
case 'Image':
|
|
5580
|
+
case 'File':
|
|
5581
|
+
case 'SingleGeo':
|
|
5582
|
+
case 'Geo':
|
|
5583
|
+
case 'Price':
|
|
5584
|
+
case 'Decimal':
|
|
5585
|
+
case 'Object':
|
|
5586
|
+
break;
|
|
5587
|
+
default:
|
|
5588
|
+
const text2 = text === 'Schema' ? entity : text;
|
|
5589
|
+
const manyToOneItem = manyToOneSet.find(([refEntity]) => refEntity === text2);
|
|
5590
|
+
if (manyToOneItem) {
|
|
5591
|
+
keys.push(attrName); // 外键属性
|
|
5592
|
+
}
|
|
5593
|
+
}
|
|
5594
|
+
}
|
|
5595
|
+
}
|
|
5596
|
+
}
|
|
5597
|
+
if (ReversePointerRelations[entity]) {
|
|
5598
|
+
for (const one of ReversePointerRelations[entity]) {
|
|
5599
|
+
const text2 = one === 'Schema' ? entity : one;
|
|
5600
|
+
keys.push((0, string_1.firstLetterLowerCase)(one));
|
|
5601
|
+
}
|
|
5602
|
+
}
|
|
5603
|
+
const { [entity]: oneToManySet = [] } = OneToMany;
|
|
5604
|
+
const foreignKeySet = {};
|
|
5605
|
+
for (const [entityName, foreignKey] of oneToManySet) {
|
|
5606
|
+
if (!foreignKeySet[entityName]) {
|
|
5607
|
+
foreignKeySet[entityName] = [];
|
|
5608
|
+
}
|
|
5609
|
+
foreignKeySet[entityName].push(foreignKey);
|
|
5610
|
+
}
|
|
5611
|
+
for (const entityName in foreignKeySet) {
|
|
5612
|
+
const entityNameLc = (0, string_1.firstLetterLowerCase)(entityName);
|
|
5613
|
+
for (const foreignKey of foreignKeySet[entityName]) {
|
|
5614
|
+
const identifier = `${entityNameLc}$${foreignKey}`;
|
|
5615
|
+
keys.push(identifier);
|
|
5616
|
+
const aggrKey = _getAggrKey(entityNameLc, foreignKey);
|
|
5617
|
+
if (typeof aggrKey === 'string') {
|
|
5618
|
+
keys.push(aggrKey);
|
|
5619
|
+
}
|
|
5620
|
+
else {
|
|
5621
|
+
// 如果是 union 类型,用映射表达式模拟(如 ["xxx$$aggr", `xxx$$${number}$$aggr`])
|
|
5622
|
+
keys.push(`${identifier}$$aggr`);
|
|
5623
|
+
}
|
|
5624
|
+
}
|
|
5625
|
+
}
|
|
5626
|
+
return [...new Set([...keys, ...getOpProjectionKeys(entity)])];
|
|
5627
|
+
}
|
|
5628
|
+
exports.getProjectionKeys = getProjectionKeys;
|
|
5477
5629
|
function _outputSchema(outputDir, printer) {
|
|
5478
5630
|
for (const entity in Schema) {
|
|
5479
5631
|
const statements = [
|
|
@@ -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));
|
|
@@ -352,7 +361,7 @@ function createAttrUpdateCheckers(schema, attrUpdateMatrix) {
|
|
|
352
361
|
return result.then((v) => {
|
|
353
362
|
if (!v) {
|
|
354
363
|
if (attrs.length > 1) {
|
|
355
|
-
return cascadelyCheckUpdateFilters(entity, schema, data, filter, matrix, attrs, context);
|
|
364
|
+
return cascadelyCheckUpdateFilters(entity, schema, action || 'select', data, filter, matrix, attrs, context);
|
|
356
365
|
}
|
|
357
366
|
throw new types_1.OakAttrCantUpdateException(entity, attrs);
|
|
358
367
|
}
|
|
@@ -360,7 +369,7 @@ function createAttrUpdateCheckers(schema, attrUpdateMatrix) {
|
|
|
360
369
|
}
|
|
361
370
|
if (!result) {
|
|
362
371
|
if (attrs.length > 1) {
|
|
363
|
-
return cascadelyCheckUpdateFilters(entity, schema, data, filter, matrix, attrs, context);
|
|
372
|
+
return cascadelyCheckUpdateFilters(entity, schema, action || 'select', data, filter, matrix, attrs, context);
|
|
364
373
|
}
|
|
365
374
|
throw new types_1.OakAttrCantUpdateException(entity, attrs, '更新的行当前属性不满足约束,请仔细检查数据');
|
|
366
375
|
}
|
|
@@ -1045,6 +1045,11 @@ class RelationAuth {
|
|
|
1045
1045
|
if (actionAuths && actionAuths.length > 0) {
|
|
1046
1046
|
return checkChildren(actionAuths);
|
|
1047
1047
|
}
|
|
1048
|
+
// 如果这个entity是updateFree,直接过掉到子结点判定
|
|
1049
|
+
const { action, entity } = node;
|
|
1050
|
+
if (this.updateFreeDict[entity] && this.updateFreeDict[entity].includes(action)) {
|
|
1051
|
+
return checkChildren([]);
|
|
1052
|
+
}
|
|
1048
1053
|
// 没有能根据父亲传下来的actionAuth判定,只能自己找
|
|
1049
1054
|
const result = this.findActionAuthsOnNode(node, context);
|
|
1050
1055
|
const checkResult = (result2) => {
|
|
@@ -1083,9 +1088,6 @@ class RelationAuth {
|
|
|
1083
1088
|
}
|
|
1084
1089
|
checkOperation(entity, operation, context) {
|
|
1085
1090
|
const { action, filter, data } = operation;
|
|
1086
|
-
if (this.updateFreeDict[entity] && this.updateFreeDict[entity].includes(action)) {
|
|
1087
|
-
return true;
|
|
1088
|
-
}
|
|
1089
1091
|
const userId = context.getCurrentUserId();
|
|
1090
1092
|
if (!userId) {
|
|
1091
1093
|
throw new types_1.OakUnloggedInException();
|
|
@@ -45,6 +45,11 @@ export type ServerConfiguration = {
|
|
|
45
45
|
headers?: string[];
|
|
46
46
|
methods?: string[];
|
|
47
47
|
};
|
|
48
|
+
ui?: {
|
|
49
|
+
disable?: boolean;
|
|
50
|
+
username?: string;
|
|
51
|
+
password?: string;
|
|
52
|
+
};
|
|
48
53
|
internalExceptionMask?: string;
|
|
49
54
|
koaBody?: IKoaBodyOptions;
|
|
50
55
|
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
|
};
|
package/lib/types/Exception.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare class OakException<ED extends EntityDict & BaseEntityDict> extend
|
|
|
12
12
|
name: string;
|
|
13
13
|
message: string;
|
|
14
14
|
_module: string | undefined;
|
|
15
|
+
params: Record<string, any> | undefined;
|
|
15
16
|
opRecords: OpRecord<ED>[];
|
|
16
17
|
tag1: string | undefined;
|
|
17
18
|
tag2: boolean | undefined;
|
package/lib/types/Exception.js
CHANGED
|
@@ -36,7 +36,7 @@ export default class SimpleConnector<ED extends EntityDict & BaseEntityDict, Fro
|
|
|
36
36
|
opRecords: any;
|
|
37
37
|
message: string | null;
|
|
38
38
|
} | {
|
|
39
|
-
result:
|
|
39
|
+
result: ReadableStream<Uint8Array> | null;
|
|
40
40
|
message: string | null;
|
|
41
41
|
opRecords?: undefined;
|
|
42
42
|
}>;
|
|
@@ -45,7 +45,7 @@ export default class SimpleConnector<ED extends EntityDict & BaseEntityDict, Fro
|
|
|
45
45
|
opRecords: any;
|
|
46
46
|
message: string | null;
|
|
47
47
|
} | {
|
|
48
|
-
result:
|
|
48
|
+
result: ReadableStream<Uint8Array> | null;
|
|
49
49
|
message: string | null;
|
|
50
50
|
opRecords?: undefined;
|
|
51
51
|
}>;
|
|
@@ -81,8 +81,7 @@ class SimpleConnector {
|
|
|
81
81
|
throw new types_1.OakServerProxyException(`网络请求返回status是${response.status}`);
|
|
82
82
|
}
|
|
83
83
|
const message = response.headers.get('oak-message');
|
|
84
|
-
const responseType = response.headers.get('Content-Type') ||
|
|
85
|
-
response.headers.get('content-type');
|
|
84
|
+
const responseType = response.headers.get('Content-Type') || response.headers.get('content-type');
|
|
86
85
|
if (responseType?.toLocaleLowerCase().match(/application\/json/i)) {
|
|
87
86
|
const { exception, result, opRecords } = await response.json();
|
|
88
87
|
if (exception) {
|
|
@@ -94,18 +93,24 @@ class SimpleConnector {
|
|
|
94
93
|
message,
|
|
95
94
|
};
|
|
96
95
|
}
|
|
97
|
-
else if (
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
// else if (
|
|
97
|
+
// responseType
|
|
98
|
+
// ?.toLocaleLowerCase()
|
|
99
|
+
// .match(/application\/octet-stream/i)
|
|
100
|
+
// ) {
|
|
101
|
+
// const result = await response.arrayBuffer();
|
|
102
|
+
// return {
|
|
103
|
+
// result,
|
|
104
|
+
// message,
|
|
105
|
+
// };
|
|
106
|
+
// }
|
|
107
|
+
else {
|
|
108
|
+
const result = response.body;
|
|
101
109
|
return {
|
|
102
110
|
result,
|
|
103
111
|
message,
|
|
104
112
|
};
|
|
105
113
|
}
|
|
106
|
-
else {
|
|
107
|
-
throw new Error(`尚不支持的content-type类型${responseType}`);
|
|
108
|
-
}
|
|
109
114
|
}
|
|
110
115
|
async callAspect(name, params, context) {
|
|
111
116
|
const { headers, body } = await this.makeHeadersAndBody(name, params, context);
|
|
@@ -153,8 +158,7 @@ class SimpleConnector {
|
|
|
153
158
|
throw new types_1.OakServerProxyException(`网络请求返回status是${response.status}`);
|
|
154
159
|
}
|
|
155
160
|
const message = response.headers.get('oak-message');
|
|
156
|
-
const responseType = response.headers.get('Content-Type') ||
|
|
157
|
-
response.headers.get('content-type');
|
|
161
|
+
const responseType = response.headers.get('Content-Type') || response.headers.get('content-type');
|
|
158
162
|
if (responseType?.toLocaleLowerCase().match(/application\/json/i)) {
|
|
159
163
|
const { socketUrl, subscribeUrl, path } = await response.json();
|
|
160
164
|
return {
|
|
@@ -185,7 +189,7 @@ class SimpleConnector {
|
|
|
185
189
|
};
|
|
186
190
|
}
|
|
187
191
|
async serializeResult(result, opRecords, headers, body, message) {
|
|
188
|
-
if (result instanceof stream_1.Stream || result instanceof Buffer) {
|
|
192
|
+
if (result instanceof stream_1.Stream || result instanceof Buffer || result instanceof ReadableStream) {
|
|
189
193
|
return {
|
|
190
194
|
body: result,
|
|
191
195
|
headers: {
|