366 lines
15 KiB
JavaScript
366 lines
15 KiB
JavaScript
"use strict";
|
||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||
};
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
exports.CascadeStore = void 0;
|
||
const assert_1 = __importDefault(require("assert"));
|
||
const lodash_1 = require("lodash");
|
||
const RowStore_1 = require("../types/RowStore");
|
||
const filter_1 = require("./filter");
|
||
const relation_1 = require("./relation");
|
||
/**这个用来处理级联的select和update,对不同能力的 */
|
||
class CascadeStore extends RowStore_1.RowStore {
|
||
constructor(storageSchema) {
|
||
super(storageSchema);
|
||
}
|
||
async cascadeSelect(entity, selection, context, params) {
|
||
const { data } = selection;
|
||
const projection = {};
|
||
const oneToMany = {};
|
||
const oneToManyOnEntity = {};
|
||
const manyToOne = {};
|
||
const manyToOneOnEntity = {};
|
||
for (const attr in data) {
|
||
const relation = (0, relation_1.judgeRelation)(this.storageSchema, entity, attr);
|
||
if (relation === 1 || relation == 0) {
|
||
(0, lodash_1.assign)(projection, {
|
||
[attr]: data[attr],
|
||
});
|
||
}
|
||
else if (relation === 2) {
|
||
// 基于entity的多对一
|
||
(0, lodash_1.assign)(projection, {
|
||
entity: 1,
|
||
entityId: 1,
|
||
});
|
||
(0, lodash_1.assign)(manyToOneOnEntity, {
|
||
[attr]: 1,
|
||
});
|
||
}
|
||
else if (typeof relation === 'string') {
|
||
// 基于属性的多对一
|
||
(0, lodash_1.assign)(projection, {
|
||
[`${attr}Id`]: 1,
|
||
});
|
||
(0, lodash_1.assign)(manyToOne, {
|
||
[attr]: relation,
|
||
});
|
||
}
|
||
else {
|
||
const [entity2, foreignKey] = relation;
|
||
if (foreignKey) {
|
||
// 基于属性的一对多
|
||
(0, lodash_1.assign)(oneToMany, {
|
||
[attr]: {
|
||
entity: entity2,
|
||
foreignKey,
|
||
},
|
||
});
|
||
}
|
||
else {
|
||
// 基于entity的多对一
|
||
(0, lodash_1.assign)(oneToManyOnEntity, {
|
||
[attr]: entity2,
|
||
});
|
||
}
|
||
}
|
||
}
|
||
const rows = await this.selectAbjointRow(entity, selection, context, params);
|
||
for (const row of rows) {
|
||
for (const attr in manyToOne) {
|
||
const row2 = await this.cascadeSelect(manyToOne[attr], {
|
||
data: data[attr],
|
||
filter: {
|
||
id: row[`${attr}Id`],
|
||
}
|
||
}, context, params);
|
||
(0, lodash_1.assign)(row, {
|
||
[attr]: row2[0],
|
||
});
|
||
}
|
||
for (const attr in manyToOneOnEntity) {
|
||
if (row.entity === attr) {
|
||
const row2 = await this.cascadeSelect(attr, {
|
||
data: data[attr],
|
||
filter: {
|
||
id: row[`entityId`],
|
||
}
|
||
}, context, params);
|
||
(0, lodash_1.assign)(row, {
|
||
[attr]: row2[0],
|
||
});
|
||
}
|
||
}
|
||
for (const attr in oneToMany) {
|
||
const { entity: entity2, foreignKey } = oneToMany[attr];
|
||
const filter2 = data[attr];
|
||
const rows2 = await this.cascadeSelect(entity2, (0, lodash_1.assign)({}, filter2, {
|
||
filter: (0, filter_1.addFilterSegment)({
|
||
[foreignKey]: row.id,
|
||
}, filter2.filter),
|
||
}), context, params);
|
||
(0, lodash_1.assign)(row, {
|
||
[attr]: rows2,
|
||
});
|
||
}
|
||
for (const attr in oneToManyOnEntity) {
|
||
const filter2 = data[attr];
|
||
const rows2 = await this.cascadeSelect(oneToManyOnEntity[attr], (0, lodash_1.assign)({}, filter2, {
|
||
filter: (0, filter_1.addFilterSegment)({
|
||
entityId: row.id,
|
||
entity,
|
||
}, filter2.filter),
|
||
}), context, params);
|
||
(0, lodash_1.assign)(row, {
|
||
[attr]: rows2,
|
||
});
|
||
}
|
||
}
|
||
return rows;
|
||
}
|
||
/**
|
||
* 级联更新
|
||
* A --> B
|
||
多对一:A CREATE/B CREATE,B data的主键赋到A的data上
|
||
A CREATE/B UPDATE,B filter的主键来自A的data
|
||
A UPDATE/B CREATE,B data的主键赋到A的data上
|
||
A UPDATE/B UPDATE,B filter的主键来自A的row
|
||
A UPDATE/B REMOVE,B filter的主键来自A的row
|
||
A REMOVE/B UPDATE,B filter的主键来自A的row
|
||
A REMOVE/B REMOVE,B filter的主键来自A的row
|
||
|
||
一对多:A CREATE/B CREATE,A data上的主键赋到B的data上
|
||
A CREATE/B UPDATE,A data上的主键赋到B的data上
|
||
A UPDATE/B CREATE,A filter上的主键赋到B的data上(一定是带主键的filter)
|
||
A UPDATE/B UPDATE,A filter上的主键赋到B的filter上(一定是带主键的filter)
|
||
A UPDATE/B REMOVE,A filter上的主键赋到B的filter上(一定是带主键的filter)
|
||
A REMOVE/B UPDATE,A filter上的主键赋到B的filter上(且B关于A的外键清空)
|
||
A REMOVE/B REMOVE,A filter上的主键赋到B的filter上
|
||
* @param entity
|
||
* @param operation
|
||
* @param context
|
||
* @param params
|
||
*/
|
||
async cascadeUpdate(entity, operation, context, params) {
|
||
const { action, data, filter } = operation;
|
||
const opData = {};
|
||
if (action === 'create' && data instanceof Array) {
|
||
for (const dataEle of data) {
|
||
await this.cascadeUpdate(entity, {
|
||
action,
|
||
data: dataEle,
|
||
}, context, params);
|
||
}
|
||
return;
|
||
}
|
||
const data2 = data;
|
||
for (const attr in data2) {
|
||
const relation = (0, relation_1.judgeRelation)(this.storageSchema, entity, attr);
|
||
if (relation === 1) {
|
||
(0, lodash_1.assign)(opData, {
|
||
[attr]: data2[attr],
|
||
});
|
||
}
|
||
else if (relation === 2) {
|
||
// 基于entity/entityId的many-to-one
|
||
const operationMto = data2[attr];
|
||
const { action: actionMto, data: dataMto, filter: filterMto } = operationMto;
|
||
if (actionMto === 'create') {
|
||
(0, lodash_1.assign)(opData, {
|
||
entityId: dataMto.id,
|
||
entity: attr,
|
||
});
|
||
}
|
||
else if (action === 'create') {
|
||
const { entityId: fkId } = data2;
|
||
(0, assert_1.default)(typeof fkId === 'string');
|
||
(0, lodash_1.assign)(operationMto, {
|
||
filter: (0, filter_1.addFilterSegment)({
|
||
id: fkId,
|
||
}), filterMto,
|
||
});
|
||
(0, lodash_1.assign)(opData, {
|
||
entity: attr,
|
||
});
|
||
}
|
||
else {
|
||
(0, assert_1.default)(!data2.hasOwnProperty('entityId') && !data2.hasOwnProperty('entity'));
|
||
(0, lodash_1.assign)(operationMto, {
|
||
filter: (0, filter_1.addFilterSegment)({
|
||
id: {
|
||
$in: {
|
||
entity,
|
||
data: {
|
||
entityId: 1,
|
||
},
|
||
filter: (0, filter_1.addFilterSegment)({
|
||
entity: attr,
|
||
}, filter),
|
||
}
|
||
},
|
||
}, filterMto),
|
||
});
|
||
}
|
||
await this.cascadeUpdate(attr, operationMto, context, params);
|
||
}
|
||
else if (typeof relation === 'string') {
|
||
// 基于attr的外键的many-to-one
|
||
const operationMto = data2[attr];
|
||
const { action: actionMto, data: dataMto, filter: filterMto } = operationMto;
|
||
if (actionMto === 'create') {
|
||
(0, lodash_1.assign)(opData, {
|
||
[`${attr}Id`]: dataMto.id,
|
||
});
|
||
}
|
||
else if (action === 'create') {
|
||
const { [`${attr}Id`]: fkId } = data2;
|
||
(0, assert_1.default)(typeof fkId === 'string');
|
||
(0, lodash_1.assign)(operationMto, {
|
||
filter: (0, filter_1.addFilterSegment)(filterMto || {}, {
|
||
id: fkId,
|
||
}),
|
||
});
|
||
}
|
||
else {
|
||
(0, assert_1.default)(!data2.hasOwnProperty(`${attr}Id`));
|
||
(0, lodash_1.assign)(operationMto, {
|
||
filter: (0, filter_1.addFilterSegment)(filterMto || {}, {
|
||
id: {
|
||
$in: {
|
||
entity,
|
||
data: {
|
||
[`${attr}Id`]: 1,
|
||
},
|
||
filter,
|
||
}
|
||
},
|
||
}),
|
||
});
|
||
}
|
||
await this.cascadeUpdate(relation, operationMto, context, params);
|
||
}
|
||
else {
|
||
const operationOtm = data2[attr];
|
||
const { action: actionOtm, data: dataOtm, filter: filterOtm } = operationOtm;
|
||
(0, assert_1.default)(relation instanceof Array);
|
||
const [entityOtm, foreignKey] = relation;
|
||
if (!foreignKey) {
|
||
// 基于entity/entityId的one-to-many
|
||
if (action === 'create') {
|
||
const { id } = data2;
|
||
if (dataOtm instanceof Array) {
|
||
dataOtm.forEach(ele => (0, lodash_1.assign)(ele, {
|
||
entity,
|
||
entityId: id,
|
||
}));
|
||
}
|
||
else {
|
||
(0, lodash_1.assign)(dataOtm, {
|
||
entity,
|
||
entityId: id,
|
||
});
|
||
}
|
||
}
|
||
else if (actionOtm === 'create') {
|
||
// 这里先假设filter上一定有id,复杂的情况后面再处理
|
||
const { id } = filter;
|
||
(0, assert_1.default)(typeof id === 'string');
|
||
if (dataOtm instanceof Array) {
|
||
dataOtm.forEach(ele => (0, lodash_1.assign)(ele, {
|
||
entity,
|
||
entityId: id,
|
||
}));
|
||
}
|
||
else {
|
||
(0, lodash_1.assign)(dataOtm, {
|
||
entity,
|
||
entityId: id,
|
||
});
|
||
}
|
||
}
|
||
else {
|
||
(0, lodash_1.assign)(operationOtm, {
|
||
filter: (0, filter_1.addFilterSegment)({
|
||
entity,
|
||
entityId: {
|
||
$in: {
|
||
entity,
|
||
data: {
|
||
id: 1,
|
||
},
|
||
filter,
|
||
}
|
||
}
|
||
}, filterOtm),
|
||
});
|
||
if (action === 'remove' && actionOtm === 'update') {
|
||
(0, lodash_1.assign)(dataOtm, {
|
||
entity: null,
|
||
entityId: null,
|
||
});
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
// 基于foreignKey的one-to-many
|
||
if (action === 'create') {
|
||
const { id } = data2;
|
||
if (dataOtm instanceof Array) {
|
||
dataOtm.forEach(ele => (0, lodash_1.assign)(ele, {
|
||
[foreignKey]: id,
|
||
}));
|
||
}
|
||
else {
|
||
(0, lodash_1.assign)(dataOtm, {
|
||
[foreignKey]: id,
|
||
});
|
||
}
|
||
}
|
||
else if (actionOtm === 'create') {
|
||
// 这里先假设filter上一定有id,复杂的情况后面再处理
|
||
const { id } = filter;
|
||
(0, assert_1.default)(typeof id === 'string');
|
||
if (dataOtm instanceof Array) {
|
||
dataOtm.forEach(ele => (0, lodash_1.assign)(ele, {
|
||
[foreignKey]: id,
|
||
}));
|
||
}
|
||
else {
|
||
(0, lodash_1.assign)(dataOtm, {
|
||
[foreignKey]: id,
|
||
});
|
||
}
|
||
}
|
||
else {
|
||
(0, lodash_1.assign)(operationOtm, {
|
||
filter: (0, filter_1.addFilterSegment)({
|
||
[foreignKey]: {
|
||
$in: {
|
||
entity,
|
||
data: {
|
||
id: 1,
|
||
},
|
||
filter,
|
||
}
|
||
}
|
||
}, filterOtm),
|
||
});
|
||
if (action === 'remove' && actionOtm === 'update') {
|
||
(0, lodash_1.assign)(dataOtm, {
|
||
[foreignKey]: null,
|
||
});
|
||
}
|
||
}
|
||
}
|
||
await this.cascadeUpdate(entityOtm, operationOtm, context, params);
|
||
}
|
||
}
|
||
const operation2 = (0, lodash_1.assign)({}, operation, {
|
||
data: opData,
|
||
});
|
||
await this.updateAbjointRow(entity, operation2, context, params);
|
||
}
|
||
}
|
||
exports.CascadeStore = CascadeStore;
|