2123 lines
96 KiB
JavaScript
2123 lines
96 KiB
JavaScript
"use strict";
|
||
Object.defineProperty(exports, "__esModule", { value: true });
|
||
var tslib_1 = require("tslib");
|
||
var lodash_1 = require("oak-domain/lib/utils/lodash");
|
||
var assert_1 = require("oak-domain/lib/utils/assert");
|
||
var Entity_1 = require("oak-domain/lib/types/Entity");
|
||
var Demand_1 = require("oak-domain/lib/types/Demand");
|
||
var Exception_1 = require("oak-domain/lib/types/Exception");
|
||
var Demand_2 = require("oak-domain/lib/types/Demand");
|
||
var relation_1 = require("oak-domain/lib/store/relation");
|
||
var Expression_1 = require("oak-domain/lib/types/Expression");
|
||
var CascadeStore_1 = require("oak-domain/lib/store/CascadeStore");
|
||
;
|
||
;
|
||
function obscurePass(value, option) {
|
||
return !!((option === null || option === void 0 ? void 0 : option.obscure) && value === undefined);
|
||
}
|
||
var OakExpressionUnresolvedException = /** @class */ (function (_super) {
|
||
tslib_1.__extends(OakExpressionUnresolvedException, _super);
|
||
function OakExpressionUnresolvedException() {
|
||
return _super !== null && _super.apply(this, arguments) || this;
|
||
}
|
||
return OakExpressionUnresolvedException;
|
||
}(Exception_1.OakException));
|
||
;
|
||
var TreeStore = /** @class */ (function (_super) {
|
||
tslib_1.__extends(TreeStore, _super);
|
||
function TreeStore(storageSchema) {
|
||
var _this = _super.call(this, storageSchema) || this;
|
||
_this.commitCallbacks = [];
|
||
_this.store = {};
|
||
_this.activeTxnDict = {};
|
||
_this.stat = {
|
||
create: 0,
|
||
update: 0,
|
||
remove: 0,
|
||
commit: 0,
|
||
};
|
||
return _this;
|
||
}
|
||
/* treeStore改成同步以后不会再出现
|
||
private async waitOnTxn(id: string, context: Cxt) {
|
||
// 先检查自己的等待者中有没有id,以避免死锁
|
||
const myId = context.getCurrentTxnId()!;
|
||
const { waitList: myWaitList } = this.activeTxnDict[myId];
|
||
if (myWaitList.find(
|
||
ele => ele.id === id
|
||
)) {
|
||
throw new OakDeadlock();
|
||
}
|
||
const { waitList } = this.activeTxnDict[id];
|
||
const p = new Promise(
|
||
(resolve) => waitList.push({
|
||
id: myId,
|
||
fn: resolve,
|
||
})
|
||
);
|
||
await p;
|
||
} */
|
||
TreeStore.prototype.supportMultipleCreate = function () {
|
||
return false;
|
||
};
|
||
TreeStore.prototype.supportManyToOneJoin = function () {
|
||
return false;
|
||
};
|
||
TreeStore.prototype.resetInitialData = function (data, stat) {
|
||
var e_1, _a, _b;
|
||
this.store = {};
|
||
var now = Date.now();
|
||
for (var entity in data) {
|
||
var attributes = this.getSchema()[entity].attributes;
|
||
this.store[entity] = {};
|
||
try {
|
||
for (var _c = (e_1 = void 0, tslib_1.__values(data[entity])), _d = _c.next(); !_d.done; _d = _c.next()) {
|
||
var row = _d.value;
|
||
for (var key in attributes) {
|
||
if (row[key] === undefined) {
|
||
Object.assign(row, (_b = {},
|
||
_b[key] = null,
|
||
_b));
|
||
}
|
||
}
|
||
/**
|
||
* 处理初始化数据
|
||
*/
|
||
if (!row.$$createAt$$) {
|
||
Object.assign(row, {
|
||
$$createAt$$: now,
|
||
});
|
||
}
|
||
if (!row.$$deleteAt$$) {
|
||
Object.assign(row, {
|
||
$$deleteAt$$: null,
|
||
});
|
||
}
|
||
if (!row.$$updateAt$$) {
|
||
Object.assign(row, {
|
||
$$updateAt$$: now,
|
||
});
|
||
}
|
||
if (!row.$$seq$$) {
|
||
Object.assign(row, {
|
||
$$seq$$: "".concat(Math.ceil((Math.random() + 1000) * 100)),
|
||
});
|
||
}
|
||
(0, assert_1.assert)(row.id && !row.id.includes('.'));
|
||
(0, lodash_1.set)(this.store, "".concat(entity, ".").concat(row.id, ".$current"), row);
|
||
}
|
||
}
|
||
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
||
finally {
|
||
try {
|
||
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
||
}
|
||
finally { if (e_1) throw e_1.error; }
|
||
}
|
||
}
|
||
if (stat) {
|
||
this.stat = stat;
|
||
}
|
||
};
|
||
TreeStore.prototype.getCurrentData = function (keys) {
|
||
var _a;
|
||
var result = {};
|
||
for (var entity in this.store) {
|
||
if (keys && !keys.includes(entity)) {
|
||
continue;
|
||
}
|
||
result[entity] = [];
|
||
for (var rowId in this.store[entity]) {
|
||
(_a = result[entity]) === null || _a === void 0 ? void 0 : _a.push(this.store[entity][rowId]['$current']);
|
||
}
|
||
}
|
||
return result;
|
||
};
|
||
TreeStore.prototype.constructRow = function (node, context, option) {
|
||
var _a, _b, _c;
|
||
var data = (0, lodash_1.cloneDeep)(node.$current);
|
||
if (context.getCurrentTxnId() && node.$txnId === context.getCurrentTxnId()) {
|
||
if (!node.$next) {
|
||
// 如果要求返回delete数据,返回带$$deleteAt$$的行
|
||
if (option === null || option === void 0 ? void 0 : option.includedDeleted) {
|
||
return Object.assign({}, data, (_a = {},
|
||
_a[Entity_1.DeleteAtAttribute] = 1,
|
||
_a));
|
||
}
|
||
return null;
|
||
}
|
||
else if (!node.$current) {
|
||
// 本事务创建的,$$createAt$$和$$updateAt$$置为1
|
||
return Object.assign({}, data, node.$next, (_b = {},
|
||
_b[Entity_1.CreateAtAttribute] = 1,
|
||
_b[Entity_1.UpdateAtAttribute] = 1,
|
||
_b));
|
||
}
|
||
else {
|
||
// 本事务更新的,$$updateAt$$置为1
|
||
return Object.assign({}, data, node.$next, (_c = {},
|
||
_c[Entity_1.UpdateAtAttribute] = 1,
|
||
_c));
|
||
}
|
||
}
|
||
return data;
|
||
};
|
||
TreeStore.prototype.testFilterFns = function (node, nodeDict, exprResolveFns, fns) {
|
||
var e_2, _a, e_3, _b, e_4, _c;
|
||
var self = fns.self, otm = fns.otm, mto = fns.mto;
|
||
try {
|
||
// 三种filterFn是and的关系,有一个失败就返回false,优先判断顺序:self -> mto -> otm
|
||
for (var self_1 = tslib_1.__values(self), self_1_1 = self_1.next(); !self_1_1.done; self_1_1 = self_1.next()) {
|
||
var f = self_1_1.value;
|
||
if (!f(node, nodeDict, exprResolveFns)) {
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
||
finally {
|
||
try {
|
||
if (self_1_1 && !self_1_1.done && (_a = self_1.return)) _a.call(self_1);
|
||
}
|
||
finally { if (e_2) throw e_2.error; }
|
||
}
|
||
try {
|
||
for (var mto_1 = tslib_1.__values(mto), mto_1_1 = mto_1.next(); !mto_1_1.done; mto_1_1 = mto_1.next()) {
|
||
var f = mto_1_1.value;
|
||
if (!f(node, nodeDict, exprResolveFns)) {
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
||
finally {
|
||
try {
|
||
if (mto_1_1 && !mto_1_1.done && (_b = mto_1.return)) _b.call(mto_1);
|
||
}
|
||
finally { if (e_3) throw e_3.error; }
|
||
}
|
||
try {
|
||
for (var otm_1 = tslib_1.__values(otm), otm_1_1 = otm_1.next(); !otm_1_1.done; otm_1_1 = otm_1.next()) {
|
||
var f = otm_1_1.value;
|
||
if (!f(node, nodeDict, exprResolveFns)) {
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
catch (e_4_1) { e_4 = { error: e_4_1 }; }
|
||
finally {
|
||
try {
|
||
if (otm_1_1 && !otm_1_1.done && (_c = otm_1.return)) _c.call(otm_1);
|
||
}
|
||
finally { if (e_4) throw e_4.error; }
|
||
}
|
||
return true;
|
||
};
|
||
TreeStore.prototype.translateLogicFilter = function (entity, filter, attr, context, option) {
|
||
var _this = this;
|
||
var self = [];
|
||
var otm = [];
|
||
var mto = [];
|
||
switch (attr) {
|
||
case '$and': {
|
||
var filters = filter[attr];
|
||
var fns = filters.map(function (ele) { return _this.translateFilterInner(entity, ele, context, option); });
|
||
self.push.apply(self, tslib_1.__spreadArray([], tslib_1.__read((fns.map(function (ele) { return ele.self; }).flat())), false));
|
||
otm.push.apply(otm, tslib_1.__spreadArray([], tslib_1.__read((fns.map(function (ele) { return ele.otm; }).flat())), false));
|
||
mto.push.apply(mto, tslib_1.__spreadArray([], tslib_1.__read((fns.map(function (ele) { return ele.mto; }).flat())), false));
|
||
break;
|
||
}
|
||
case '$or': {
|
||
var filters = filter[attr];
|
||
var fns_1 = filters.map(function (ele) { return _this.translateFilterInner(entity, ele, context, option); });
|
||
/**
|
||
* 对于or的情况,按最坏的一种判定来计算,同时对所有的判定也可以排序,先计算代价最轻的
|
||
*/
|
||
fns_1.sort(function (ele1, ele2) {
|
||
if (ele2.mto.length > 0) {
|
||
return -1;
|
||
}
|
||
else if (ele1.mto.length > 0) {
|
||
return 1;
|
||
}
|
||
else if (ele2.otm.length > 0) {
|
||
return -1;
|
||
}
|
||
else if (ele1.otm.length > 0) {
|
||
return 1;
|
||
}
|
||
return 0;
|
||
});
|
||
var fn = function (node, nodeDict, exprResolveFns) {
|
||
var e_5, _a;
|
||
try {
|
||
for (var fns_2 = tslib_1.__values(fns_1), fns_2_1 = fns_2.next(); !fns_2_1.done; fns_2_1 = fns_2.next()) {
|
||
var fn_1 = fns_2_1.value;
|
||
if (_this.testFilterFns(node, nodeDict, exprResolveFns, fn_1)) {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
catch (e_5_1) { e_5 = { error: e_5_1 }; }
|
||
finally {
|
||
try {
|
||
if (fns_2_1 && !fns_2_1.done && (_a = fns_2.return)) _a.call(fns_2);
|
||
}
|
||
finally { if (e_5) throw e_5.error; }
|
||
}
|
||
return false;
|
||
};
|
||
var last = fns_1[fns_1.length - 1];
|
||
if (last.mto.length > 0) {
|
||
mto.push(fn);
|
||
}
|
||
else if (last.otm.length > 0) {
|
||
otm.push(fn);
|
||
}
|
||
else {
|
||
self.push(fn);
|
||
}
|
||
break;
|
||
}
|
||
case '$not': {
|
||
var filter2 = filter[attr];
|
||
var filterFn_1 = this.translateFilterInner(entity, filter2, context, option);
|
||
var fn = function (node, nodeDict, exprResolveFns) {
|
||
if (_this.testFilterFns(node, nodeDict, exprResolveFns, filterFn_1)) {
|
||
return false;
|
||
}
|
||
return true;
|
||
};
|
||
if (filterFn_1.otm.length > 0) {
|
||
otm.push(fn);
|
||
}
|
||
else if (filterFn_1.mto.length > 0) {
|
||
mto.push(fn);
|
||
}
|
||
else {
|
||
self.push(fn);
|
||
}
|
||
break;
|
||
}
|
||
default: {
|
||
(0, assert_1.assert)(false, "".concat(attr, "\u7B97\u5B50\u6682\u4E0D\u652F\u6301"));
|
||
}
|
||
}
|
||
return {
|
||
self: self,
|
||
otm: otm,
|
||
mto: mto,
|
||
};
|
||
};
|
||
/**
|
||
* 对表达式中某个结点的翻译,有三种情况:
|
||
* 1、结点是一个表达式,此时递归翻译其子结点
|
||
* 2、结点是一个常量,直接返回
|
||
* 3、结点引用了某个属性,此时返回一个函数(ExprNodeTranslator),该函数在实际执行时对某行进行处理,又可能有两种case:
|
||
* 3.1、得到结果,此时返回结果的值(常量)
|
||
* 3.2、还欠缺某些外部结点的值才能得到结果,此时返回一个函数(ExprLaterCheckFn),此函数可以在执行中获得更多结点之后再调用并得到结果的值
|
||
* @param entity
|
||
* @param expression
|
||
* @param context
|
||
* @returns
|
||
*/
|
||
TreeStore.prototype.translateExpressionNode = function (entity, expression, context, option) {
|
||
var _this = this;
|
||
if ((0, Expression_1.isExpression)(expression)) {
|
||
var op_1 = Object.keys(expression)[0];
|
||
var option2_1 = expression[op_1];
|
||
if ((0, Expression_1.opMultipleParams)(op_1)) {
|
||
var paramsTranslated_1 = option2_1.map(function (ele) { return _this.translateExpressionNode(entity, ele, context, option2_1); });
|
||
return function (row, nodeDict) {
|
||
var later = false;
|
||
var results = paramsTranslated_1.map(function (ele) {
|
||
if (typeof ele === 'function') {
|
||
var r = ele(row, nodeDict);
|
||
if (typeof r === 'function') {
|
||
later = true;
|
||
}
|
||
return r;
|
||
}
|
||
return ele;
|
||
});
|
||
if (!later) {
|
||
return (0, Expression_1.execOp)(op_1, results, option2_1.obscure);
|
||
}
|
||
var laterCheckFn = function (nodeDict2) {
|
||
results = results.map(function (ele) {
|
||
if (typeof ele === 'function') {
|
||
var r = ele(nodeDict2);
|
||
return r;
|
||
}
|
||
return ele;
|
||
});
|
||
if (results.find(function (ele) { return typeof ele === 'function'; })) {
|
||
return laterCheckFn;
|
||
}
|
||
return (0, Expression_1.execOp)(op_1, results, option && option.obscure);
|
||
};
|
||
return laterCheckFn;
|
||
};
|
||
}
|
||
else {
|
||
var paramsTranslated_2 = this.translateExpressionNode(entity, option2_1, context, option2_1);
|
||
if (typeof paramsTranslated_2 === 'function') {
|
||
return function (row, nodeDict) {
|
||
var result = paramsTranslated_2(row, nodeDict);
|
||
if (typeof result === 'function') {
|
||
var laterCheckFn_1 = function (nodeDict2) {
|
||
result = result(nodeDict2);
|
||
if (typeof result === 'function') {
|
||
return laterCheckFn_1;
|
||
}
|
||
return result;
|
||
};
|
||
return laterCheckFn_1;
|
||
}
|
||
return (0, Expression_1.execOp)(op_1, result, option2_1.obscure);
|
||
};
|
||
}
|
||
else {
|
||
return function () {
|
||
return (0, Expression_1.execOp)(op_1, paramsTranslated_2, option2_1.obscure);
|
||
};
|
||
}
|
||
}
|
||
}
|
||
else if ((0, Demand_2.isRefAttrNode)(expression)) {
|
||
// 是RefAttr结点
|
||
return function (row, nodeDict) {
|
||
if (expression.hasOwnProperty('#attr')) {
|
||
// 说明是本结点的属性;
|
||
return row[expression['#attr']];
|
||
}
|
||
else {
|
||
(0, assert_1.assert)(expression.hasOwnProperty('#refId'));
|
||
var _a = expression, refId_1 = _a["#refId"], refAttr_1 = _a["#refAttr"];
|
||
if (nodeDict.hasOwnProperty(refId_1)) {
|
||
return nodeDict[refId_1][refAttr_1];
|
||
}
|
||
// 引用的结点还没有取到,此时需要在未来的某个时刻再检查
|
||
var laterCheckFn_2 = function (nodeDict2) {
|
||
if (nodeDict2.hasOwnProperty(refId_1)) {
|
||
return nodeDict2[refId_1][refAttr_1];
|
||
}
|
||
return laterCheckFn_2;
|
||
};
|
||
return laterCheckFn_2;
|
||
}
|
||
};
|
||
}
|
||
else {
|
||
// 是常量结点
|
||
return expression;
|
||
}
|
||
};
|
||
TreeStore.prototype.translateExpression = function (entity, expression, context, option) {
|
||
var expr = this.translateExpressionNode(entity, expression, context, option);
|
||
return function (row, nodeDict) {
|
||
if (typeof expr !== 'function') {
|
||
return expr;
|
||
}
|
||
var result = expr(row, nodeDict);
|
||
return result;
|
||
};
|
||
};
|
||
TreeStore.prototype.translateFulltext = function (entity, filter, context, option) {
|
||
var _this = this;
|
||
// 全文索引查找
|
||
var _a = this.getSchema(), _b = entity, indexes = _a[_b].indexes;
|
||
var fulltextIndex = indexes.find(function (ele) { return ele.config && ele.config.type === 'fulltext'; });
|
||
var attributes = fulltextIndex.attributes;
|
||
var $search = filter.$search;
|
||
return function (node) {
|
||
var e_6, _a;
|
||
var row = _this.constructRow(node, context, option);
|
||
try {
|
||
for (var attributes_1 = tslib_1.__values(attributes), attributes_1_1 = attributes_1.next(); !attributes_1_1.done; attributes_1_1 = attributes_1.next()) {
|
||
var attr = attributes_1_1.value;
|
||
var name_1 = attr.name;
|
||
if (row && row[name_1] && (typeof row[name_1] === 'string' && row[name_1].includes($search) || obscurePass(row[name_1], option))) {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
catch (e_6_1) { e_6 = { error: e_6_1 }; }
|
||
finally {
|
||
try {
|
||
if (attributes_1_1 && !attributes_1_1.done && (_a = attributes_1.return)) _a.call(attributes_1);
|
||
}
|
||
finally { if (e_6) throw e_6.error; }
|
||
}
|
||
return false;
|
||
};
|
||
};
|
||
TreeStore.prototype.translatePredicate = function (path, predicate, value, option) {
|
||
switch (predicate) {
|
||
case '$gt': {
|
||
return function (row) {
|
||
var data = (0, lodash_1.get)(row, path);
|
||
return ['number', 'string'].includes(typeof data) && data > value || obscurePass(data, option);
|
||
};
|
||
}
|
||
case '$lt': {
|
||
return function (row) {
|
||
var data = (0, lodash_1.get)(row, path);
|
||
return ['number', 'string'].includes(typeof data) && data < value || obscurePass(data, option);
|
||
};
|
||
}
|
||
case '$gte': {
|
||
return function (row) {
|
||
var data = (0, lodash_1.get)(row, path);
|
||
return ['number', 'string'].includes(typeof data) && data >= value || obscurePass(data, option);
|
||
};
|
||
}
|
||
case '$lte': {
|
||
return function (row) {
|
||
var data = (0, lodash_1.get)(row, path);
|
||
return ['number', 'string'].includes(typeof data) && data <= value || obscurePass(data, option);
|
||
};
|
||
}
|
||
case '$eq': {
|
||
return function (row) {
|
||
var data = (0, lodash_1.get)(row, path);
|
||
return ['number', 'string'].includes(typeof data) && data === value || obscurePass(data, option);
|
||
};
|
||
}
|
||
case '$ne': {
|
||
return function (row) {
|
||
var data = (0, lodash_1.get)(row, path);
|
||
return ['number', 'string'].includes(typeof data) && data !== value || obscurePass(data, option);
|
||
};
|
||
}
|
||
case '$between': {
|
||
return function (row) {
|
||
var data = (0, lodash_1.get)(row, path);
|
||
return ['number', 'string'].includes(typeof data) && data >= value[0] && data <= value[1] || obscurePass(data, option);
|
||
};
|
||
}
|
||
case '$startsWith': {
|
||
return function (row) {
|
||
var data = (0, lodash_1.get)(row, path);
|
||
return ['string'].includes(typeof data) && data.startsWith(value) || obscurePass(data, option);
|
||
};
|
||
}
|
||
case '$endsWith': {
|
||
return function (row) {
|
||
var data = (0, lodash_1.get)(row, path);
|
||
return ['string'].includes(typeof data) && data.endsWith(value) || obscurePass(data, option);
|
||
};
|
||
}
|
||
case '$includes': {
|
||
return function (row) {
|
||
var data = (0, lodash_1.get)(row, path);
|
||
return ['string'].includes(typeof data) && data.includes(value) || obscurePass(data, option);
|
||
};
|
||
}
|
||
case '$exists': {
|
||
(0, assert_1.assert)(typeof value === 'boolean');
|
||
return function (row) {
|
||
var data = (0, lodash_1.get)(row, path);
|
||
if (value) {
|
||
return ![null, undefined].includes(data) || obscurePass(data, option);
|
||
}
|
||
else {
|
||
return [null, undefined].includes(data) || obscurePass(data, option);
|
||
}
|
||
};
|
||
}
|
||
case '$in': {
|
||
(0, assert_1.assert)(value instanceof Array);
|
||
return function (row) {
|
||
var data = (0, lodash_1.get)(row, path);
|
||
return value.includes(data) || obscurePass(data, option);
|
||
};
|
||
}
|
||
case '$nin': {
|
||
(0, assert_1.assert)(value instanceof Array);
|
||
return function (row) {
|
||
var data = (0, lodash_1.get)(row, path);
|
||
return !value.includes(data) || obscurePass(data, option);
|
||
};
|
||
}
|
||
case '$contains': {
|
||
// json中的多值查询
|
||
var array_1 = value instanceof Array ? value : [value];
|
||
return function (row) {
|
||
var data = (0, lodash_1.get)(row, path);
|
||
return (0, lodash_1.difference)(array_1, data).length === 0 || obscurePass(data, option);
|
||
};
|
||
}
|
||
case '$overlaps': {
|
||
// json中的多值查询
|
||
var array_2 = value instanceof Array ? value : [value];
|
||
return function (row) {
|
||
var data = (0, lodash_1.get)(row, path);
|
||
return (0, lodash_1.intersection)(array_2, data).length > 0 || obscurePass(data, option);
|
||
};
|
||
}
|
||
default: {
|
||
throw new Error("predicate ".concat(predicate, " is not recoganized"));
|
||
}
|
||
}
|
||
};
|
||
TreeStore.prototype.translateObjectPredicate = function (filter) {
|
||
var _this = this;
|
||
var fns = [];
|
||
var translatePredicateInner = function (p, path) {
|
||
var predicate = Object.keys(p)[0];
|
||
if (predicate.startsWith('$')) {
|
||
(0, assert_1.assert)(Object.keys(p).length === 1);
|
||
fns.push(_this.translatePredicate(path, predicate, p[predicate]));
|
||
}
|
||
else {
|
||
if (p instanceof Array) {
|
||
p.forEach(function (ele, idx) {
|
||
var path2 = "".concat(path, "[").concat(idx, "]");
|
||
if (typeof ele !== 'object') {
|
||
if (![null, undefined].includes(ele)) {
|
||
fns.push(_this.translatePredicate(path2, '$eq', ele));
|
||
}
|
||
}
|
||
else {
|
||
translatePredicateInner(ele, path2);
|
||
}
|
||
});
|
||
}
|
||
else {
|
||
for (var attr in p) {
|
||
var path2 = path ? "".concat(path, ".").concat(attr) : attr;
|
||
if (typeof p[attr] !== 'object') {
|
||
fns.push(_this.translatePredicate(path2, '$eq', filter[attr]));
|
||
}
|
||
else {
|
||
translatePredicateInner(p[attr], path2);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
};
|
||
translatePredicateInner(filter, '');
|
||
return function (value) {
|
||
var e_7, _a;
|
||
try {
|
||
for (var fns_3 = tslib_1.__values(fns), fns_3_1 = fns_3.next(); !fns_3_1.done; fns_3_1 = fns_3.next()) {
|
||
var fn = fns_3_1.value;
|
||
if (!fn(value)) {
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
catch (e_7_1) { e_7 = { error: e_7_1 }; }
|
||
finally {
|
||
try {
|
||
if (fns_3_1 && !fns_3_1.done && (_a = fns_3.return)) _a.call(fns_3);
|
||
}
|
||
finally { if (e_7) throw e_7.error; }
|
||
}
|
||
return true;
|
||
};
|
||
};
|
||
TreeStore.prototype.translateAttribute = function (entity, filter, attr, context, option) {
|
||
var _this = this;
|
||
var _a;
|
||
// 如果是模糊查询且该属性为undefined,说明没取到,返回true
|
||
function obscurePassLocal(row) {
|
||
return obscurePass(row[attr], option);
|
||
}
|
||
if (typeof filter !== 'object') {
|
||
return function (node) {
|
||
var row = _this.constructRow(node, context, option);
|
||
return row ? row[attr] === filter || obscurePassLocal(row) : false;
|
||
};
|
||
}
|
||
else {
|
||
var predicate = Object.keys(filter)[0];
|
||
if (predicate.startsWith('$')) {
|
||
if (['$in', '$nin'].includes(predicate) && !(filter[predicate] instanceof Array)) {
|
||
throw new Error('子查询已经改用一对多的外键连接方式');
|
||
var inData_1 = filter[predicate];
|
||
if (predicate === '$in') {
|
||
// 如果是obscure,则返回的集合中有没有都不能否决“可能有”,所以可以直接返回true
|
||
if (option === null || option === void 0 ? void 0 : option.obscure) {
|
||
return function () { return true; };
|
||
}
|
||
else {
|
||
// 这里只有当子查询中的filter不包含引用外部的子查询时才可以提前计算,否则必须等到执行时再计算
|
||
// 子查询查询的行不用返回,和数据库的行为保持一致
|
||
try {
|
||
var legalSets_1 = (this.selectAbjointRow(inData_1.entity, inData_1, context, { dontCollect: true })).map(function (ele) {
|
||
var data = inData_1.data;
|
||
var key = Object.keys(data)[0];
|
||
return ele[key];
|
||
});
|
||
return function (node) {
|
||
var row = _this.constructRow(node, context, option);
|
||
if (!row) {
|
||
return false;
|
||
}
|
||
return legalSets_1.includes(row[attr]);
|
||
};
|
||
}
|
||
catch (err) {
|
||
if (err instanceof OakExpressionUnresolvedException) {
|
||
return function (node, nodeDict) {
|
||
var row = _this.constructRow(node, context, option);
|
||
if (!row) {
|
||
return false;
|
||
}
|
||
var option2 = Object.assign({}, option, { nodeDict: nodeDict });
|
||
var legalSets = _this.selectAbjointRow(inData_1.entity, inData_1, context, option2).map(function (ele) {
|
||
var data = inData_1.data;
|
||
var key = Object.keys(data)[0];
|
||
return ele[key];
|
||
});
|
||
return legalSets.includes(row[attr]);
|
||
};
|
||
}
|
||
else {
|
||
throw err;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
// obscure对nin没有影响,如果返回的子查询结果中包含此行就一定是false,否则一定为true(obscure只考虑数据不完整,不考虑不准确),但若相应属性为undefined则任然可以认为true
|
||
// 这里只有当子查询中的filter不包含引用外部的子查询时才可以提前计算,否则必须等到执行时再计算
|
||
// 子查询查询的行不用返回,和数据库的行为保持一致
|
||
try {
|
||
var legalSets_2 = this.selectAbjointRow(inData_1.entity, inData_1, context, { dontCollect: true }).map(function (ele) {
|
||
var data = inData_1.data;
|
||
var key = Object.keys(data)[0];
|
||
return ele[key];
|
||
});
|
||
return function (node) {
|
||
var row = _this.constructRow(node, context, option);
|
||
if (!row) {
|
||
return false;
|
||
}
|
||
return !legalSets_2.includes(row[attr]) || obscurePassLocal(row);
|
||
};
|
||
}
|
||
catch (err) {
|
||
if (err instanceof OakExpressionUnresolvedException) {
|
||
return function (node, nodeDict) {
|
||
var row = _this.constructRow(node, context, option);
|
||
if (!row) {
|
||
return false;
|
||
}
|
||
var option2 = Object.assign({}, option, { nodeDict: nodeDict });
|
||
var legalSets = _this.selectAbjointRow(inData_1.entity, inData_1, context, option2).map(function (ele) {
|
||
var data = inData_1.data;
|
||
var key = Object.keys(data)[0];
|
||
return ele[key];
|
||
});
|
||
return !legalSets.includes(row[attr]) || obscurePassLocal(row);
|
||
};
|
||
}
|
||
else {
|
||
throw err;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
var fn_2 = this.translatePredicate(attr, predicate, filter[predicate], option);
|
||
return function (node) {
|
||
var row = _this.constructRow(node, context, option);
|
||
if (!row) {
|
||
return false;
|
||
}
|
||
return fn_2(row);
|
||
};
|
||
}
|
||
}
|
||
else {
|
||
// 对象的内部查询
|
||
(0, assert_1.assert)(((_a = this.getSchema()[entity].attributes[attr]) === null || _a === void 0 ? void 0 : _a.type) === 'object');
|
||
var fn_3 = this.translateObjectPredicate(filter);
|
||
return function (node) {
|
||
var row = _this.constructRow(node, context, option);
|
||
if (!row) {
|
||
return false;
|
||
}
|
||
return fn_3(row[attr]) || obscurePassLocal(row);
|
||
};
|
||
}
|
||
}
|
||
};
|
||
TreeStore.prototype.translateFilterInner = function (entity, filter, context, option) {
|
||
var _this = this;
|
||
var self = [];
|
||
var otm = [];
|
||
var mto = [];
|
||
var nodeId;
|
||
var _loop_1 = function (attr) {
|
||
var _a, _b, _c;
|
||
if (attr === '#id') {
|
||
nodeId = filter['#id'];
|
||
}
|
||
else if (['$and', '$or', '$xor', '$not'].includes(attr)) {
|
||
var filterFns = this_1.translateLogicFilter(entity, filter, attr, context, option);
|
||
self.push.apply(self, tslib_1.__spreadArray([], tslib_1.__read((filterFns.self)), false));
|
||
otm.push.apply(otm, tslib_1.__spreadArray([], tslib_1.__read((filterFns.otm)), false));
|
||
mto.push.apply(mto, tslib_1.__spreadArray([], tslib_1.__read((filterFns.mto)), false));
|
||
}
|
||
else if (attr.toLowerCase().startsWith(Demand_1.EXPRESSION_PREFIX)) {
|
||
var fn_4 = this_1.translateExpression(entity, filter[attr], context, option);
|
||
// expression上先假设大都是只查询自身和外层的属性,不一定对。by Xc 20230824
|
||
self.push(function (node, nodeDict, exprResolveFns) {
|
||
var row = _this.constructRow(node, context, option);
|
||
if (!row) {
|
||
return false;
|
||
}
|
||
var result = fn_4(row, nodeDict);
|
||
if (typeof result === 'function') {
|
||
exprResolveFns.push(result);
|
||
}
|
||
return !!result;
|
||
});
|
||
}
|
||
else if (attr.toLowerCase() === '$text') {
|
||
self.push(this_1.translateFulltext(entity, filter[attr], context, option));
|
||
}
|
||
else {
|
||
// 属性级过滤
|
||
var relation_2 = (0, relation_1.judgeRelation)(this_1.getSchema(), entity, attr);
|
||
if (relation_2 === 1) {
|
||
// 行本身的属性
|
||
self.push(this_1.translateAttribute(entity, filter[attr], attr, context, option));
|
||
}
|
||
else if (relation_2 === 2) {
|
||
// 基于entity/entityId的指针
|
||
var filterFn_2 = this_1.translateFilter(attr, filter[attr], context, option);
|
||
mto.push(function (node, nodeDict, exprResolveFns) {
|
||
var row = _this.constructRow(node, context, option);
|
||
if (!row) {
|
||
return false;
|
||
}
|
||
if (obscurePass(row.entity, option) || obscurePass(row.entityId, option)) {
|
||
return true;
|
||
}
|
||
if (row.entity !== attr || !row.entityId) {
|
||
return false;
|
||
}
|
||
var node2 = (0, lodash_1.get)(_this.store, "".concat(attr, ".").concat(row.entityId));
|
||
if (!node2) {
|
||
if (option === null || option === void 0 ? void 0 : option.obscure) {
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
return filterFn_2(node2, nodeDict, exprResolveFns);
|
||
});
|
||
}
|
||
else if (typeof relation_2 === 'string') {
|
||
// 只能是基于普通属性的外键
|
||
var filterFn_3 = this_1.translateFilter(relation_2, filter[attr], context, option);
|
||
mto.push(function (node, nodeDict, exprResolveFns) {
|
||
var row = _this.constructRow(node, context, option);
|
||
if (!row) {
|
||
return false;
|
||
}
|
||
if (obscurePass(row["".concat(attr, "Id")], option)) {
|
||
return true;
|
||
}
|
||
if (row["".concat(attr, "Id")]) {
|
||
var node2 = (0, lodash_1.get)(_this.store, "".concat(relation_2, ".").concat(row["".concat(attr, "Id")]));
|
||
if (!node2) {
|
||
if (option === null || option === void 0 ? void 0 : option.obscure) {
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
return filterFn_3(node2, nodeDict, exprResolveFns);
|
||
}
|
||
return false;
|
||
});
|
||
}
|
||
else if (relation_2 instanceof Array) {
|
||
// 一对多的子查询
|
||
var _d = tslib_1.__read(relation_2, 2), otmEntity_1 = _d[0], otmForeignKey_1 = _d[1];
|
||
var predicate_1 = filter[attr][Demand_1.SUB_QUERY_PREDICATE_KEYWORD] || 'in';
|
||
if (option === null || option === void 0 ? void 0 : option.obscure) {
|
||
// 如果是obscure,则返回的集合中有没有都不能否决“可能有”或“并不全部是”,所以可以直接返回true
|
||
if (['in', 'not all'].includes(predicate_1)) {
|
||
self.push(function () { return true; });
|
||
return "continue";
|
||
}
|
||
}
|
||
var fk_1 = otmForeignKey_1 || 'entityId';
|
||
var otmProjection_1 = (_a = {},
|
||
_a[fk_1] = 1,
|
||
_a);
|
||
/**
|
||
* in代表外键连接后至少有一行数据
|
||
* not in代表外键连接后一行也不能有
|
||
* all代表反外键连接条件的一行也不能有(符合的是否至少要有一行?直觉上没这个限制)
|
||
* not all 代表反外键连接条件的至少有一行
|
||
*
|
||
* 此时还没有确定父行,只有查询中明确带有id的查询可以先执行,否则不执行,暂先这个逻辑 by Xc 20230725
|
||
*/
|
||
var makeAfterLogic = function () {
|
||
otm.push(function (node, nodeDict) {
|
||
var _a, _b;
|
||
var row = _this.constructRow(node, context, option);
|
||
if (!row) {
|
||
return false;
|
||
}
|
||
/**
|
||
* in代表外键连接后至少有一行数据
|
||
* not in代表外键连接后一行也不能有
|
||
* all代表反外键连接条件的一行也不能有(符合的是否至少要有一行?直觉上没这个限制)
|
||
* not all 代表反外键连接条件的至少有一行
|
||
*/
|
||
var otmFilter = !otmForeignKey_1 ? Object.assign({
|
||
entity: entity,
|
||
}, filter[attr]) : (0, lodash_1.cloneDeep)(filter[attr]);
|
||
if (['not in', 'in'].includes(predicate_1)) {
|
||
Object.assign(otmFilter, (_a = {},
|
||
_a[fk_1] = row.id,
|
||
_a));
|
||
}
|
||
else {
|
||
Object.assign(otmFilter, (_b = {},
|
||
_b[fk_1] = {
|
||
$ne: row.id,
|
||
},
|
||
_b));
|
||
}
|
||
var option2 = Object.assign({}, option, { nodeDict: nodeDict, dontCollect: true });
|
||
var subQuerySet = (_this.selectAbjointRow(otmEntity_1, {
|
||
data: otmProjection_1,
|
||
filter: otmFilter,
|
||
indexFrom: 0,
|
||
count: 1,
|
||
}, context, option2)).map(function (ele) {
|
||
return (ele)[fk_1];
|
||
});
|
||
switch (predicate_1) {
|
||
case 'in':
|
||
case 'not all': {
|
||
return subQuerySet.length > 0;
|
||
}
|
||
case 'not in':
|
||
case 'all': {
|
||
return subQuerySet.length === 0;
|
||
}
|
||
default: {
|
||
throw new Error("illegal sqp: ".concat(predicate_1));
|
||
}
|
||
}
|
||
});
|
||
};
|
||
if (filter.id && typeof filter.id === 'string') {
|
||
var otmFilter = !otmForeignKey_1 ? Object.assign({
|
||
entity: entity,
|
||
}, filter[attr]) : (0, lodash_1.cloneDeep)(filter[attr]);
|
||
if (['not in', 'in'].includes(predicate_1)) {
|
||
Object.assign(otmFilter, (_b = {},
|
||
_b[fk_1] = filter.id,
|
||
_b));
|
||
}
|
||
else {
|
||
Object.assign(otmFilter, (_c = {},
|
||
_c[fk_1] = {
|
||
$ne: filter.id,
|
||
},
|
||
_c));
|
||
}
|
||
try {
|
||
var subQuerySet_1 = (this_1.selectAbjointRow(otmEntity_1, {
|
||
data: otmProjection_1,
|
||
filter: otmFilter,
|
||
indexFrom: 0,
|
||
count: 1,
|
||
}, context, { dontCollect: true })).map(function (ele) {
|
||
return (ele)[fk_1];
|
||
});
|
||
self.push(function (node) {
|
||
var row = _this.constructRow(node, context, option);
|
||
if (!row) {
|
||
return false;
|
||
}
|
||
switch (predicate_1) {
|
||
case 'in':
|
||
case 'not all': {
|
||
return subQuerySet_1.length > 0;
|
||
}
|
||
case 'not in':
|
||
case 'all': {
|
||
return subQuerySet_1.length === 0;
|
||
}
|
||
default: {
|
||
throw new Error("illegal sqp: ".concat(predicate_1));
|
||
}
|
||
}
|
||
});
|
||
}
|
||
catch (err) {
|
||
if (err instanceof OakExpressionUnresolvedException) {
|
||
makeAfterLogic();
|
||
}
|
||
else {
|
||
throw err;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
makeAfterLogic();
|
||
}
|
||
}
|
||
else {
|
||
// metadata
|
||
(0, assert_1.assert)(relation_2 === 0);
|
||
}
|
||
}
|
||
};
|
||
var this_1 = this;
|
||
for (var attr in filter) {
|
||
_loop_1(attr);
|
||
}
|
||
return {
|
||
self: self,
|
||
otm: otm,
|
||
mto: mto,
|
||
nodeId: nodeId,
|
||
};
|
||
};
|
||
TreeStore.prototype.translateFilter = function (entity, filter, context, option) {
|
||
var _this = this;
|
||
var filterFns = this.translateFilterInner(entity, filter, context, option);
|
||
var nodeId = filterFns.nodeId;
|
||
return function (node, nodeDict, exprResolveFns) {
|
||
var _a;
|
||
if (nodeId) {
|
||
(0, assert_1.assert)(!nodeDict.hasOwnProperty(nodeId), "Filter\u4E2D\u7684nodeId\u300C".concat(nodeId, "\u300D\u51FA\u73B0\u4E86\u591A\u6B21"));
|
||
Object.assign(nodeDict, (_a = {},
|
||
_a[nodeId] = _this.constructRow(node, context, option),
|
||
_a));
|
||
}
|
||
return _this.testFilterFns(node, nodeDict, exprResolveFns, filterFns);
|
||
};
|
||
};
|
||
TreeStore.prototype.translateSorter = function (entity, sorter, context, option) {
|
||
var _this = this;
|
||
var compare = function (row1, row2, entity2, sortAttr, direction) {
|
||
var row11 = row1;
|
||
var row22 = row2;
|
||
(0, assert_1.assert)(Object.keys(sortAttr).length === 1);
|
||
var attr = Object.keys(sortAttr)[0];
|
||
var relation = (0, relation_1.judgeRelation)(_this.getSchema(), entity2, attr);
|
||
if (relation === 1 || relation === 0) {
|
||
var getAttrOrExprValue = function (r) {
|
||
if (sortAttr[attr] === 1) {
|
||
return r[attr];
|
||
}
|
||
else {
|
||
// 改变策略,让所有需要获得的值在projection上取得
|
||
(0, assert_1.assert)(typeof sortAttr[attr] === 'string' && sortAttr[attr].startsWith('$expr'));
|
||
return r[sortAttr[attr]];
|
||
}
|
||
};
|
||
var v1 = row1 && getAttrOrExprValue(row11);
|
||
var v2 = row2 && getAttrOrExprValue(row22);
|
||
if ([null, undefined].includes(v1) || [null, undefined].includes(v2)) {
|
||
if ([null, undefined].includes(v1) && [null, undefined].includes(v2)) {
|
||
return 0;
|
||
}
|
||
if ([null, undefined].includes(v1)) {
|
||
if (direction === 'asc') {
|
||
return -1;
|
||
}
|
||
return 1;
|
||
}
|
||
if (direction === 'desc') {
|
||
return 1;
|
||
}
|
||
return -1;
|
||
}
|
||
if (v1 > v2) {
|
||
if (direction === 'desc') {
|
||
return -1;
|
||
}
|
||
else {
|
||
return 1;
|
||
}
|
||
}
|
||
else if (v1 < v2) {
|
||
if (direction === 'desc') {
|
||
return 1;
|
||
}
|
||
else {
|
||
return -1;
|
||
}
|
||
}
|
||
else {
|
||
return 0;
|
||
}
|
||
}
|
||
else {
|
||
if (relation === 2) {
|
||
(0, assert_1.assert)(row11['entity'] === row22['entity']);
|
||
(0, assert_1.assert)(row11.entity === attr);
|
||
var node1 = _this.store[row11.entity] && _this.store[row11.entity][row11.entityId];
|
||
var node2 = _this.store[row22.entity] && _this.store[row22.entity][row22.entityId];
|
||
var row111 = node1 && _this.constructRow(node1, context, option);
|
||
var row222 = node2 && _this.constructRow(node2, context, option);
|
||
return compare(row111, row222, row11['entity'], sortAttr[attr], direction);
|
||
}
|
||
else {
|
||
(0, assert_1.assert)(typeof relation === 'string');
|
||
var node1 = _this.store[relation] && _this.store[relation][row11["".concat(attr, "Id")]];
|
||
var node2 = _this.store[relation] && _this.store[relation][row22["".concat(attr, "Id")]];
|
||
var row111 = node1 && _this.constructRow(node1, context, option);
|
||
var row222 = node2 && _this.constructRow(node2, context, option);
|
||
return compare(row111, row222, relation, sortAttr[attr], direction);
|
||
}
|
||
}
|
||
};
|
||
return function (row1, row2) {
|
||
var e_8, _a;
|
||
try {
|
||
for (var sorter_1 = tslib_1.__values(sorter), sorter_1_1 = sorter_1.next(); !sorter_1_1.done; sorter_1_1 = sorter_1.next()) {
|
||
var sorterElement = sorter_1_1.value;
|
||
var $attr = sorterElement.$attr, $direction = sorterElement.$direction;
|
||
var result = compare(row1, row2, entity, $attr, $direction);
|
||
if (result !== 0) {
|
||
return result;
|
||
}
|
||
}
|
||
}
|
||
catch (e_8_1) { e_8 = { error: e_8_1 }; }
|
||
finally {
|
||
try {
|
||
if (sorter_1_1 && !sorter_1_1.done && (_a = sorter_1.return)) _a.call(sorter_1);
|
||
}
|
||
finally { if (e_8) throw e_8.error; }
|
||
}
|
||
return 0;
|
||
};
|
||
};
|
||
TreeStore.prototype.selectAbjointRow = function (entity, selection, context, option) {
|
||
var e_9, _a, e_10, _b;
|
||
var _this = this;
|
||
var filter = selection.filter;
|
||
var nodeDict = option === null || option === void 0 ? void 0 : option.nodeDict;
|
||
var filterFn = filter && this.translateFilter(entity, filter, context, option);
|
||
var entityNodes = this.store[entity] ? Object.values(this.store[entity]) : [];
|
||
var nodes = [];
|
||
try {
|
||
for (var entityNodes_1 = tslib_1.__values(entityNodes), entityNodes_1_1 = entityNodes_1.next(); !entityNodes_1_1.done; entityNodes_1_1 = entityNodes_1.next()) {
|
||
var n = entityNodes_1_1.value;
|
||
// 做个优化,若是插入的行不用等
|
||
if (n.$txnId && n.$txnId !== context.getCurrentTxnId() && n.$current === null) {
|
||
continue;
|
||
}
|
||
(0, assert_1.assert)(!n.$txnId || n.$txnId === context.getCurrentTxnId());
|
||
var exprResolveFns = [];
|
||
var nodeDict2 = {};
|
||
if (nodeDict) {
|
||
Object.assign(nodeDict2, nodeDict);
|
||
}
|
||
// 如果没有filterFn,要保证行不为null(本事务remove的case)
|
||
if (filterFn ? filterFn(n, nodeDict2, exprResolveFns) : this.constructRow(n, context, option)) {
|
||
// 如果有延时处理的expression,在这里加以判断,此时所有在filter中的node应该都已经加以遍历了
|
||
var exprResult = true;
|
||
if (exprResolveFns.length > 0) {
|
||
try {
|
||
for (var exprResolveFns_1 = (e_10 = void 0, tslib_1.__values(exprResolveFns)), exprResolveFns_1_1 = exprResolveFns_1.next(); !exprResolveFns_1_1.done; exprResolveFns_1_1 = exprResolveFns_1.next()) {
|
||
var fn = exprResolveFns_1_1.value;
|
||
var result = fn(nodeDict2);
|
||
if (typeof result === 'function') {
|
||
throw new OakExpressionUnresolvedException();
|
||
}
|
||
if (!!!result) {
|
||
exprResult = false;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
catch (e_10_1) { e_10 = { error: e_10_1 }; }
|
||
finally {
|
||
try {
|
||
if (exprResolveFns_1_1 && !exprResolveFns_1_1.done && (_b = exprResolveFns_1.return)) _b.call(exprResolveFns_1);
|
||
}
|
||
finally { if (e_10) throw e_10.error; }
|
||
}
|
||
}
|
||
if (exprResult) {
|
||
nodes.push(n);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (e_9_1) { e_9 = { error: e_9_1 }; }
|
||
finally {
|
||
try {
|
||
if (entityNodes_1_1 && !entityNodes_1_1.done && (_a = entityNodes_1.return)) _a.call(entityNodes_1);
|
||
}
|
||
finally { if (e_9) throw e_9.error; }
|
||
}
|
||
var rows = nodes.map(function (node) { return _this.constructRow(node, context, option); });
|
||
var rows2 = this.formResult(entity, rows, selection, context, option);
|
||
return rows2;
|
||
};
|
||
TreeStore.prototype.updateAbjointRow = function (entity, operation, context, option) {
|
||
var e_11, _a;
|
||
var data = operation.data, action = operation.action, operId = operation.id;
|
||
switch (action) {
|
||
case 'create': {
|
||
var id = data.id;
|
||
(0, assert_1.assert)(id);
|
||
// const node = this.store[entity] && (this.store[entity]!)[id as string];
|
||
// const row = node && this.constructRow(node, context) || {};
|
||
/* if (row) {
|
||
throw new OakError(RowStore.$$LEVEL, RowStore.$$CODES.primaryKeyConfilict);
|
||
} */
|
||
if (this.store[entity] && (this.store[entity])[id]) {
|
||
var node = this.store[entity] && (this.store[entity])[id];
|
||
throw new Exception_1.OakCongruentRowExists(entity, this.constructRow(node, context, option));
|
||
}
|
||
if (!data.$$seq$$) {
|
||
// tree-store随意生成即可
|
||
Object.assign(data, {
|
||
$$seq$$: "".concat(Math.ceil((Math.random() + 1000) * 100)),
|
||
});
|
||
}
|
||
var node2 = {
|
||
$txnId: context.getCurrentTxnId(),
|
||
$current: null,
|
||
$next: data,
|
||
$path: "".concat(entity, ".").concat(id),
|
||
};
|
||
if (!this.store[entity]) {
|
||
this.store[entity] = {};
|
||
}
|
||
(0, lodash_1.set)(this.store, "".concat(entity, ".").concat(id), node2);
|
||
this.addToTxnNode(node2, context, 'create');
|
||
return 1;
|
||
}
|
||
default: {
|
||
var selection = {
|
||
data: {
|
||
id: 1,
|
||
},
|
||
filter: operation.filter,
|
||
indexFrom: operation.indexFrom,
|
||
count: operation.count,
|
||
};
|
||
var rows = this.selectAbjointRow(entity, selection, context, { dontCollect: true });
|
||
var ids = rows.map(function (ele) { return ele.id; });
|
||
try {
|
||
for (var ids_1 = tslib_1.__values(ids), ids_1_1 = ids_1.next(); !ids_1_1.done; ids_1_1 = ids_1.next()) {
|
||
var id = ids_1_1.value;
|
||
var alreadyDirtyNode = false;
|
||
var node = (this.store[entity])[id];
|
||
(0, assert_1.assert)(node && (!node.$txnId || node.$txnId == context.getCurrentTxnId()));
|
||
if (!node.$txnId) {
|
||
node.$txnId = context.getCurrentTxnId();
|
||
}
|
||
else {
|
||
(0, assert_1.assert)(node.$txnId === context.getCurrentTxnId());
|
||
alreadyDirtyNode = true;
|
||
}
|
||
node.$path = "".concat(entity, ".").concat(id);
|
||
if (action === 'remove') {
|
||
node.$next = null;
|
||
if (!alreadyDirtyNode) {
|
||
// 如果已经更新过的结点就不能再加了,会形成循环
|
||
this.addToTxnNode(node, context, 'remove');
|
||
}
|
||
}
|
||
else {
|
||
node.$next = Object.assign(node.$next || {}, data);
|
||
if (!alreadyDirtyNode) {
|
||
// 如果已经更新过的结点就不能再加了,会形成循环
|
||
this.addToTxnNode(node, context, 'update');
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (e_11_1) { e_11 = { error: e_11_1 }; }
|
||
finally {
|
||
try {
|
||
if (ids_1_1 && !ids_1_1.done && (_a = ids_1.return)) _a.call(ids_1);
|
||
}
|
||
finally { if (e_11) throw e_11.error; }
|
||
}
|
||
return rows.length;
|
||
}
|
||
}
|
||
};
|
||
TreeStore.prototype.selectAbjointRowAsync = function (entity, selection, context, option) {
|
||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||
return tslib_1.__generator(this, function (_a) {
|
||
return [2 /*return*/, this.selectAbjointRow(entity, selection, context, option)];
|
||
});
|
||
});
|
||
};
|
||
TreeStore.prototype.updateAbjointRowAsync = function (entity, operation, context, option) {
|
||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||
return tslib_1.__generator(this, function (_a) {
|
||
return [2 /*return*/, this.updateAbjointRow(entity, operation, context, option)];
|
||
});
|
||
});
|
||
};
|
||
TreeStore.prototype.operateSync = function (entity, operation, context, option) {
|
||
(0, assert_1.assert)(context.getCurrentTxnId());
|
||
return _super.prototype.operateSync.call(this, entity, operation, context, option);
|
||
};
|
||
TreeStore.prototype.operateAsync = function (entity, operation, context, option) {
|
||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||
return tslib_1.__generator(this, function (_a) {
|
||
(0, assert_1.assert)(context.getCurrentTxnId());
|
||
return [2 /*return*/, _super.prototype.operateAsync.call(this, entity, operation, context, option)];
|
||
});
|
||
});
|
||
};
|
||
/**
|
||
* 计算最终结果集当中的函数,这个函数可能测试不够充分
|
||
* @param entity
|
||
* @param projection
|
||
* @param data
|
||
* @param nodeDict
|
||
* @param context
|
||
*/
|
||
TreeStore.prototype.formExprInResult = function (entity, projection, data, nodeDict, context) {
|
||
var _a, _b, _c, _d;
|
||
var _this = this;
|
||
var laterExprDict = {};
|
||
for (var attr in projection) {
|
||
if (attr.startsWith(Demand_1.EXPRESSION_PREFIX)) {
|
||
var ExprNodeTranslator = this.translateExpression(entity, projection[attr], context, {});
|
||
var exprResult = ExprNodeTranslator(data, nodeDict);
|
||
if (typeof exprResult === 'function') {
|
||
Object.assign(laterExprDict, (_a = {},
|
||
_a[attr] = exprResult,
|
||
_a));
|
||
}
|
||
else {
|
||
Object.assign(data, (_b = {},
|
||
_b[attr] = exprResult,
|
||
_b));
|
||
}
|
||
}
|
||
else if (attr === '#id') {
|
||
var nodeId = projection[attr];
|
||
(0, assert_1.assert)(!nodeDict.hasOwnProperty(nodeId), "Filter\u4E2D\u7684nodeId\u300C".concat(nodeId, "\u300D\u51FA\u73B0\u4E86\u591A\u6B21"));
|
||
Object.assign(nodeDict, (_c = {},
|
||
_c[nodeId] = data,
|
||
_c));
|
||
}
|
||
}
|
||
var _loop_2 = function (attr) {
|
||
var rel = this_2.judgeRelation(entity, attr);
|
||
if (rel === 1) {
|
||
}
|
||
else if (rel === 2) {
|
||
if (data[attr]) {
|
||
this_2.formExprInResult(attr, projection[attr], data[attr], nodeDict, context);
|
||
}
|
||
}
|
||
else if (typeof rel === 'string') {
|
||
if (data[attr]) {
|
||
var result2 = {};
|
||
this_2.formExprInResult(rel, projection[attr], data[attr], nodeDict, context);
|
||
}
|
||
}
|
||
else if (rel instanceof Array) {
|
||
if (!attr.endsWith('$$aggr')) {
|
||
if (data[attr] && data[attr] instanceof Array) {
|
||
data[attr].map(function (ele) { return _this.formExprInResult(rel[0], projection[attr].data, ele, nodeDict, context); });
|
||
}
|
||
}
|
||
}
|
||
};
|
||
var this_2 = this;
|
||
for (var attr in projection) {
|
||
_loop_2(attr);
|
||
}
|
||
for (var attr in laterExprDict) {
|
||
var exprResult = laterExprDict[attr](nodeDict);
|
||
// projection是不应出现计算不出来的情况
|
||
(0, assert_1.assert)(typeof exprResult !== 'function', 'data中的expr无法计算,请检查命名与引用的一致性');
|
||
Object.assign(data, (_d = {},
|
||
_d[attr] = exprResult,
|
||
_d));
|
||
}
|
||
};
|
||
TreeStore.prototype.formResult = function (entity, rows, selection, context, option) {
|
||
var e_12, _a, _b, _c, _d;
|
||
var _this = this;
|
||
var data = selection.data, sorter = selection.sorter, indexFrom = selection.indexFrom, count = selection.count;
|
||
var findAvailableExprName = function (current) {
|
||
var counter = 1;
|
||
while (counter < 20) {
|
||
var exprName = "$expr".concat(counter++);
|
||
if (!current.includes(exprName)) {
|
||
return exprName;
|
||
}
|
||
}
|
||
(0, assert_1.assert)(false, '找不到可用的expr命名');
|
||
};
|
||
var sortToProjection = function (entity2, proj, sort) {
|
||
Object.keys(sort).forEach(function (attr) {
|
||
var _a, _b, _c, _d;
|
||
// 要把sorter中的expr运算提到这里做掉,否则异步运算无法排序
|
||
if (attr.startsWith('$expr') && typeof sort[attr] === 'object') {
|
||
var attrName = findAvailableExprName(Object.keys(proj));
|
||
Object.assign(proj, (_a = {},
|
||
_a[attrName] = sort[attr],
|
||
_a));
|
||
Object.assign(sort, (_b = {},
|
||
_b[attr] = attrName,
|
||
_b));
|
||
}
|
||
var rel = (0, relation_1.judgeRelation)(_this.getSchema(), entity2, attr);
|
||
if (rel === 2 || typeof rel === 'string') {
|
||
if (!proj[attr]) {
|
||
Object.assign(proj, (_c = {},
|
||
_c[attr] = {},
|
||
_c));
|
||
}
|
||
var entity3 = typeof rel === 'string' ? rel : attr;
|
||
sortToProjection(entity3, proj[attr], sort[attr]);
|
||
}
|
||
else if (rel === 1) {
|
||
Object.assign(proj, (_d = {},
|
||
_d[attr] = 1,
|
||
_d));
|
||
}
|
||
});
|
||
};
|
||
if (sorter) {
|
||
sorter.forEach(function (ele) {
|
||
sortToProjection(entity, data, ele.$attr);
|
||
});
|
||
}
|
||
// 先计算projection,formResult只处理abjoint的行,不需要考虑expression和一对多多对一关系
|
||
var rows2 = [];
|
||
var incompletedRowIds = [];
|
||
var projection = selection.data;
|
||
try {
|
||
for (var rows_1 = tslib_1.__values(rows), rows_1_1 = rows_1.next(); !rows_1_1.done; rows_1_1 = rows_1.next()) {
|
||
var row = rows_1_1.value;
|
||
var result = {};
|
||
var _loop_3 = function (attr) {
|
||
var _e, _f;
|
||
var rel = this_3.judgeRelation(entity, attr);
|
||
if (rel === 1) {
|
||
if (row[attr] === undefined) {
|
||
incompletedRowIds.push(row.id);
|
||
return "break";
|
||
}
|
||
else if (typeof projection[attr] === 'number') {
|
||
Object.assign(result, (_e = {},
|
||
_e[attr] = row[attr],
|
||
_e));
|
||
}
|
||
else {
|
||
// object数据的深层次select
|
||
Object.assign(result, (_f = {},
|
||
_f[attr] = {},
|
||
_f));
|
||
var assignIner_1 = function (dest, proj, source) {
|
||
if (proj instanceof Array) {
|
||
(0, assert_1.assert)(dest instanceof Array);
|
||
(0, assert_1.assert)(source instanceof Array);
|
||
proj.forEach(function (attr, idx) {
|
||
if (typeof attr === 'number') {
|
||
dest[idx] = source[idx];
|
||
}
|
||
else if (typeof attr === 'object') {
|
||
dest[idx] = {};
|
||
assignIner_1(dest[idx], attr, source[idx]);
|
||
}
|
||
});
|
||
}
|
||
else {
|
||
for (var attr_1 in proj) {
|
||
if (typeof proj[attr_1] === 'number') {
|
||
dest[attr_1] = source[attr_1];
|
||
}
|
||
else if (typeof proj[attr_1] === 'object') {
|
||
dest[attr_1] = proj[attr_1] instanceof Array ? [] : {};
|
||
assignIner_1(dest[attr_1], proj[attr_1], source[attr_1]);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
assignIner_1(result[attr], projection[attr], row[attr]);
|
||
}
|
||
}
|
||
};
|
||
var this_3 = this;
|
||
for (var attr in projection) {
|
||
var state_1 = _loop_3(attr);
|
||
if (state_1 === "break")
|
||
break;
|
||
}
|
||
// 这三个属性在前台cache中可能表达特殊语义的,需要返回
|
||
if (row[Entity_1.DeleteAtAttribute]) {
|
||
Object.assign(result, (_b = {},
|
||
_b[Entity_1.DeleteAtAttribute] = row[Entity_1.DeleteAtAttribute],
|
||
_b));
|
||
}
|
||
if (row[Entity_1.UpdateAtAttribute]) {
|
||
Object.assign(result, (_c = {},
|
||
_c[Entity_1.UpdateAtAttribute] = row[Entity_1.UpdateAtAttribute],
|
||
_c));
|
||
}
|
||
if (row[Entity_1.CreateAtAttribute]) {
|
||
Object.assign(result, (_d = {},
|
||
_d[Entity_1.CreateAtAttribute] = row[Entity_1.CreateAtAttribute],
|
||
_d));
|
||
}
|
||
rows2.push(result);
|
||
}
|
||
}
|
||
catch (e_12_1) { e_12 = { error: e_12_1 }; }
|
||
finally {
|
||
try {
|
||
if (rows_1_1 && !rows_1_1.done && (_a = rows_1.return)) _a.call(rows_1);
|
||
}
|
||
finally { if (e_12) throw e_12.error; }
|
||
}
|
||
if (incompletedRowIds.length > 0) {
|
||
// 如果有缺失属性的行,则报OakRowUnexistedException错误
|
||
// fixed: 这里不报了。按约定框架应当保证取到要访问的属性
|
||
/* throw new OakRowUnexistedException([{
|
||
entity,
|
||
selection: {
|
||
data: projection,
|
||
filter: {
|
||
id: {
|
||
$in: incompletedRowIds,
|
||
},
|
||
},
|
||
},
|
||
}]); */
|
||
}
|
||
// 再计算sorter
|
||
if (sorter) {
|
||
var sorterFn = this.translateSorter(entity, sorter, context, option);
|
||
rows2.sort(sorterFn);
|
||
}
|
||
// 最后用indexFrom和count来截断
|
||
if (typeof indexFrom === 'number') {
|
||
return rows2.slice(indexFrom, indexFrom + count);
|
||
}
|
||
else {
|
||
return rows2;
|
||
}
|
||
};
|
||
/**
|
||
* 本函数把结果中的相应属性映射成一个字符串,用于GroupBy
|
||
* @param entity
|
||
* @param row
|
||
* @param projection
|
||
*/
|
||
TreeStore.prototype.mappingProjectionOnRow = function (entity, row, projection) {
|
||
var _this = this;
|
||
var key = '';
|
||
var result = {};
|
||
var values = [];
|
||
var mappingIter = function (entity2, row2, p2, result2) {
|
||
var e_13, _a;
|
||
var keys = Object.keys(p2).sort(function (ele1, ele2) { return ele1 < ele2 ? -1 : 1; });
|
||
try {
|
||
for (var keys_1 = tslib_1.__values(keys), keys_1_1 = keys_1.next(); !keys_1_1.done; keys_1_1 = keys_1.next()) {
|
||
var k = keys_1_1.value;
|
||
var rel = _this.judgeRelation(entity2, k);
|
||
if (rel === 2) {
|
||
result2[k] = {};
|
||
if (row2[k]) {
|
||
mappingIter(k, row2[k], p2[k], result2[k]);
|
||
}
|
||
}
|
||
else if (typeof rel === 'string') {
|
||
result2[k] = {};
|
||
if (row2[k]) {
|
||
mappingIter(rel, row2[k], p2[k], result2[k]);
|
||
}
|
||
}
|
||
else {
|
||
(0, assert_1.assert)([0, 1].includes(rel));
|
||
result2[k] = row2[k];
|
||
(0, assert_1.assert)(['string', 'number', 'boolean'].includes(typeof row2[k]));
|
||
key += "".concat(row2[k]);
|
||
values.push(row2[k]);
|
||
}
|
||
}
|
||
}
|
||
catch (e_13_1) { e_13 = { error: e_13_1 }; }
|
||
finally {
|
||
try {
|
||
if (keys_1_1 && !keys_1_1.done && (_a = keys_1.return)) _a.call(keys_1);
|
||
}
|
||
finally { if (e_13) throw e_13.error; }
|
||
}
|
||
};
|
||
mappingIter(entity, row, projection, result);
|
||
return {
|
||
result: result,
|
||
key: key,
|
||
values: values,
|
||
};
|
||
};
|
||
TreeStore.prototype.calcAggregation = function (entity, rows, aggregationData) {
|
||
var e_14, _a, e_15, _b, e_16, _c;
|
||
var ops = Object.keys(aggregationData).filter(function (ele) { return ele !== '#aggr'; });
|
||
var result = {};
|
||
try {
|
||
for (var rows_2 = tslib_1.__values(rows), rows_2_1 = rows_2.next(); !rows_2_1.done; rows_2_1 = rows_2.next()) {
|
||
var row = rows_2_1.value;
|
||
try {
|
||
for (var ops_1 = (e_15 = void 0, tslib_1.__values(ops)), ops_1_1 = ops_1.next(); !ops_1_1.done; ops_1_1 = ops_1.next()) {
|
||
var op = ops_1_1.value;
|
||
var values = this.mappingProjectionOnRow(entity, row, aggregationData[op]).values;
|
||
(0, assert_1.assert)(values.length === 1, "\u805A\u5408\u8FD0\u7B97\u4E2D\uFF0C".concat(op, "\u7684\u76EE\u6807\u5C5E\u6027\u591A\u4E8E1\u4E2A"));
|
||
if (op.startsWith('#max')) {
|
||
if (![undefined, null].includes(values[0]) && (!result.hasOwnProperty(op) || result[op] < values[0])) {
|
||
result[op] = values[0];
|
||
}
|
||
}
|
||
else if (op.startsWith('#min')) {
|
||
if (![undefined, null].includes(values[0]) && (!result.hasOwnProperty(op) || result[op] > values[0])) {
|
||
result[op] = values[0];
|
||
}
|
||
}
|
||
else if (op.startsWith('#sum')) {
|
||
if (![undefined, null].includes(values[0])) {
|
||
(0, assert_1.assert)(typeof values[0] === 'number', '只有number类型的属性才可以计算sum');
|
||
if (!result.hasOwnProperty(op)) {
|
||
result[op] = values[0];
|
||
}
|
||
else {
|
||
result[op] += values[0];
|
||
}
|
||
}
|
||
}
|
||
else if (op.startsWith('#count')) {
|
||
if (![undefined, null].includes(values[0])) {
|
||
if (!result.hasOwnProperty(op)) {
|
||
result[op] = 1;
|
||
}
|
||
else {
|
||
result[op] += 1;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
(0, assert_1.assert)(op.startsWith('#avg'));
|
||
if (![undefined, null].includes(values[0])) {
|
||
(0, assert_1.assert)(typeof values[0] === 'number', '只有number类型的属性才可以计算avg');
|
||
if (!result.hasOwnProperty(op)) {
|
||
result[op] = {
|
||
total: values[0],
|
||
count: 1,
|
||
};
|
||
}
|
||
else {
|
||
result[op].total += values[0];
|
||
result[op].count += 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (e_15_1) { e_15 = { error: e_15_1 }; }
|
||
finally {
|
||
try {
|
||
if (ops_1_1 && !ops_1_1.done && (_b = ops_1.return)) _b.call(ops_1);
|
||
}
|
||
finally { if (e_15) throw e_15.error; }
|
||
}
|
||
}
|
||
}
|
||
catch (e_14_1) { e_14 = { error: e_14_1 }; }
|
||
finally {
|
||
try {
|
||
if (rows_2_1 && !rows_2_1.done && (_a = rows_2.return)) _a.call(rows_2);
|
||
}
|
||
finally { if (e_14) throw e_14.error; }
|
||
}
|
||
try {
|
||
for (var ops_2 = tslib_1.__values(ops), ops_2_1 = ops_2.next(); !ops_2_1.done; ops_2_1 = ops_2.next()) {
|
||
var op = ops_2_1.value;
|
||
if (!result[op]) {
|
||
if (op.startsWith('#count')) {
|
||
result[op] = 0;
|
||
}
|
||
else {
|
||
result[op] = null;
|
||
}
|
||
}
|
||
else if (op.startsWith('#avg')) {
|
||
result[op] = result[op].total / result[op].count;
|
||
}
|
||
}
|
||
}
|
||
catch (e_16_1) { e_16 = { error: e_16_1 }; }
|
||
finally {
|
||
try {
|
||
if (ops_2_1 && !ops_2_1.done && (_c = ops_2.return)) _c.call(ops_2);
|
||
}
|
||
finally { if (e_16) throw e_16.error; }
|
||
}
|
||
return result;
|
||
};
|
||
TreeStore.prototype.formAggregation = function (entity, rows, aggregationData) {
|
||
var _this = this;
|
||
var aggrExpr = aggregationData["#aggr"];
|
||
if (aggrExpr) {
|
||
var groups_1 = (0, lodash_1.groupBy)(rows, function (row) {
|
||
var key = _this.mappingProjectionOnRow(entity, row, aggrExpr).key;
|
||
return key;
|
||
});
|
||
var result = Object.keys(groups_1).map(function (ele) {
|
||
var aggr = _this.calcAggregation(entity, groups_1[ele], aggregationData);
|
||
var r = _this.mappingProjectionOnRow(entity, groups_1[ele][0], aggrExpr).result;
|
||
aggr['#data'] = r;
|
||
return aggr;
|
||
});
|
||
return result;
|
||
}
|
||
var aggr = this.calcAggregation(entity, rows, aggregationData);
|
||
return [aggr];
|
||
};
|
||
TreeStore.prototype.selectSync = function (entity, selection, context, option) {
|
||
var _this = this;
|
||
(0, assert_1.assert)(context.getCurrentTxnId());
|
||
var result = _super.prototype.selectSync.call(this, entity, selection, context, option);
|
||
// 在这里再计算所有的表达式
|
||
result.forEach(function (ele) { return _this.formExprInResult(entity, selection.data, ele, {}, context); });
|
||
return result;
|
||
};
|
||
TreeStore.prototype.selectAsync = function (entity, selection, context, option) {
|
||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||
var result;
|
||
var _this = this;
|
||
return tslib_1.__generator(this, function (_a) {
|
||
switch (_a.label) {
|
||
case 0:
|
||
(0, assert_1.assert)(context.getCurrentTxnId());
|
||
return [4 /*yield*/, _super.prototype.selectAsync.call(this, entity, selection, context, option)];
|
||
case 1:
|
||
result = _a.sent();
|
||
// 在这里再计算所有的表达式
|
||
result.forEach(function (ele) { return _this.formExprInResult(entity, selection.data, ele, {}, context); });
|
||
return [2 /*return*/, result];
|
||
}
|
||
});
|
||
});
|
||
};
|
||
TreeStore.prototype.aggregateSync = function (entity, aggregation, context, option) {
|
||
var _this = this;
|
||
(0, assert_1.assert)(context.getCurrentTxnId());
|
||
var data = aggregation.data, filter = aggregation.filter, sorter = aggregation.sorter, indexFrom = aggregation.indexFrom, count = aggregation.count;
|
||
var p = {};
|
||
for (var k in data) {
|
||
Object.assign(p, (0, lodash_1.cloneDeep)(data[k]));
|
||
}
|
||
var selection = {
|
||
data: p,
|
||
filter: filter,
|
||
sorter: sorter,
|
||
indexFrom: indexFrom,
|
||
count: count,
|
||
};
|
||
var result = this.cascadeSelect(entity, selection, context, Object.assign({}, option, {
|
||
dontCollect: true,
|
||
}));
|
||
// 在这里再计算所有的表达式
|
||
result.forEach(function (ele) { return _this.formExprInResult(entity, selection.data, ele, {}, context); });
|
||
// 最后计算Aggregation
|
||
return this.formAggregation(entity, result, aggregation.data);
|
||
};
|
||
TreeStore.prototype.aggregateAsync = function (entity, aggregation, context, option) {
|
||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||
var data, filter, sorter, indexFrom, count, p, k, selection, result;
|
||
var _this = this;
|
||
return tslib_1.__generator(this, function (_a) {
|
||
switch (_a.label) {
|
||
case 0:
|
||
(0, assert_1.assert)(context.getCurrentTxnId());
|
||
data = aggregation.data, filter = aggregation.filter, sorter = aggregation.sorter, indexFrom = aggregation.indexFrom, count = aggregation.count;
|
||
p = {};
|
||
for (k in data) {
|
||
Object.assign(p, (0, lodash_1.cloneDeep)(data[k]));
|
||
}
|
||
selection = {
|
||
data: p,
|
||
filter: filter,
|
||
sorter: sorter,
|
||
indexFrom: indexFrom,
|
||
count: count,
|
||
};
|
||
return [4 /*yield*/, this.cascadeSelectAsync(entity, selection, context, Object.assign({}, option, {
|
||
dontCollect: true,
|
||
}))];
|
||
case 1:
|
||
result = _a.sent();
|
||
// 在这里再计算所有的表达式
|
||
result.forEach(function (ele) { return _this.formExprInResult(entity, selection.data, ele, {}, context); });
|
||
// 最后计算Aggregation
|
||
return [2 /*return*/, this.formAggregation(entity, result, aggregation.data)];
|
||
}
|
||
});
|
||
});
|
||
};
|
||
TreeStore.prototype.countSync = function (entity, selection, context, option) {
|
||
var selection2 = Object.assign({}, selection, {
|
||
data: {
|
||
id: 1,
|
||
},
|
||
});
|
||
var result = this.selectSync(entity, selection2, context, Object.assign({}, option, {
|
||
dontCollect: true,
|
||
}));
|
||
return typeof selection.count === 'number' ? Math.min(result.length, selection.count) : result.length;
|
||
};
|
||
TreeStore.prototype.countAsync = function (entity, selection, context, option) {
|
||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||
var selection2, result;
|
||
return tslib_1.__generator(this, function (_a) {
|
||
switch (_a.label) {
|
||
case 0:
|
||
selection2 = Object.assign({}, selection, {
|
||
data: {
|
||
id: 1,
|
||
},
|
||
});
|
||
return [4 /*yield*/, this.selectAsync(entity, selection2, context, Object.assign({}, option, {
|
||
dontCollect: true,
|
||
}))];
|
||
case 1:
|
||
result = _a.sent();
|
||
return [2 /*return*/, typeof selection.count === 'number' ? Math.min(result.length, selection.count) : result.length];
|
||
}
|
||
});
|
||
});
|
||
};
|
||
TreeStore.prototype.addToTxnNode = function (node, context, action) {
|
||
var txnNode = this.activeTxnDict[context.getCurrentTxnId()];
|
||
(0, assert_1.assert)(txnNode);
|
||
if (!node.$nextNode) {
|
||
// 如果nextNode有值,说明这个结点已经在链表中了
|
||
if (txnNode.nodeHeader) {
|
||
node.$nextNode = txnNode.nodeHeader;
|
||
txnNode.nodeHeader = node;
|
||
}
|
||
else {
|
||
txnNode.nodeHeader = node;
|
||
}
|
||
}
|
||
txnNode[action]++;
|
||
};
|
||
TreeStore.prototype.getStat = function () {
|
||
return this.stat;
|
||
};
|
||
TreeStore.prototype.beginSync = function () {
|
||
var _a;
|
||
var uuid = "".concat(Math.random());
|
||
(0, assert_1.assert)(!this.activeTxnDict.hasOwnProperty(uuid));
|
||
Object.assign(this.activeTxnDict, (_a = {},
|
||
_a[uuid] = {
|
||
create: 0,
|
||
update: 0,
|
||
remove: 0,
|
||
waitList: [],
|
||
},
|
||
_a));
|
||
return uuid;
|
||
};
|
||
TreeStore.prototype.onCommit = function (callback) {
|
||
var _this = this;
|
||
this.commitCallbacks.push(callback);
|
||
return function () { return (0, lodash_1.pull)(_this.commitCallbacks, callback); };
|
||
};
|
||
TreeStore.prototype.addToOperationResult = function (result, entity, action) {
|
||
var _a, _b, _c;
|
||
if (result[entity]) {
|
||
if (result[entity][action]) {
|
||
result[entity][action]++;
|
||
}
|
||
else {
|
||
Object.assign(result[entity], (_a = {},
|
||
_a[action] = 1,
|
||
_a));
|
||
}
|
||
}
|
||
else {
|
||
Object.assign(result, (_b = {},
|
||
_b[entity] = (_c = {},
|
||
_c[action] = 1,
|
||
_c),
|
||
_b));
|
||
}
|
||
};
|
||
TreeStore.prototype.commitSync = function (uuid) {
|
||
var e_17, _a;
|
||
var _b;
|
||
(0, assert_1.assert)(this.activeTxnDict.hasOwnProperty(uuid), uuid);
|
||
var node = this.activeTxnDict[uuid].nodeHeader;
|
||
var result = {};
|
||
while (node) {
|
||
var node2 = node.$nextNode;
|
||
if (node.$txnId === uuid) {
|
||
(0, assert_1.assert)(node.$path);
|
||
var entity = (_b = node.$path) === null || _b === void 0 ? void 0 : _b.split('.')[0];
|
||
if (node.$next) {
|
||
// create/update
|
||
node.$current = Object.assign(node.$current || {}, node.$next);
|
||
if (node.$current) {
|
||
this.addToOperationResult(result, entity, 'create');
|
||
}
|
||
else {
|
||
this.addToOperationResult(result, entity, 'update');
|
||
}
|
||
(0, lodash_1.unset)(node, '$txnId');
|
||
(0, lodash_1.unset)(node, '$next');
|
||
(0, lodash_1.unset)(node, '$path');
|
||
(0, lodash_1.unset)(node, '$nextNode');
|
||
}
|
||
else {
|
||
// remove
|
||
this.addToOperationResult(result, entity, 'remove');
|
||
(0, lodash_1.unset)(this.store, node.$path);
|
||
(0, lodash_1.unset)(node, '$txnId');
|
||
}
|
||
}
|
||
else {
|
||
// 同一行被同一事务更新多次
|
||
(0, assert_1.assert)(node.$txnId === undefined);
|
||
}
|
||
node = node2;
|
||
}
|
||
if (this.activeTxnDict[uuid].create || this.activeTxnDict[uuid].update || this.activeTxnDict[uuid].remove) {
|
||
this.stat.create += this.activeTxnDict[uuid].create;
|
||
this.stat.update += this.activeTxnDict[uuid].update;
|
||
this.stat.remove += this.activeTxnDict[uuid].remove;
|
||
this.stat.commit++;
|
||
}
|
||
try {
|
||
// 唤起等待者
|
||
for (var _c = tslib_1.__values(this.activeTxnDict[uuid].waitList), _d = _c.next(); !_d.done; _d = _c.next()) {
|
||
var waiter = _d.value;
|
||
waiter.fn();
|
||
}
|
||
}
|
||
catch (e_17_1) { e_17 = { error: e_17_1 }; }
|
||
finally {
|
||
try {
|
||
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
|
||
}
|
||
finally { if (e_17) throw e_17.error; }
|
||
}
|
||
(0, lodash_1.unset)(this.activeTxnDict, uuid);
|
||
this.commitCallbacks.forEach(function (callback) { return callback(result); });
|
||
};
|
||
TreeStore.prototype.rollbackSync = function (uuid) {
|
||
var e_18, _a;
|
||
(0, assert_1.assert)(this.activeTxnDict.hasOwnProperty(uuid));
|
||
var node = this.activeTxnDict[uuid].nodeHeader;
|
||
while (node) {
|
||
var node2 = node.$nextNode;
|
||
if (node.$txnId === uuid) {
|
||
if (node.$current) {
|
||
// update/remove
|
||
(0, lodash_1.unset)(node, '$txnId');
|
||
(0, lodash_1.unset)(node, '$next');
|
||
(0, lodash_1.unset)(node, '$path');
|
||
(0, lodash_1.unset)(node, '$nextNode');
|
||
}
|
||
else {
|
||
// create
|
||
(0, assert_1.assert)(node.$path);
|
||
(0, lodash_1.unset)(this.store, node.$path);
|
||
(0, lodash_1.unset)(node, '$txnId');
|
||
}
|
||
}
|
||
else {
|
||
// 该结点被同一事务反复处理
|
||
(0, assert_1.assert)(node.$txnId === undefined);
|
||
}
|
||
node = node2;
|
||
}
|
||
try {
|
||
// 唤起等待者
|
||
for (var _b = tslib_1.__values(this.activeTxnDict[uuid].waitList), _c = _b.next(); !_c.done; _c = _b.next()) {
|
||
var waiter = _c.value;
|
||
waiter.fn();
|
||
}
|
||
}
|
||
catch (e_18_1) { e_18 = { error: e_18_1 }; }
|
||
finally {
|
||
try {
|
||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
|
||
}
|
||
finally { if (e_18) throw e_18.error; }
|
||
}
|
||
(0, lodash_1.unset)(this.activeTxnDict, uuid);
|
||
};
|
||
TreeStore.prototype.beginAsync = function () {
|
||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||
return tslib_1.__generator(this, function (_a) {
|
||
return [2 /*return*/, this.beginSync()];
|
||
});
|
||
});
|
||
};
|
||
TreeStore.prototype.commitAsync = function (uuid) {
|
||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||
return tslib_1.__generator(this, function (_a) {
|
||
return [2 /*return*/, this.commitSync(uuid)];
|
||
});
|
||
});
|
||
};
|
||
TreeStore.prototype.rollbackAsync = function (uuid) {
|
||
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
||
return tslib_1.__generator(this, function (_a) {
|
||
return [2 /*return*/, this.rollbackSync(uuid)];
|
||
});
|
||
});
|
||
};
|
||
// 将输入的OpRecord同步到数据中
|
||
TreeStore.prototype.sync = function (opRecords, context, option) {
|
||
var e_19, _a, e_20, _b;
|
||
var option2 = Object.assign({}, option, {
|
||
dontCollect: true,
|
||
dontCreateOper: true,
|
||
});
|
||
var result = {};
|
||
try {
|
||
for (var opRecords_1 = tslib_1.__values(opRecords), opRecords_1_1 = opRecords_1.next(); !opRecords_1_1.done; opRecords_1_1 = opRecords_1.next()) {
|
||
var record = opRecords_1_1.value;
|
||
switch (record.a) {
|
||
case 'c': {
|
||
var e = record.e, d = record.d;
|
||
if (d instanceof Array) {
|
||
try {
|
||
for (var d_1 = (e_20 = void 0, tslib_1.__values(d)), d_1_1 = d_1.next(); !d_1_1.done; d_1_1 = d_1.next()) {
|
||
var dd = d_1_1.value;
|
||
if (this.store[e] && this.store[e][dd.id]) {
|
||
this.updateAbjointRow(e, {
|
||
id: 'dummy',
|
||
action: 'update',
|
||
data: dd,
|
||
filter: {
|
||
id: dd.id,
|
||
},
|
||
}, context, option2);
|
||
this.addToOperationResult(result, e, 'update');
|
||
}
|
||
else {
|
||
this.updateAbjointRow(e, {
|
||
id: 'dummy',
|
||
action: 'create',
|
||
data: dd,
|
||
}, context, option2);
|
||
this.addToOperationResult(result, e, 'create');
|
||
}
|
||
}
|
||
}
|
||
catch (e_20_1) { e_20 = { error: e_20_1 }; }
|
||
finally {
|
||
try {
|
||
if (d_1_1 && !d_1_1.done && (_b = d_1.return)) _b.call(d_1);
|
||
}
|
||
finally { if (e_20) throw e_20.error; }
|
||
}
|
||
}
|
||
else {
|
||
if (this.store[e] && this.store[e][d.id]) {
|
||
this.updateAbjointRow(e, {
|
||
id: 'dummy',
|
||
action: 'update',
|
||
data: d,
|
||
filter: {
|
||
id: d.id,
|
||
},
|
||
}, context, option2);
|
||
this.addToOperationResult(result, e, 'update');
|
||
}
|
||
else {
|
||
this.updateAbjointRow(e, {
|
||
id: 'dummy',
|
||
action: 'create',
|
||
data: d,
|
||
}, context, option2);
|
||
this.addToOperationResult(result, e, 'create');
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case 'u': {
|
||
var _c = record, e = _c.e, d = _c.d, f = _c.f;
|
||
this.updateAbjointRow(e, {
|
||
id: 'dummy',
|
||
action: 'update',
|
||
data: d,
|
||
filter: f,
|
||
}, context, option2);
|
||
this.addToOperationResult(result, e, 'update');
|
||
break;
|
||
}
|
||
case 'r': {
|
||
var _d = record, e = _d.e, f = _d.f;
|
||
this.updateAbjointRow(e, {
|
||
id: 'dummy',
|
||
action: 'remove',
|
||
data: {},
|
||
filter: f,
|
||
}, context, option2);
|
||
this.addToOperationResult(result, e, 'remove');
|
||
break;
|
||
}
|
||
case 's': {
|
||
var d = record.d;
|
||
for (var entity in d) {
|
||
for (var id in d[entity]) {
|
||
if (this.store[entity] && this.store[entity][id]) {
|
||
this.updateAbjointRow(entity, {
|
||
id: 'dummy',
|
||
action: 'update',
|
||
data: d[entity][id],
|
||
filter: {
|
||
id: id,
|
||
},
|
||
}, context, option2);
|
||
this.addToOperationResult(result, entity, 'update');
|
||
}
|
||
else {
|
||
this.updateAbjointRow(entity, {
|
||
id: 'dummy',
|
||
action: 'create',
|
||
data: d[entity][id],
|
||
}, context, option2);
|
||
this.addToOperationResult(result, entity, 'create');
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
default: {
|
||
(0, assert_1.assert)(false);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (e_19_1) { e_19 = { error: e_19_1 }; }
|
||
finally {
|
||
try {
|
||
if (opRecords_1_1 && !opRecords_1_1.done && (_a = opRecords_1.return)) _a.call(opRecords_1);
|
||
}
|
||
finally { if (e_19) throw e_19.error; }
|
||
}
|
||
this.commitCallbacks.forEach(function (callback) { return callback(result); });
|
||
};
|
||
return TreeStore;
|
||
}(CascadeStore_1.CascadeStore));
|
||
exports.default = TreeStore;
|