修正了judgeRelation的一个bug

This commit is contained in:
Xu Chang 2023-01-08 18:09:34 +08:00
parent 98bd993d02
commit 6a3a670324
7 changed files with 314 additions and 143 deletions

View File

@ -15,7 +15,7 @@ export declare abstract class CascadeStore<ED extends EntityDict & BaseEntityDic
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>;
protected abstract aggregateSync<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']>;
protected abstract aggregateAsync<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']>>;
protected destructCascadeSelect<T extends keyof ED, OP extends SelectOption, Cxt extends SyncContext<ED> | AsyncContext<ED>>(entity: T, projection2: ED[T]['Selection']['data'], 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']>[]>, option: OP): {
protected destructCascadeSelect<T extends keyof ED, OP extends SelectOption, Cxt extends SyncContext<ED> | AsyncContext<ED>>(entity: T, projection2: ED[T]['Selection']['data'], 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): {
projection: ED[T]["Selection"]["data"];
cascadeSelectionFns: ((result: Partial<ED[T]['Schema']>[]) => Promise<void> | void)[];
};

View File

@ -17,7 +17,7 @@ var CascadeStore = /** @class */ (function (_super) {
function CascadeStore(storageSchema) {
return _super.call(this, storageSchema) || this;
}
CascadeStore.prototype.destructCascadeSelect = function (entity, projection2, context, cascadeSelectFn, option) {
CascadeStore.prototype.destructCascadeSelect = function (entity, projection2, context, cascadeSelectFn, aggregateFn, option) {
var _this = this;
var projection = {};
var cascadeSelectionFns = [];
@ -58,7 +58,7 @@ var CascadeStore = /** @class */ (function (_super) {
});
}
});
var _e = this_1.destructCascadeSelect(attr, projection2[attr], context, cascadeSelectFn, option), subProjection = _e.projection, subCascadeSelectionFns = _e.cascadeSelectionFns;
var _e = this_1.destructCascadeSelect(attr, projection2[attr], context, cascadeSelectFn, aggregateFn, option), subProjection = _e.projection, subCascadeSelectionFns = _e.cascadeSelectionFns;
Object.assign(projection, (_b = {},
_b[attr] = subProjection,
_b));
@ -143,7 +143,7 @@ var CascadeStore = /** @class */ (function (_super) {
}
});
}
var _f = this_1.destructCascadeSelect(relation, projection2[attr], context, cascadeSelectFn, option), subProjection = _f.projection, subCascadeSelectionFns = _f.cascadeSelectionFns;
var _f = this_1.destructCascadeSelect(relation, projection2[attr], context, cascadeSelectFn, aggregateFn, option), subProjection = _f.projection, subCascadeSelectionFns = _f.cascadeSelectionFns;
Object.assign(projection, (_d = {},
_d[attr] = subProjection,
_d));
@ -210,69 +210,143 @@ var CascadeStore = /** @class */ (function (_super) {
(0, assert_1.default)(relation instanceof Array);
var _g = projection2[attr], subProjection_1 = _g.data, subFilter_1 = _g.filter, indexFrom_1 = _g.indexFrom, count_1 = _g.count, subSorter_1 = _g.sorter;
var _h = tslib_1.__read(relation, 2), entity2_1 = _h[0], foreignKey_1 = _h[1];
var isAggr = attr.endsWith('$$aggr');
if (foreignKey_1) {
// 基于属性的一对多
cascadeSelectionFns.push(function (result) {
var _a;
var ids = result.map(function (ele) { return ele.id; });
var dealWithSubRows = function (subRows) {
result.forEach(function (ele) {
var _a;
var subRowss = subRows.filter(function (ele2) { return ele2[foreignKey_1] === ele.id; });
(0, assert_1.default)(subRowss);
Object.assign(ele, (_a = {},
_a[attr] = subRowss,
_a));
if (isAggr) {
// 是聚合运算
cascadeSelectionFns.push(function (result) {
var aggrResults = result.map(function (row) {
var _a, _b;
var aggrResult = aggregateFn.call(_this, entity2_1, {
data: subProjection_1,
filter: (0, filter_1.combineFilters)([(_a = {},
_a[foreignKey_1] = row.id,
_a), subFilter_1]),
sorter: subSorter_1,
indexFrom: indexFrom_1,
count: count_1
}, context, option);
if (aggrResult instanceof Promise) {
return aggrResult.then(function (aggrResultResult) {
var _a;
return Object.assign(row, (_a = {},
_a[attr] = aggrResultResult,
_a));
});
}
else {
Object.assign(row, (_b = {},
_b[attr] = aggrResult,
_b));
}
});
};
var subRows = cascadeSelectFn.call(_this, entity2_1, {
data: subProjection_1,
filter: (0, filter_1.combineFilters)([(_a = {},
_a[foreignKey_1] = {
$in: ids,
},
_a), subFilter_1]),
sorter: subSorter_1,
indexFrom: indexFrom_1,
count: count_1
}, context, option);
if (subRows instanceof Promise) {
return subRows.then(function (subRowss) { return dealWithSubRows(subRowss); });
}
dealWithSubRows(subRows);
});
if (aggrResults.length > 0 && aggrResults[0] instanceof Promise) {
return Promise.all(aggrResults).then(function () { return undefined; });
}
});
}
else {
// 是一对多查询
cascadeSelectionFns.push(function (result) {
var _a;
var ids = result.map(function (ele) { return ele.id; });
var dealWithSubRows = function (subRows) {
result.forEach(function (ele) {
var _a;
var subRowss = subRows.filter(function (ele2) { return ele2[foreignKey_1] === ele.id; });
(0, assert_1.default)(subRowss);
Object.assign(ele, (_a = {},
_a[attr] = subRowss,
_a));
});
};
var subRows = cascadeSelectFn.call(_this, entity2_1, {
data: subProjection_1,
filter: (0, filter_1.combineFilters)([(_a = {},
_a[foreignKey_1] = {
$in: ids,
},
_a), subFilter_1]),
sorter: subSorter_1,
indexFrom: indexFrom_1,
count: count_1
}, context, option);
if (subRows instanceof Promise) {
return subRows.then(function (subRowss) { return dealWithSubRows(subRowss); });
}
dealWithSubRows(subRows);
});
}
}
else {
// 基于entity的多对一
cascadeSelectionFns.push(function (result) {
var ids = result.map(function (ele) { return ele.id; });
var dealWithSubRows = function (subRows) {
result.forEach(function (ele) {
if (isAggr) {
// 是聚合运算
cascadeSelectionFns.push(function (result) {
var aggrResults = result.map(function (row) {
var _a;
var subRowss = subRows.filter(function (ele2) { return ele2.entityId === ele.id; });
(0, assert_1.default)(subRowss);
Object.assign(ele, (_a = {},
_a[attr] = subRowss,
_a));
var aggrResult = aggregateFn.call(_this, entity2_1, {
data: subProjection_1,
filter: (0, filter_1.combineFilters)([{
entity: entity,
entityId: row.id,
}, subFilter_1]),
sorter: subSorter_1,
indexFrom: indexFrom_1,
count: count_1
}, context, option);
if (aggrResult instanceof Promise) {
return aggrResult.then(function (aggrResultResult) {
var _a;
return Object.assign(row, (_a = {},
_a[attr] = aggrResultResult,
_a));
});
}
else {
Object.assign(row, (_a = {},
_a[attr] = aggrResult,
_a));
}
});
};
var subRows = cascadeSelectFn.call(_this, entity2_1, {
data: subProjection_1,
filter: (0, filter_1.combineFilters)([{
entity: entity,
entityId: {
$in: ids,
}
}, subFilter_1]),
sorter: subSorter_1,
indexFrom: indexFrom_1,
count: count_1
}, context, option);
if (subRows instanceof Promise) {
return subRows.then(function (subRowss) { return dealWithSubRows(subRowss); });
}
dealWithSubRows(subRows);
});
if (aggrResults.length > 0 && aggrResults[0] instanceof Promise) {
return Promise.all(aggrResults).then(function () { return undefined; });
}
});
}
else {
// 是一对多查询
cascadeSelectionFns.push(function (result) {
var ids = result.map(function (ele) { return ele.id; });
var dealWithSubRows = function (subRows) {
result.forEach(function (ele) {
var _a;
var subRowss = subRows.filter(function (ele2) { return ele2.entityId === ele.id; });
(0, assert_1.default)(subRowss);
Object.assign(ele, (_a = {},
_a[attr] = subRowss,
_a));
});
};
var subRows = cascadeSelectFn.call(_this, entity2_1, {
data: subProjection_1,
filter: (0, filter_1.combineFilters)([{
entity: entity,
entityId: {
$in: ids,
}
}, subFilter_1]),
sorter: subSorter_1,
indexFrom: indexFrom_1,
count: count_1
}, context, option);
if (subRows instanceof Promise) {
return subRows.then(function (subRowss) { return dealWithSubRows(subRowss); });
}
dealWithSubRows(subRows);
});
}
}
}
};
@ -1339,7 +1413,7 @@ var CascadeStore = /** @class */ (function (_super) {
};
CascadeStore.prototype.cascadeSelect = function (entity, selection, context, option) {
var data = selection.data, filter = selection.filter, indexFrom = selection.indexFrom, count = selection.count, sorter = selection.sorter;
var _a = this.destructCascadeSelect(entity, data, context, this.cascadeSelect, option), projection = _a.projection, cascadeSelectionFns = _a.cascadeSelectionFns;
var _a = this.destructCascadeSelect(entity, data, context, this.cascadeSelect, this.aggregateSync, option), projection = _a.projection, cascadeSelectionFns = _a.cascadeSelectionFns;
var rows = this.selectAbjointRow(entity, {
data: projection,
filter: filter,
@ -1460,7 +1534,7 @@ var CascadeStore = /** @class */ (function (_super) {
switch (_b.label) {
case 0:
data = selection.data, filter = selection.filter, indexFrom = selection.indexFrom, count = selection.count, sorter = selection.sorter;
_a = this.destructCascadeSelect(entity, data, context, this.cascadeSelectAsync, option), projection = _a.projection, cascadeSelectionFns = _a.cascadeSelectionFns;
_a = this.destructCascadeSelect(entity, data, context, this.cascadeSelectAsync, this.aggregateAsync, option), projection = _a.projection, cascadeSelectionFns = _a.cascadeSelectionFns;
return [4 /*yield*/, this.selectAbjointRowAsync(entity, {
data: projection,
filter: filter,

View File

@ -27,7 +27,8 @@ function judgeRelation(schema, entity, attr) {
var firstDelimiter = attr.indexOf('$');
var entity2 = attr.slice(0, firstDelimiter);
(0, assert_1.default)(schema.hasOwnProperty(entity2));
var foreignKey = attr.slice(firstDelimiter + 1, attr.indexOf('$', firstDelimiter + 1));
var secondDelemiter = attr.indexOf('$', firstDelimiter + 1);
var foreignKey = attr.slice(firstDelimiter + 1, secondDelemiter > 0 ? secondDelemiter : attr.length);
var _c = schema, _d = entity2, attributes2 = _c[_d].attributes;
if (foreignKey === 'entity') {
// 基于反指对象的反向关联

View File

@ -181,7 +181,7 @@ function reinforceSelection(schema, entity, selection) {
necessaryAttrs.push("".concat(attr, "Id"));
checkProjectionNode(rel, projectionNode[attr]);
}
else if (rel instanceof Array) {
else if (rel instanceof Array && !attr.endsWith('$$aggr')) {
var data_1 = projectionNode[attr].data;
if (rel[1]) {
checkNode(data_1, [rel[1]]);
@ -189,7 +189,7 @@ function reinforceSelection(schema, entity, selection) {
else {
checkNode(data_1, ['entity', 'entityId']);
}
checkProjectionNode(rel[0], data_1);
reinforceSelection(schema, rel[0], projectionNode[attr]);
}
}
}

View File

@ -66,6 +66,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
projection2: ED[T]['Selection']['data'],
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) {
const projection: ED[T]['Selection']['data'] = {};
const cascadeSelectionFns: Array<(result: Partial<ED[T]['Schema']>[]) => Promise<void> | void> = [];
@ -114,7 +115,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
const {
projection: subProjection,
cascadeSelectionFns: subCascadeSelectionFns,
} = this.destructCascadeSelect(attr, projection2[attr], context, cascadeSelectFn, option);
} = this.destructCascadeSelect(attr, projection2[attr], context, cascadeSelectFn, aggregateFn, option);
Object.assign(projection, {
[attr]: subProjection,
});
@ -223,7 +224,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
const {
projection: subProjection,
cascadeSelectionFns: subCascadeSelectionFns,
} = this.destructCascadeSelect(relation, projection2[attr], context, cascadeSelectFn, option);
} = this.destructCascadeSelect(relation, projection2[attr], context, cascadeSelectFn, aggregateFn, option);
Object.assign(projection, {
[attr]: subProjection,
});
@ -307,89 +308,171 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
assert(relation instanceof Array);
const { data: subProjection, filter: subFilter, indexFrom, count, sorter: subSorter } = projection2[attr];
const [entity2, foreignKey] = relation;
const isAggr = attr.endsWith('$$aggr');
if (foreignKey) {
// 基于属性的一对多
cascadeSelectionFns.push(
(result) => {
const ids = result.map(
ele => ele.id
) as string[];
const dealWithSubRows = (subRows: Partial<ED[keyof ED]['Schema']>[]) => {
result.forEach(
(ele) => {
const subRowss = subRows.filter(
ele2 => ele2[foreignKey] === ele.id
);
assert(subRowss);
Object.assign(ele, {
[attr]: subRowss,
});
if (isAggr) {
// 是聚合运算
cascadeSelectionFns.push(
(result) => {
const aggrResults = result.map(
(row) => {
const aggrResult = aggregateFn.call(this, entity2, {
data: subProjection,
filter: combineFilters([{
[foreignKey]: row.id,
}, subFilter]),
sorter: subSorter,
indexFrom,
count
}, context, option);
if (aggrResult instanceof Promise) {
return aggrResult.then(
(aggrResultResult) => Object.assign(row, {
[attr]: aggrResultResult,
})
);
}
else {
Object.assign(row, {
[attr]: aggrResult,
});
}
}
);
};
const subRows = cascadeSelectFn.call(this, entity2, {
data: subProjection,
filter: combineFilters([{
[foreignKey]: {
$in: ids,
}
}, subFilter]),
sorter: subSorter,
indexFrom,
count
}, context, option);
if (subRows instanceof Promise) {
return subRows.then(
(subRowss) => dealWithSubRows(subRowss)
);
if (aggrResults.length > 0 && aggrResults[0] instanceof Promise) {
return Promise.all(aggrResults).then(
() => undefined
);
}
}
dealWithSubRows(subRows as any);
}
);
);
}
else {
// 是一对多查询
cascadeSelectionFns.push(
(result) => {
const ids = result.map(
ele => ele.id
) as string[];
const dealWithSubRows = (subRows: Partial<ED[keyof ED]['Schema']>[]) => {
result.forEach(
(ele) => {
const subRowss = subRows.filter(
ele2 => ele2[foreignKey] === ele.id
);
assert(subRowss);
Object.assign(ele, {
[attr]: subRowss,
});
}
);
};
const subRows = cascadeSelectFn.call(this, entity2, {
data: subProjection,
filter: combineFilters([{
[foreignKey]: {
$in: ids,
}
}, subFilter]),
sorter: subSorter,
indexFrom,
count
}, context, option);
if (subRows instanceof Promise) {
return subRows.then(
(subRowss) => dealWithSubRows(subRowss)
);
}
dealWithSubRows(subRows as any);
}
);
}
}
else {
// 基于entity的多对一
cascadeSelectionFns.push(
(result) => {
const ids = result.map(
ele => ele.id
) as string[];
const dealWithSubRows = (subRows: Partial<ED[T]['Schema']>[]) => {
result.forEach(
(ele) => {
const subRowss = subRows.filter(
ele2 => ele2.entityId === ele.id
);
assert(subRowss);
Object.assign(ele, {
[attr]: subRowss,
});
if (isAggr) {
// 是聚合运算
cascadeSelectionFns.push(
(result) => {
const aggrResults = result.map(
(row) => {
const aggrResult = aggregateFn.call(this, entity2, {
data: subProjection,
filter: combineFilters([{
entity,
entityId: row.id,
}, subFilter]),
sorter: subSorter,
indexFrom,
count
}, context, option);
if (aggrResult instanceof Promise) {
return aggrResult.then(
(aggrResultResult) => Object.assign(row, {
[attr]: aggrResultResult,
})
);
}
else {
Object.assign(row, {
[attr]: aggrResult,
});
}
}
);
};
const subRows = cascadeSelectFn.call(this, entity2, {
data: subProjection,
filter: combineFilters([{
entity,
entityId: {
$in: ids,
}
}, subFilter]),
sorter: subSorter,
indexFrom,
count
}, context, option);
if (subRows instanceof Promise) {
return subRows.then(
(subRowss) => dealWithSubRows(subRowss)
);
if (aggrResults.length > 0 && aggrResults[0] instanceof Promise) {
return Promise.all(aggrResults).then(
() => undefined
);
}
}
dealWithSubRows(subRows as any);
}
);
);
}
else {
// 是一对多查询
cascadeSelectionFns.push(
(result) => {
const ids = result.map(
ele => ele.id
) as string[];
const dealWithSubRows = (subRows: Partial<ED[T]['Schema']>[]) => {
result.forEach(
(ele) => {
const subRowss = subRows.filter(
ele2 => ele2.entityId === ele.id
);
assert(subRowss);
Object.assign(ele, {
[attr]: subRowss,
});
}
);
};
const subRows = cascadeSelectFn.call(this, entity2, {
data: subProjection,
filter: combineFilters([{
entity,
entityId: {
$in: ids,
}
}, subFilter]),
sorter: subSorter,
indexFrom,
count
}, context, option);
if (subRows instanceof Promise) {
return subRows.then(
(subRowss) => dealWithSubRows(subRowss)
);
}
dealWithSubRows(subRows as any);
}
);
}
}
}
}
@ -1339,7 +1422,13 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
context: Cxt,
option: OP): Partial<ED[T]['Schema']>[] {
const { data, filter, indexFrom, count, sorter } = selection;
const { projection, cascadeSelectionFns } = this.destructCascadeSelect(entity, data, context, this.cascadeSelect, option);
const { projection, cascadeSelectionFns } = this.destructCascadeSelect(
entity,
data,
context,
this.cascadeSelect,
this.aggregateSync,
option);
const rows = this.selectAbjointRow(entity, {
data: projection,
@ -1472,7 +1561,13 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
context: Cxt,
option: OP): Promise<Partial<ED[T]['Schema']>[]> {
const { data, filter, indexFrom, count, sorter } = selection;
const { projection, cascadeSelectionFns } = this.destructCascadeSelect(entity, data, context, this.cascadeSelectAsync, option);
const { projection, cascadeSelectionFns } = this.destructCascadeSelect(
entity,
data,
context,
this.cascadeSelectAsync,
this.aggregateAsync,
option);
const rows = await this.selectAbjointRowAsync(entity, {
data: projection,

View File

@ -30,7 +30,8 @@ export function judgeRelation<ED extends {
const firstDelimiter = attr.indexOf('$');
const entity2 = attr.slice(0, firstDelimiter);
assert (schema.hasOwnProperty(entity2));
const foreignKey = attr.slice(firstDelimiter + 1, attr.indexOf('$', firstDelimiter + 1));
const secondDelemiter = attr.indexOf('$', firstDelimiter + 1);
const foreignKey = attr.slice(firstDelimiter + 1, secondDelemiter > 0 ? secondDelemiter : attr.length);
const { [entity2]: { attributes: attributes2 } } = schema;
if (foreignKey === 'entity') {

View File

@ -177,7 +177,7 @@ export function reinforceSelection<ED extends EntityDict>(schema: StorageSchema<
necessaryAttrs.push(`${attr}Id`);
checkProjectionNode(rel, projectionNode[attr]);
}
else if (rel instanceof Array) {
else if (rel instanceof Array && !attr.endsWith('$$aggr')) {
const { data } = projectionNode[attr];
if (rel[1]) {
checkNode(data, [rel[1]]);
@ -185,7 +185,7 @@ export function reinforceSelection<ED extends EntityDict>(schema: StorageSchema<
else {
checkNode(data, ['entity', 'entityId']);
}
checkProjectionNode(rel[0], data);
reinforceSelection(schema, rel[0], projectionNode[attr]);
}
}
}