修正了reinforceSelection中的部分无用代码,增加了几个未来用于subscribe的结构定义
This commit is contained in:
parent
a506f2acc2
commit
060c208804
|
|
@ -24,13 +24,12 @@ var CascadeStore = /** @class */ (function (_super) {
|
|||
}
|
||||
CascadeStore.prototype.reinforceSelectionAsync = function (entity, selection, context, option) {
|
||||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||||
var noRelationDestEntities, rewriterPromises;
|
||||
var rewriterPromises;
|
||||
var _this = this;
|
||||
return tslib_1.__generator(this, function (_a) {
|
||||
switch (_a.label) {
|
||||
case 0:
|
||||
noRelationDestEntities = [];
|
||||
this.reinforceSelectionInner(entity, selection, context, noRelationDestEntities);
|
||||
this.reinforceSelectionInner(entity, selection, context);
|
||||
rewriterPromises = this.selectionRewriters.map(function (ele) { return ele(_this.getSchema(), entity, selection, context); });
|
||||
if (!(rewriterPromises.length > 0)) return [3 /*break*/, 2];
|
||||
return [4 /*yield*/, Promise.all(rewriterPromises)];
|
||||
|
|
@ -44,13 +43,16 @@ var CascadeStore = /** @class */ (function (_super) {
|
|||
};
|
||||
CascadeStore.prototype.reinforceSelectionSync = function (entity, selection, context, option) {
|
||||
var _this = this;
|
||||
this.reinforceSelectionInner(entity, selection, context, []);
|
||||
var rewriterPromises = this.selectionRewriters.map(function (ele) { return ele(_this.getSchema(), entity, selection, context); });
|
||||
this.reinforceSelectionInner(entity, selection, context);
|
||||
this.selectionRewriters.forEach(function (ele) {
|
||||
var result = ele(_this.getSchema(), entity, selection, context);
|
||||
(0, assert_1.default)(!(result instanceof Promise));
|
||||
});
|
||||
};
|
||||
CascadeStore.prototype.reinforceSelectionInner = function (entity, selection, context, noRelationDestEntities) {
|
||||
CascadeStore.prototype.reinforceSelectionInner = function (entity, selection, context) {
|
||||
var _this = this;
|
||||
var filter = selection.filter, data = selection.data, sorter = selection.sorter;
|
||||
var checkNode = function (projectionNode, attrs) {
|
||||
var assignNecessaryProjectionAttrs = function (projectionNode, attrs) {
|
||||
attrs.forEach(function (attr) {
|
||||
var _a;
|
||||
if (!projectionNode.hasOwnProperty(attr)) {
|
||||
|
|
@ -60,108 +62,108 @@ var CascadeStore = /** @class */ (function (_super) {
|
|||
}
|
||||
});
|
||||
};
|
||||
var relevantIds = [];
|
||||
if (filter) {
|
||||
var toBeAssignNode_1 = {}; // 用来记录在表达式中涉及到的结点
|
||||
// filter当中所关联到的属性必须在projection中
|
||||
var filterNodeDict_1 = {};
|
||||
var checkFilterNode_1 = function (entity2, filterNode, projectionNode) {
|
||||
var _a, e_1, _b, _c, _d, _e, _f;
|
||||
var necessaryAttrs = ['id'];
|
||||
for (var attr in filterNode) {
|
||||
if (attr === '#id') {
|
||||
(0, assert_1.default)(!filterNodeDict_1[filterNode[attr]], "projection\u4E2D\u7ED3\u70B9\u7684id\u6709\u91CD\u590D, ".concat(filterNode[attr]));
|
||||
Object.assign(filterNodeDict_1, (_a = {},
|
||||
_a[filterNode[attr]] = projectionNode,
|
||||
_a));
|
||||
if (toBeAssignNode_1[filterNode[attr]]) {
|
||||
checkNode(projectionNode, toBeAssignNode_1[filterNode[attr]]);
|
||||
var checkFilterNode = function (entity2, filterNode, projectionNode, toBeAssignNode, filterNodeDict) {
|
||||
var _a, e_1, _b, _c, _d, _e, _f;
|
||||
var necessaryAttrs = ['id'];
|
||||
for (var attr in filterNode) {
|
||||
if (attr === '#id') {
|
||||
(0, assert_1.default)(!filterNodeDict[filterNode[attr]], "projection\u4E2D\u7ED3\u70B9\u7684id\u6709\u91CD\u590D, ".concat(filterNode[attr]));
|
||||
Object.assign(filterNodeDict, (_a = {},
|
||||
_a[filterNode[attr]] = projectionNode,
|
||||
_a));
|
||||
if (toBeAssignNode[filterNode[attr]]) {
|
||||
assignNecessaryProjectionAttrs(projectionNode, toBeAssignNode[filterNode[attr]]);
|
||||
}
|
||||
}
|
||||
else if (['$and', '$or'].includes(attr)) {
|
||||
try {
|
||||
for (var _g = (e_1 = void 0, tslib_1.__values(filterNode[attr])), _h = _g.next(); !_h.done; _h = _g.next()) {
|
||||
var node = _h.value;
|
||||
checkFilterNode(entity2, node, projectionNode, toBeAssignNode, filterNodeDict);
|
||||
}
|
||||
}
|
||||
else if (['$and', '$or'].includes(attr)) {
|
||||
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
||||
finally {
|
||||
try {
|
||||
for (var _g = (e_1 = void 0, tslib_1.__values(filterNode[attr])), _h = _g.next(); !_h.done; _h = _g.next()) {
|
||||
var node = _h.value;
|
||||
checkFilterNode_1(entity2, node, projectionNode);
|
||||
}
|
||||
if (_h && !_h.done && (_b = _g.return)) _b.call(_g);
|
||||
}
|
||||
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
||||
finally {
|
||||
try {
|
||||
if (_h && !_h.done && (_b = _g.return)) _b.call(_g);
|
||||
finally { if (e_1) throw e_1.error; }
|
||||
}
|
||||
}
|
||||
else if (attr === '$not') {
|
||||
checkFilterNode(entity2, filterNode[attr], projectionNode, toBeAssignNode, filterNodeDict);
|
||||
}
|
||||
else if (attr === '$text') {
|
||||
// 全文检索首先要有fulltext索引,其次要把fulltext的相关属性加到projection里
|
||||
var indexes = _this.getSchema()[entity2].indexes;
|
||||
var fulltextIndex = indexes.find(function (ele) { return ele.config && ele.config.type === 'fulltext'; });
|
||||
var attributes = fulltextIndex.attributes;
|
||||
necessaryAttrs.push.apply(necessaryAttrs, tslib_1.__spreadArray([], tslib_1.__read((attributes.map(function (ele) { return ele.name; }))), false));
|
||||
}
|
||||
else {
|
||||
if (attr.toLowerCase().startsWith(types_1.EXPRESSION_PREFIX)) {
|
||||
var exprResult = (0, types_1.getAttrRefInExpression)(filterNode[attr]);
|
||||
for (var nodeName in exprResult) {
|
||||
if (nodeName === '#current') {
|
||||
assignNecessaryProjectionAttrs(projectionNode, exprResult[nodeName]);
|
||||
}
|
||||
finally { if (e_1) throw e_1.error; }
|
||||
}
|
||||
}
|
||||
else if (attr === '$not') {
|
||||
checkFilterNode_1(entity2, filterNode[attr], projectionNode);
|
||||
}
|
||||
else if (attr === '$text') {
|
||||
// 全文检索首先要有fulltext索引,其次要把fulltext的相关属性加到projection里
|
||||
var indexes = _this.getSchema()[entity2].indexes;
|
||||
var fulltextIndex = indexes.find(function (ele) { return ele.config && ele.config.type === 'fulltext'; });
|
||||
var attributes = fulltextIndex.attributes;
|
||||
necessaryAttrs.push.apply(necessaryAttrs, tslib_1.__spreadArray([], tslib_1.__read((attributes.map(function (ele) { return ele.name; }))), false));
|
||||
}
|
||||
else {
|
||||
if (attr.toLowerCase().startsWith(types_1.EXPRESSION_PREFIX)) {
|
||||
var exprResult = (0, types_1.getAttrRefInExpression)(filterNode[attr]);
|
||||
for (var nodeName in exprResult) {
|
||||
if (nodeName === '#current') {
|
||||
checkNode(projectionNode, exprResult[nodeName]);
|
||||
}
|
||||
else if (filterNodeDict_1[nodeName]) {
|
||||
checkNode(filterNodeDict_1[nodeName], exprResult[nodeName]);
|
||||
else if (filterNodeDict[nodeName]) {
|
||||
assignNecessaryProjectionAttrs(filterNodeDict[nodeName], exprResult[nodeName]);
|
||||
}
|
||||
else {
|
||||
if (toBeAssignNode[nodeName]) {
|
||||
(_c = toBeAssignNode[nodeName]).push.apply(_c, tslib_1.__spreadArray([], tslib_1.__read(exprResult[nodeName]), false));
|
||||
}
|
||||
else {
|
||||
if (toBeAssignNode_1[nodeName]) {
|
||||
(_c = toBeAssignNode_1[nodeName]).push.apply(_c, tslib_1.__spreadArray([], tslib_1.__read(exprResult[nodeName]), false));
|
||||
}
|
||||
else {
|
||||
Object.assign(toBeAssignNode_1, (_d = {},
|
||||
_d[nodeName] = exprResult[nodeName],
|
||||
_d));
|
||||
}
|
||||
Object.assign(toBeAssignNode, (_d = {},
|
||||
_d[nodeName] = exprResult[nodeName],
|
||||
_d));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
var rel = _this.judgeRelation(entity2, attr);
|
||||
if (rel === 1) {
|
||||
necessaryAttrs.push(attr);
|
||||
}
|
||||
else if (rel === 2) {
|
||||
// entity/entityId反指
|
||||
necessaryAttrs.push('entity', 'entityId');
|
||||
if (!projectionNode[attr]) {
|
||||
Object.assign(projectionNode, (_e = {},
|
||||
_e[attr] = {
|
||||
id: 1,
|
||||
},
|
||||
_e));
|
||||
}
|
||||
checkFilterNode_1(attr, filterNode[attr], projectionNode[attr]);
|
||||
}
|
||||
else if (typeof rel === 'string') {
|
||||
necessaryAttrs.push("".concat(attr, "Id"));
|
||||
if (!projectionNode[attr]) {
|
||||
Object.assign(projectionNode, (_f = {},
|
||||
_f[attr] = {
|
||||
id: 1,
|
||||
},
|
||||
_f));
|
||||
}
|
||||
checkFilterNode_1(rel, filterNode[attr], projectionNode[attr]);
|
||||
}
|
||||
else if (rel instanceof Array) {
|
||||
// 现在filter中还不支持一对多的语义,先放着吧
|
||||
}
|
||||
}
|
||||
}
|
||||
checkNode(projectionNode, necessaryAttrs);
|
||||
else {
|
||||
var rel = _this.judgeRelation(entity2, attr);
|
||||
if (rel === 1) {
|
||||
necessaryAttrs.push(attr);
|
||||
}
|
||||
else if (rel === 2) {
|
||||
// entity/entityId反指
|
||||
necessaryAttrs.push('entity', 'entityId');
|
||||
if (!projectionNode[attr]) {
|
||||
Object.assign(projectionNode, (_e = {},
|
||||
_e[attr] = {
|
||||
id: 1,
|
||||
},
|
||||
_e));
|
||||
}
|
||||
checkFilterNode(attr, filterNode[attr], projectionNode[attr], toBeAssignNode, filterNodeDict);
|
||||
}
|
||||
else if (typeof rel === 'string') {
|
||||
necessaryAttrs.push("".concat(attr, "Id"));
|
||||
if (!projectionNode[attr]) {
|
||||
Object.assign(projectionNode, (_f = {},
|
||||
_f[attr] = {
|
||||
id: 1,
|
||||
},
|
||||
_f));
|
||||
}
|
||||
checkFilterNode(rel, filterNode[attr], projectionNode[attr], toBeAssignNode, filterNodeDict);
|
||||
}
|
||||
else if (rel instanceof Array) {
|
||||
// 子查询,暂时不处理
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
checkFilterNode_1(entity, filter, data);
|
||||
assignNecessaryProjectionAttrs(projectionNode, necessaryAttrs);
|
||||
}
|
||||
};
|
||||
var relevantIds = [];
|
||||
if (filter) {
|
||||
var toBeAssignNode = {}; // 用来记录在表达式中涉及到的结点
|
||||
// filter当中所关联到的属性必须在projection中
|
||||
var filterNodeDict = {};
|
||||
checkFilterNode(entity, filter, data, toBeAssignNode, filterNodeDict);
|
||||
relevantIds = (0, filter_2.getRelevantIds)(filter);
|
||||
}
|
||||
// sorter感觉现在取不取影响不大,前端的list直接获取返回的ids了,先不管之
|
||||
|
|
@ -179,7 +181,7 @@ var CascadeStore = /** @class */ (function (_super) {
|
|||
_a[projectionNode[attr]] = projectionNode,
|
||||
_a));
|
||||
if (toBeAssignNode2[projectionNode[attr]]) {
|
||||
checkNode(projectionNode, toBeAssignNode2[projectionNode[attr]]);
|
||||
assignNecessaryProjectionAttrs(projectionNode, toBeAssignNode2[projectionNode[attr]]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -187,10 +189,10 @@ var CascadeStore = /** @class */ (function (_super) {
|
|||
var exprResult = (0, types_1.getAttrRefInExpression)(projectionNode[attr]);
|
||||
for (var nodeName in exprResult) {
|
||||
if (nodeName === '#current') {
|
||||
checkNode(projectionNode, exprResult[nodeName]);
|
||||
assignNecessaryProjectionAttrs(projectionNode, exprResult[nodeName]);
|
||||
}
|
||||
else if (projectionNodeDict[nodeName]) {
|
||||
checkNode(projectionNodeDict[nodeName], exprResult[nodeName]);
|
||||
assignNecessaryProjectionAttrs(projectionNodeDict[nodeName], exprResult[nodeName]);
|
||||
}
|
||||
else {
|
||||
if (toBeAssignNode2[nodeName]) {
|
||||
|
|
@ -219,18 +221,18 @@ var CascadeStore = /** @class */ (function (_super) {
|
|||
checkProjectionNode(rel, projectionNode[attr]);
|
||||
}
|
||||
else if (rel instanceof Array && !attr.endsWith('$$aggr')) {
|
||||
var data_1 = projectionNode[attr].data;
|
||||
var _d = projectionNode[attr], data_1 = _d.data, filter_3 = _d.filter;
|
||||
if (rel[1]) {
|
||||
checkNode(data_1, [rel[1]]);
|
||||
assignNecessaryProjectionAttrs(data_1, [rel[1]]);
|
||||
}
|
||||
else {
|
||||
checkNode(data_1, ['entity', 'entityId']);
|
||||
assignNecessaryProjectionAttrs(data_1, ['entity', 'entityId']);
|
||||
}
|
||||
_this.reinforceSelectionInner(rel[0], projectionNode[attr], context, noRelationDestEntities);
|
||||
_this.reinforceSelectionInner(rel[0], projectionNode[attr], context);
|
||||
}
|
||||
}
|
||||
}
|
||||
checkNode(projectionNode, necessaryAttrs);
|
||||
assignNecessaryProjectionAttrs(projectionNode, necessaryAttrs);
|
||||
}
|
||||
// 如果对象中指向一对多的Modi,此时加上指向Modi的projection
|
||||
if (_this.getSchema()[entity2].toModi) {
|
||||
|
|
@ -281,7 +283,6 @@ var CascadeStore = /** @class */ (function (_super) {
|
|||
},
|
||||
});
|
||||
}
|
||||
noRelationDestEntities.push(entity2);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -190,4 +190,9 @@ export declare type AuthDeduceRelationMap<ED extends EntityDict> = {
|
|||
};
|
||||
export declare type SelectFreeEntities<ED extends EntityDict> = (keyof ED)[];
|
||||
export declare type OtmKey<K extends string> = K | `${K}$${number}`;
|
||||
export interface SubDataDef<ED extends EntityDict, T extends keyof ED> {
|
||||
id: string;
|
||||
entity: T;
|
||||
filter: ED[T]['Selection']['filter'];
|
||||
}
|
||||
export {};
|
||||
|
|
|
|||
|
|
@ -12,3 +12,4 @@ exports.initinctiveAttributes = [exports.PrimaryKeyAttribute, exports.TriggerDat
|
|||
;
|
||||
;
|
||||
;
|
||||
;
|
||||
|
|
|
|||
|
|
@ -29,38 +29,14 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
|
|||
private selectionRewriters: SelectionRewriter<ED, AsyncContext<ED> | SyncContext<ED>>[] = [];
|
||||
private operationRewriters: OperationRewriter<ED, AsyncContext<ED> | SyncContext<ED>>[] = [];
|
||||
|
||||
private async reinforceSelectionAsync<Cxt extends AsyncContext<ED>, OP extends SelectOption>(entity: keyof ED, selection: ED[keyof ED]['Selection'], context: Cxt, option: OP) {
|
||||
const noRelationDestEntities: string[] = [];
|
||||
|
||||
this.reinforceSelectionInner(entity, selection, context, noRelationDestEntities);
|
||||
private async reinforceSelectionAsync<Cxt extends AsyncContext<ED>, OP extends SelectOption>(entity: keyof ED, selection: ED[keyof ED]['Selection'], context: Cxt, option: OP) {
|
||||
|
||||
|
||||
this.reinforceSelectionInner(entity, selection, context);
|
||||
|
||||
const rewriterPromises = this.selectionRewriters.map(
|
||||
ele => ele(this.getSchema(), entity, selection, context)
|
||||
);
|
||||
|
||||
// 这个设计每次都要取actionAuth的数据,感觉不是很优雅。by Xc 20230722
|
||||
// 这个设计废除了,前台页面自己来取需要的actionAUth,通过cache的缓存和KeepFresh机制来减少对后台数据的访问
|
||||
/* if (noRelationDestEntities.length > 0 && !option.dontCollect) {
|
||||
rewriterPromises.push(
|
||||
context.select('actionAuth', {
|
||||
data: {
|
||||
id: 1,
|
||||
deActions: 1,
|
||||
destEntity: 1,
|
||||
paths: 1,
|
||||
relationId: 1,
|
||||
},
|
||||
filter: {
|
||||
relationId: {
|
||||
$exists: false,
|
||||
},
|
||||
destEntity: {
|
||||
$in: noRelationDestEntities,
|
||||
},
|
||||
},
|
||||
}, {}) as any
|
||||
);
|
||||
} */
|
||||
|
||||
if (rewriterPromises.length > 0) {
|
||||
await Promise.all(rewriterPromises);
|
||||
|
|
@ -68,21 +44,24 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
|
|||
}
|
||||
|
||||
private reinforceSelectionSync<Cxt extends SyncContext<ED>, OP extends SelectOption>(entity: keyof ED, selection: ED[keyof ED]['Selection'], context: Cxt, option: OP) {
|
||||
this.reinforceSelectionInner(entity, selection, context, []);
|
||||
this.reinforceSelectionInner(entity, selection, context);
|
||||
|
||||
const rewriterPromises = this.selectionRewriters.map(
|
||||
ele => ele(this.getSchema(), entity, selection, context)
|
||||
this.selectionRewriters.forEach(
|
||||
ele => {
|
||||
const result = ele(this.getSchema(), entity, selection, context);
|
||||
assert(!(result instanceof Promise));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private reinforceSelectionInner<Cxt extends AsyncContext<ED> | SyncContext<ED>, OP extends SelectOption>(
|
||||
entity: keyof ED,
|
||||
selection: ED[keyof ED]['Selection'],
|
||||
context: Cxt,
|
||||
noRelationDestEntities: string[]) {
|
||||
entity: keyof ED,
|
||||
selection: ED[keyof ED]['Selection'],
|
||||
context: Cxt
|
||||
) {
|
||||
const { filter, data, sorter } = selection;
|
||||
|
||||
const checkNode = (projectionNode: ED[keyof ED]['Selection']['data'], attrs: string[]) => {
|
||||
const assignNecessaryProjectionAttrs = (projectionNode: ED[keyof ED]['Selection']['data'], attrs: string[]) => {
|
||||
attrs.forEach(
|
||||
(attr) => {
|
||||
if (!projectionNode.hasOwnProperty(attr)) {
|
||||
|
|
@ -94,102 +73,109 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
|
|||
);
|
||||
};
|
||||
|
||||
|
||||
const checkFilterNode = (
|
||||
entity2: keyof ED,
|
||||
filterNode: ED[keyof ED]['Selection']['filter'],
|
||||
projectionNode: ED[keyof ED]['Selection']['data'],
|
||||
toBeAssignNode: Record<string, string[]>,
|
||||
filterNodeDict: Record<string, ED[keyof ED]['Selection']['data']>) => {
|
||||
const necessaryAttrs: string[] = ['id'];
|
||||
for (const attr in filterNode) {
|
||||
if (attr === '#id') {
|
||||
assert(!filterNodeDict[filterNode[attr]!], `projection中结点的id有重复, ${filterNode[attr]}`);
|
||||
Object.assign(filterNodeDict, {
|
||||
[filterNode[attr]!]: projectionNode,
|
||||
});
|
||||
if (toBeAssignNode[filterNode[attr]!]) {
|
||||
assignNecessaryProjectionAttrs(projectionNode, toBeAssignNode[filterNode[attr]!]);
|
||||
}
|
||||
}
|
||||
else if (['$and', '$or'].includes(attr)) {
|
||||
for (const node of filterNode[attr]!) {
|
||||
checkFilterNode(entity2, node, projectionNode, toBeAssignNode, filterNodeDict);
|
||||
}
|
||||
}
|
||||
else if (attr === '$not') {
|
||||
checkFilterNode(entity2, filterNode[attr]!, projectionNode, toBeAssignNode, filterNodeDict);
|
||||
}
|
||||
else if (attr === '$text') {
|
||||
// 全文检索首先要有fulltext索引,其次要把fulltext的相关属性加到projection里
|
||||
const { indexes } = this.getSchema()[entity2];
|
||||
|
||||
const fulltextIndex = indexes!.find(
|
||||
ele => ele.config && ele.config.type === 'fulltext'
|
||||
);
|
||||
|
||||
const { attributes } = fulltextIndex!;
|
||||
necessaryAttrs.push(...(attributes.map(ele => ele.name as string)));
|
||||
}
|
||||
else {
|
||||
if (attr.toLowerCase().startsWith(EXPRESSION_PREFIX)) {
|
||||
const exprResult = getAttrRefInExpression(filterNode[attr]!);
|
||||
for (const nodeName in exprResult) {
|
||||
if (nodeName === '#current') {
|
||||
assignNecessaryProjectionAttrs(projectionNode, exprResult[nodeName]);
|
||||
}
|
||||
else if (filterNodeDict[nodeName]) {
|
||||
assignNecessaryProjectionAttrs(filterNodeDict[nodeName], exprResult[nodeName]);
|
||||
}
|
||||
else {
|
||||
if (toBeAssignNode[nodeName]) {
|
||||
toBeAssignNode[nodeName].push(...exprResult[nodeName]);
|
||||
}
|
||||
else {
|
||||
Object.assign(toBeAssignNode, {
|
||||
[nodeName]: exprResult[nodeName],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const rel = this.judgeRelation(entity2, attr);
|
||||
if (rel === 1) {
|
||||
necessaryAttrs.push(attr);
|
||||
}
|
||||
else if (rel === 2) {
|
||||
// entity/entityId反指
|
||||
necessaryAttrs.push('entity', 'entityId');
|
||||
if (!projectionNode[attr]) {
|
||||
Object.assign(projectionNode, {
|
||||
[attr]: {
|
||||
id: 1,
|
||||
}
|
||||
});
|
||||
}
|
||||
checkFilterNode(attr, filterNode[attr]!, projectionNode[attr], toBeAssignNode, filterNodeDict);
|
||||
}
|
||||
else if (typeof rel === 'string') {
|
||||
necessaryAttrs.push(`${attr}Id`);
|
||||
if (!projectionNode[attr]) {
|
||||
Object.assign(projectionNode, {
|
||||
[attr]: {
|
||||
id: 1,
|
||||
}
|
||||
});
|
||||
}
|
||||
checkFilterNode(rel, filterNode[attr]!, projectionNode[attr], toBeAssignNode, filterNodeDict);
|
||||
}
|
||||
else if (rel instanceof Array) {
|
||||
// 子查询,暂时不处理
|
||||
}
|
||||
}
|
||||
}
|
||||
assignNecessaryProjectionAttrs(projectionNode, necessaryAttrs);
|
||||
}
|
||||
};
|
||||
|
||||
let relevantIds: string[] = [];
|
||||
if (filter) {
|
||||
const toBeAssignNode: Record<string, string[]> = {}; // 用来记录在表达式中涉及到的结点
|
||||
// filter当中所关联到的属性必须在projection中
|
||||
const filterNodeDict: Record<string, ED[keyof ED]['Selection']['data']> = {};
|
||||
const checkFilterNode = (entity2: keyof ED, filterNode: ED[keyof ED]['Selection']['filter'], projectionNode: ED[keyof ED]['Selection']['data']) => {
|
||||
const necessaryAttrs: string[] = ['id'];
|
||||
for (const attr in filterNode) {
|
||||
if (attr === '#id') {
|
||||
assert(!filterNodeDict[filterNode[attr]!], `projection中结点的id有重复, ${filterNode[attr]}`);
|
||||
Object.assign(filterNodeDict, {
|
||||
[filterNode[attr]!]: projectionNode,
|
||||
});
|
||||
if (toBeAssignNode[filterNode[attr]!]) {
|
||||
checkNode(projectionNode, toBeAssignNode[filterNode[attr]!]);
|
||||
}
|
||||
}
|
||||
else if (['$and', '$or'].includes(attr)) {
|
||||
for (const node of filterNode[attr]!) {
|
||||
checkFilterNode(entity2, node, projectionNode);
|
||||
}
|
||||
}
|
||||
else if (attr === '$not') {
|
||||
checkFilterNode(entity2, filterNode[attr]!, projectionNode);
|
||||
}
|
||||
else if (attr === '$text') {
|
||||
// 全文检索首先要有fulltext索引,其次要把fulltext的相关属性加到projection里
|
||||
const { indexes } = this.getSchema()[entity2];
|
||||
|
||||
const fulltextIndex = indexes!.find(
|
||||
ele => ele.config && ele.config.type === 'fulltext'
|
||||
);
|
||||
|
||||
const { attributes } = fulltextIndex!;
|
||||
necessaryAttrs.push(...(attributes.map(ele => ele.name as string)));
|
||||
}
|
||||
else {
|
||||
if (attr.toLowerCase().startsWith(EXPRESSION_PREFIX)) {
|
||||
const exprResult = getAttrRefInExpression(filterNode[attr]!);
|
||||
for (const nodeName in exprResult) {
|
||||
if (nodeName === '#current') {
|
||||
checkNode(projectionNode, exprResult[nodeName]);
|
||||
}
|
||||
else if (filterNodeDict[nodeName]) {
|
||||
checkNode(filterNodeDict[nodeName], exprResult[nodeName]);
|
||||
}
|
||||
else {
|
||||
if (toBeAssignNode[nodeName]) {
|
||||
toBeAssignNode[nodeName].push(...exprResult[nodeName]);
|
||||
}
|
||||
else {
|
||||
Object.assign(toBeAssignNode, {
|
||||
[nodeName]: exprResult[nodeName],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
const rel = this.judgeRelation(entity2, attr);
|
||||
if (rel === 1) {
|
||||
necessaryAttrs.push(attr);
|
||||
}
|
||||
else if (rel === 2) {
|
||||
// entity/entityId反指
|
||||
necessaryAttrs.push('entity', 'entityId');
|
||||
if (!projectionNode[attr]) {
|
||||
Object.assign(projectionNode, {
|
||||
[attr]: {
|
||||
id: 1,
|
||||
}
|
||||
});
|
||||
}
|
||||
checkFilterNode(attr, filterNode[attr]!, projectionNode[attr]);
|
||||
}
|
||||
else if (typeof rel === 'string') {
|
||||
necessaryAttrs.push(`${attr}Id`);
|
||||
if (!projectionNode[attr]) {
|
||||
Object.assign(projectionNode, {
|
||||
[attr]: {
|
||||
id: 1,
|
||||
}
|
||||
});
|
||||
}
|
||||
checkFilterNode(rel, filterNode[attr]!, projectionNode[attr]);
|
||||
}
|
||||
else if (rel instanceof Array) {
|
||||
// 现在filter中还不支持一对多的语义,先放着吧
|
||||
}
|
||||
}
|
||||
}
|
||||
checkNode(projectionNode, necessaryAttrs);
|
||||
}
|
||||
};
|
||||
|
||||
checkFilterNode(entity, filter, data);
|
||||
checkFilterNode(entity, filter, data, toBeAssignNode, filterNodeDict);
|
||||
relevantIds = getRelevantIds(filter);
|
||||
}
|
||||
|
||||
|
|
@ -208,7 +194,7 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
|
|||
[projectionNode[attr]!]: projectionNode,
|
||||
});
|
||||
if (toBeAssignNode2[projectionNode[attr]!]) {
|
||||
checkNode(projectionNode, toBeAssignNode2[projectionNode[attr]!]);
|
||||
assignNecessaryProjectionAttrs(projectionNode, toBeAssignNode2[projectionNode[attr]!]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -216,10 +202,10 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
|
|||
const exprResult = getAttrRefInExpression(projectionNode[attr]!);
|
||||
for (const nodeName in exprResult) {
|
||||
if (nodeName === '#current') {
|
||||
checkNode(projectionNode, exprResult[nodeName]);
|
||||
assignNecessaryProjectionAttrs(projectionNode, exprResult[nodeName]);
|
||||
}
|
||||
else if (projectionNodeDict[nodeName]) {
|
||||
checkNode(projectionNodeDict[nodeName], exprResult[nodeName]);
|
||||
assignNecessaryProjectionAttrs(projectionNodeDict[nodeName], exprResult[nodeName]);
|
||||
}
|
||||
else {
|
||||
if (toBeAssignNode2[nodeName]) {
|
||||
|
|
@ -248,18 +234,18 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
|
|||
checkProjectionNode(rel, projectionNode[attr]);
|
||||
}
|
||||
else if (rel instanceof Array && !attr.endsWith('$$aggr')) {
|
||||
const { data } = projectionNode[attr];
|
||||
const { data, filter } = projectionNode[attr];
|
||||
if (rel[1]) {
|
||||
checkNode(data, [rel[1]]);
|
||||
assignNecessaryProjectionAttrs(data, [rel[1]]);
|
||||
}
|
||||
else {
|
||||
checkNode(data, ['entity', 'entityId']);
|
||||
assignNecessaryProjectionAttrs(data, ['entity', 'entityId']);
|
||||
}
|
||||
this.reinforceSelectionInner(rel[0], projectionNode[attr], context, noRelationDestEntities);
|
||||
this.reinforceSelectionInner(rel[0], projectionNode[attr], context);
|
||||
}
|
||||
}
|
||||
}
|
||||
checkNode(projectionNode, necessaryAttrs);
|
||||
assignNecessaryProjectionAttrs(projectionNode, necessaryAttrs);
|
||||
}
|
||||
|
||||
// 如果对象中指向一对多的Modi,此时加上指向Modi的projection
|
||||
|
|
@ -312,7 +298,6 @@ export abstract class CascadeStore<ED extends EntityDict & BaseEntityDict> exten
|
|||
} as ED['userRelation']['Selection'],
|
||||
});
|
||||
}
|
||||
noRelationDestEntities.push(entity2 as string);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { EntityDict } from "./Entity";
|
||||
import { EntityDict, SubDataDef } from "./Entity";
|
||||
import { OpRecord } from "./Entity";
|
||||
import { AsyncContext } from "../store/AsyncRowStore";
|
||||
|
||||
|
|
@ -12,4 +12,10 @@ export interface AspectWrapper<ED extends EntityDict, Cxt extends AsyncContext<E
|
|||
opRecords?: OpRecord<ED>[];
|
||||
message?: string | null;
|
||||
}>;
|
||||
|
||||
/* sub: (data: Array<SubDataDef<ED, keyof ED>>) => Promise<void>;
|
||||
|
||||
unsub: (ids: string[]) => Promise<void>;
|
||||
|
||||
registerSubCallback: (callback: (records: OpRecord<ED>[]) => void) => Promise<void>; */
|
||||
};
|
||||
|
|
@ -268,3 +268,9 @@ export type AuthDeduceRelationMap<ED extends EntityDict> = {
|
|||
export type SelectFreeEntities<ED extends EntityDict> = (keyof ED)[];
|
||||
// 一对多的键值的扩展
|
||||
export type OtmKey<K extends string> = K | `${K}$${number}`;
|
||||
|
||||
export interface SubDataDef<ED extends EntityDict, T extends keyof ED> {
|
||||
id: string;
|
||||
entity: T,
|
||||
filter: ED[T]['Selection']['filter'],
|
||||
};
|
||||
Loading…
Reference in New Issue