oak-db/lib/sqlTranslator.js

901 lines
42 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SqlTranslator = void 0;
var tslib_1 = require("tslib");
var assert_1 = tslib_1.__importDefault(require("assert"));
var lodash_1 = require("lodash");
var types_1 = require("oak-domain/lib/types");
var relation_1 = require("oak-domain/lib/store/relation");
;
;
var SqlTranslator = /** @class */ (function () {
function SqlTranslator(schema) {
this.schema = this.makeFullSchema(schema);
}
SqlTranslator.prototype.makeFullSchema = function (schema2) {
var schema = (0, lodash_1.cloneDeep)(schema2);
for (var entity in schema) {
var _a = schema[entity], attributes = _a.attributes, indexes = _a.indexes;
// 增加默认的属性
(0, lodash_1.assign)(attributes, {
id: {
type: 'char',
params: {
length: 36,
},
},
$$seq$$: {
type: 'sequence',
sequenceStart: 10000,
},
$$createAt$$: {
type: 'datetime',
notNull: true,
},
$$updateAt$$: {
type: 'datetime',
notNull: true,
},
$$deleteAt$$: {
type: 'datetime',
},
$$triggerData$$: {
type: 'object',
},
$$triggerTimestamp$$: {
type: 'datetime',
},
});
// 增加默认的索引
var intrinsticIndexes = [
{
name: "".concat(entity, "_create_at_auto_create"),
attributes: [{
name: '$$createAt$$',
}, {
name: '$$deleteAt$$',
}]
}, {
name: "".concat(entity, "_update_at_auto_create"),
attributes: [{
name: '$$updateAt$$',
}, {
name: '$$deleteAt$$',
}],
}, {
name: "".concat(entity, "_trigger_ts_auto_create"),
attributes: [{
name: '$$triggerTimestamp$$',
}, {
name: '$$deleteAt$$',
}],
}
];
var _loop_1 = function (attr) {
if (attributes[attr].type === 'ref') {
if (!(indexes === null || indexes === void 0 ? void 0 : indexes.find(function (ele) { return ele.attributes[0].name === attr; }))) {
intrinsticIndexes.push({
name: "".concat(entity, "_fk_").concat(attr, "_auto_create"),
attributes: [{
name: attr,
}, {
name: '$$deleteAt$$',
}]
});
}
}
if (attr === 'entity' && attributes[attr].type === 'varchar') {
var entityIdDef = attributes.entityId;
if ((entityIdDef === null || entityIdDef === void 0 ? void 0 : entityIdDef.type) === 'varchar') {
if (!(indexes === null || indexes === void 0 ? void 0 : indexes.find(function (ele) { var _a; return ele.attributes[0].name === 'entity' && ((_a = ele.attributes[1]) === null || _a === void 0 ? void 0 : _a.name) === 'entityId'; }))) {
intrinsticIndexes.push({
name: "".concat(entity, "_fk_entity_entityId_auto_create"),
attributes: [{
name: 'entity',
}, {
name: 'entityId',
}, {
name: '$$deleteAt$$',
}]
});
}
}
}
if (attr.endsWith('State') && attributes[attr].type === 'varchar') {
if (!(indexes === null || indexes === void 0 ? void 0 : indexes.find(function (ele) { return ele.attributes[0].name === attr; }))) {
intrinsticIndexes.push({
name: "".concat(entity, "_").concat(attr, "_auto_create"),
attributes: [{
name: attr,
}, {
name: '$$deleteAt$$',
}]
});
}
}
if (attr === 'expired' && attributes[attr].type === 'boolean') {
var expiresAtDef = attributes.expiresAt;
if ((expiresAtDef === null || expiresAtDef === void 0 ? void 0 : expiresAtDef.type) === 'datetime') {
if (!(indexes === null || indexes === void 0 ? void 0 : indexes.find(function (ele) { var _a; return ele.attributes[0].name === 'expired' && ((_a = ele.attributes[1]) === null || _a === void 0 ? void 0 : _a.name) === 'expiresAt'; }))) {
intrinsticIndexes.push({
name: "".concat(entity, "_expires_expiredAt_auto_create"),
attributes: [{
name: 'expired',
}, {
name: 'expiresAt',
}, {
name: '$$deleteAt$$',
}]
});
}
}
}
};
// 增加外键等相关属性上的索引
for (var attr in attributes) {
_loop_1(attr);
}
if (indexes) {
indexes.push.apply(indexes, intrinsticIndexes);
}
else {
(0, lodash_1.assign)(schema[entity], {
indexes: intrinsticIndexes,
});
}
}
return schema;
};
SqlTranslator.prototype.getStorageName = function (entity) {
var storageName = this.schema[entity].storageName;
return (storageName || entity);
};
SqlTranslator.prototype.translateInsert = function (entity, data) {
var _this = this;
var schema = this.schema;
var _a = schema[entity], attributes = _a.attributes, _b = _a.storageName, storageName = _b === void 0 ? entity : _b;
var sql = "insert into `".concat(storageName, "`(");
/**
* 这里的attrs要用所有行的union集合
*/
var dataFull = data.reduce(function (prev, cur) { return Object.assign({}, cur, prev); }, {});
var attrs = Object.keys(dataFull).filter(function (ele) { return attributes.hasOwnProperty(ele); });
attrs.forEach(function (attr, idx) {
sql += " `".concat(attr, "`");
if (idx < attrs.length - 1) {
sql += ',';
}
});
sql += ') values ';
data.forEach(function (d, dataIndex) {
sql += '(';
attrs.forEach(function (attr, attrIdx) {
var attrDef = attributes[attr];
var dataType = attrDef.type;
var value = _this.translateAttrValue(dataType, d[attr]);
sql += value;
if (attrIdx < attrs.length - 1) {
sql += ',';
}
});
if (dataIndex < data.length - 1) {
sql += '),';
}
else {
sql += ')';
}
});
return sql;
};
/**
* analyze the join relations in projection/query/sort
* 所有的层次关系都当成left join处理如果有内表为空的情况请手动处理
* {
* b: {
* name: {
* $exists: false,
* }
* }
* }
* 这样的query会把内表为空的行也返回
* @param param0
*/
SqlTranslator.prototype.analyzeJoin = function (entity, _a, initialNumber) {
var _this = this;
var projection = _a.projection, filter = _a.filter, sorter = _a.sorter, aggregation = _a.aggregation;
var schema = this.schema;
var number = initialNumber || 1;
var projectionRefAlias = {};
var filterRefAlias = {};
var extraWhere = '';
var alias = "".concat(entity, "_").concat(number++);
var from = " `".concat(this.getStorageName(entity), "` `").concat(alias, "` ");
var aliasDict = {
'./': alias,
};
var analyzeFilterNode = function (_a) {
var _b;
var node = _a.node, path = _a.path, entityName = _a.entityName, alias = _a.alias;
Object.keys(node).forEach(function (op) {
var _a, _b;
if (['$and', '$or'].includes(op)) {
node[op].forEach(function (subNode) { return analyzeFilterNode({
node: subNode,
path: path,
entityName: entityName,
alias: alias,
}); });
}
else if (['$not'].includes(op)) {
analyzeFilterNode({
node: node[op],
path: path,
entityName: entityName,
alias: alias,
});
}
else if (['$text'].includes(op)) {
}
else {
var rel = (0, relation_1.judgeRelation)(_this.schema, entityName, op);
if (typeof rel === 'string') {
var alias2 = void 0;
var pathAttr = "".concat(path).concat(op, "/");
if (!aliasDict.hasOwnProperty(pathAttr)) {
alias2 = "".concat(rel, "_").concat(number++);
(0, lodash_1.assign)(aliasDict, (_a = {},
_a[pathAttr] = alias2,
_a));
from += " left join `".concat(_this.getStorageName(rel), "` `").concat(alias2, "` on `").concat(alias, "`.`").concat(op, "Id` = `").concat(alias2, "`.`id`");
}
else {
alias2 = aliasDict[pathAttr];
}
analyzeFilterNode({
node: node[op],
path: pathAttr,
entityName: rel,
alias: alias2,
});
}
else if (rel === 2) {
var alias2 = void 0;
var pathAttr = "".concat(path).concat(op, "/");
if (!aliasDict.hasOwnProperty(pathAttr)) {
alias2 = "".concat(op, "_").concat(number++);
(0, lodash_1.assign)(aliasDict, (_b = {},
_b[pathAttr] = alias2,
_b));
from += " left join `".concat(_this.getStorageName(op), "` `").concat(alias2, "` on `").concat(alias, "`.`entityId` = `").concat(alias2, "`.`id` and `").concat(alias, "`.`entity` = '").concat(op, "'");
}
else {
alias2 = aliasDict[pathAttr];
}
analyzeFilterNode({
node: node[op],
path: pathAttr,
entityName: op,
alias: alias2,
});
}
else {
// 不支持一对多
(0, assert_1.default)(rel === 0 || rel === 1);
}
}
});
if (node['#id']) {
(0, assert_1.default)(!filterRefAlias[node['#id']]);
(0, lodash_1.assign)(filterRefAlias, (_b = {},
_b[node['#id']] = [alias, entityName],
_b));
}
};
if (filter) {
analyzeFilterNode({
node: filter,
path: './',
entityName: entity,
alias: alias,
});
}
var analyzeSortNode = function (_a) {
var _b, _c;
var node = _a.node, path = _a.path, entityName = _a.entityName, alias = _a.alias;
var attr = (0, lodash_1.keys)(node)[0];
var rel = (0, relation_1.judgeRelation)(_this.schema, entityName, attr);
if (typeof rel === 'string') {
var pathAttr = "".concat(path).concat(attr, "/");
var alias2 = void 0;
if (!aliasDict.hasOwnProperty(pathAttr)) {
alias2 = "".concat(rel, "_").concat(number++);
(0, lodash_1.assign)(aliasDict, (_b = {},
_b[pathAttr] = alias2,
_b));
from += " left join `".concat(_this.getStorageName(rel), "` `").concat(alias2, "` on `").concat(alias, "`.`").concat(attr, "Id` = `").concat(alias2, "`.`id`");
}
else {
alias2 = aliasDict[pathAttr];
}
analyzeSortNode({
node: node[attr],
path: pathAttr,
entityName: rel,
alias: alias2,
});
}
else if (rel === 2) {
var pathAttr = "".concat(path).concat(attr, "/");
var alias2 = void 0;
if (!aliasDict.hasOwnProperty(pathAttr)) {
alias2 = "".concat(attr, "_").concat(number++);
(0, lodash_1.assign)(aliasDict, (_c = {},
_c[pathAttr] = alias2,
_c));
from += " left join `".concat(_this.getStorageName(attr), "` `").concat(alias2, "` on `").concat(alias, "`.`entityId` = `").concat(alias2, "`.`id` and `").concat(alias, "`.`entity` = '").concat(attr, "'");
}
else {
alias2 = aliasDict[pathAttr];
}
analyzeSortNode({
node: node[attr],
path: pathAttr,
entityName: attr,
alias: alias2,
});
}
else {
(0, assert_1.default)(rel === 0 || rel === 1);
}
};
if (sorter) {
sorter.forEach(function (sortNode) {
analyzeSortNode({
node: sortNode.$attr,
path: './',
entityName: entity,
alias: alias,
});
});
}
var analyzeProjectionNode = function (_a) {
var _b;
var node = _a.node, path = _a.path, entityName = _a.entityName, alias = _a.alias;
var attributes = schema[entityName].attributes;
Object.keys(node).forEach(function (attr) {
var _a, _b;
var rel = (0, relation_1.judgeRelation)(_this.schema, entityName, attr);
if (typeof rel === 'string') {
var pathAttr = "".concat(path).concat(attr, "/");
var alias2 = void 0;
if (!aliasDict.hasOwnProperty(pathAttr)) {
alias2 = "".concat(rel, "_").concat(number++);
(0, lodash_1.assign)(aliasDict, (_a = {},
_a[pathAttr] = alias2,
_a));
from += " left join `".concat(_this.getStorageName(rel), "` `").concat(alias2, "` on `").concat(alias, "`.`").concat(attr, "Id` = `").concat(alias2, "`.`id`");
}
else {
alias2 = aliasDict[pathAttr];
}
analyzeProjectionNode({
node: node[attr],
path: pathAttr,
entityName: rel,
alias: alias2,
});
}
else if (rel === 2) {
var pathAttr = "".concat(path).concat(attr, "/");
var alias2 = void 0;
if (!aliasDict.hasOwnProperty(pathAttr)) {
alias2 = "".concat(attr, "_").concat(number++);
(0, lodash_1.assign)(aliasDict, (_b = {},
_b[pathAttr] = alias2,
_b));
from += " left join `".concat(_this.getStorageName(attr), "` `").concat(alias2, "` on `").concat(alias, "`.`entityId` = `").concat(alias2, "`.`id` and `").concat(alias, "`.`entity` = '").concat(attr, "'");
}
else {
alias2 = aliasDict[pathAttr];
}
analyzeProjectionNode({
node: node[attr],
path: pathAttr,
entityName: attr,
alias: alias2,
});
}
});
if (node['#id']) {
(0, assert_1.default)(!projectionRefAlias[node['#id']], "projection\u4E0A\u6709\u91CD\u590D\u7684#id\u5B9A\u4E49\u300C".concat(node['#id'], "\u300D"));
(0, lodash_1.assign)(projectionRefAlias, (_b = {},
_b[node['#id']] = [alias, entityName],
_b));
}
};
if (projection) {
analyzeProjectionNode({ node: projection, path: './', entityName: entity, alias: alias });
}
else if (aggregation) {
for (var k in aggregation) {
analyzeProjectionNode({
node: aggregation[k],
path: './',
entityName: entity,
alias: alias,
});
}
}
return {
aliasDict: aliasDict,
from: from,
projectionRefAlias: projectionRefAlias,
filterRefAlias: filterRefAlias,
extraWhere: extraWhere,
currentNumber: number,
};
};
SqlTranslator.prototype.translateComparison = function (attr, value, type) {
var SQL_OP = {
$gt: '>',
$lt: '<',
$gte: '>=',
$lte: '<=',
$eq: '=',
$ne: '<>',
};
if (Object.keys(SQL_OP).includes(attr)) {
return " ".concat(SQL_OP[attr], " ").concat(this.translateAttrValue(type, value));
}
switch (attr) {
case '$startsWith': {
return " like '".concat(value, "%'");
}
case '$endsWith': {
return " like '%".concat(value, "'");
}
case '$includes': {
return " like '%".concat(value, "%'");
}
default: {
throw new Error("unrecoganized comparison operator ".concat(attr));
}
}
};
SqlTranslator.prototype.translateElement = function (attr, value) {
(0, assert_1.default)(attr === '$exists'); // only support one operator now
if (value) {
return ' is not null';
}
return ' is null';
};
SqlTranslator.prototype.translateEvaluation = function (attr, value, entity, alias, type, initialNumber, refAlias) {
switch (attr) {
case '$text': {
// fulltext search
return {
stmt: this.translateFullTextSearch(value, entity, alias),
currentNumber: initialNumber,
};
}
case '$in':
case '$nin': {
var IN_OP = {
$in: 'in',
$nin: 'not in',
};
if (value instanceof Array) {
var values = value.map(function (v) {
if (['varchar', 'char', 'text', 'nvarchar', 'ref', 'enum'].includes(type)) {
return "'".concat(v, "'");
}
else {
return "".concat(v);
}
});
if (values.length > 0) {
return {
stmt: " ".concat(IN_OP[attr], "(").concat(values.join(','), ")"),
currentNumber: initialNumber,
};
}
else {
if (attr === '$in') {
return {
stmt: ' in (null)',
currentNumber: initialNumber,
};
}
else {
return {
stmt: ' is not null',
currentNumber: initialNumber,
};
}
}
}
else {
// sub query
var _a = this.translateSelectInner(value.entity, value, initialNumber, refAlias, undefined), subQueryStmt = _a.stmt, currentNumber = _a.currentNumber;
return {
stmt: " ".concat(IN_OP[attr], "(").concat(subQueryStmt, ")"),
currentNumber: currentNumber,
};
}
}
default: {
(0, assert_1.default)('$between' === attr);
var values = value.map(function (v) {
if (['varchar', 'char', 'text', 'nvarchar', 'ref'].includes(type)) {
return "'".concat(v, "'");
}
else {
return "".concat(v);
}
});
return {
stmt: " between ".concat(values[0], " and ").concat(values[1]),
currentNumber: initialNumber,
};
}
}
};
SqlTranslator.prototype.translateFilter = function (entity, selection, aliasDict, filterRefAlias, initialNumber, extraWhere, option) {
var _this = this;
var schema = this.schema;
var filter = selection.filter;
var currentNumber = initialNumber;
var translateInner = function (entity2, path, filter2, type) {
var alias = aliasDict[path];
var attributes = schema[entity2].attributes;
var whereText = type ? '' : _this.getDefaultSelectFilter(alias, option);
if (filter2) {
var attrs = Object.keys(filter2).filter(function (ele) { return !ele.startsWith('#'); });
attrs.forEach(function (attr) {
if (whereText) {
whereText += ' and ';
}
if (['$and', '$or', '$xor', '$not'].includes(attr)) {
var result = '';
whereText += '(';
switch (attr) {
case '$and':
case '$or':
case '$xor': {
var logicQueries_1 = filter2[attr];
logicQueries_1.forEach(function (logicQuery, index) {
var sql = translateInner(entity2, path, logicQuery);
if (sql) {
whereText += " (".concat(sql, ")");
if (index < logicQueries_1.length - 1) {
whereText += " ".concat(attr.slice(1));
}
}
});
break;
}
default: {
(0, assert_1.default)(attr === '$not');
var logicQuery = filter2[attr];
var sql = translateInner(entity2, path, logicQuery);
if (sql) {
whereText += " not (".concat(translateInner(entity2, path, logicQuery), ")");
break;
}
}
}
whereText += ')';
}
else if (attr.toLowerCase().startsWith(types_1.EXPRESSION_PREFIX)) {
// expression
whereText += " (".concat(_this.translateExpression(entity2, alias, filter2[attr], filterRefAlias), ")");
}
else if (['$gt', '$gte', '$lt', '$lte', '$eq', '$ne', '$startsWith', '$endsWith', '$includes'].includes(attr)) {
whereText += _this.translateComparison(attr, filter2[attr], type);
}
else if (['$exists'].includes(attr)) {
whereText += _this.translateElement(attr, filter2[attr]);
}
else if (['$text', '$in', '$nin', '$between'].includes(attr)) {
var _a = _this.translateEvaluation(attr, filter2[attr], entity2, alias, type, initialNumber, filterRefAlias), stmt = _a.stmt, cn2 = _a.currentNumber;
whereText += stmt;
currentNumber = cn2;
}
else {
var rel = (0, relation_1.judgeRelation)(_this.schema, entity2, attr);
if (rel === 2) {
whereText += " (".concat(translateInner(attr, "".concat(path).concat(attr, "/"), filter2[attr]), ")");
}
else if (typeof rel === 'string') {
whereText += " (".concat(translateInner(rel, "".concat(path).concat(attr, "/"), filter2[attr]), ")");
}
else {
(0, assert_1.default)(attributes.hasOwnProperty(attr), "\u975E\u6CD5\u7684\u5C5E\u6027".concat(attr));
var type2 = attributes[attr].type;
// assert (type2 !== 'ref');
if (typeof filter2[attr] === 'object' && Object.keys(filter2[attr])[0] && Object.keys(filter2[attr])[0].startsWith('$')) {
whereText += " (`".concat(alias, "`.`").concat(attr, "` ").concat(translateInner(entity2, path, filter2[attr], type2), ")");
}
else {
whereText += " (`".concat(alias, "`.`").concat(attr, "` = ").concat(_this.translateAttrValue(type2, filter2[attr]), ")");
}
}
}
});
}
if (!whereText) {
whereText = 'true'; // 如果为空就赋一个永真条件以便处理and
}
return whereText;
};
var where = translateInner(entity, './', filter);
if (extraWhere && where) {
return {
stmt: "".concat(extraWhere, " and ").concat(where),
currentNumber: currentNumber,
};
}
return {
stmt: extraWhere || where,
currentNumber: currentNumber,
};
};
SqlTranslator.prototype.translateSorter = function (entity, sorter, aliasDict) {
var _this = this;
var translateInner = function (entity2, sortAttr, path) {
(0, assert_1.default)(Object.keys(sortAttr).length === 1);
var attr = Object.keys(sortAttr)[0];
var alias = aliasDict[path];
if (attr.toLocaleLowerCase().startsWith(types_1.EXPRESSION_PREFIX)) {
return _this.translateExpression(entity2, alias, sortAttr[attr], {});
}
else if (sortAttr[attr] === 1) {
return "`".concat(alias, "`.`").concat(attr, "`");
}
else {
var rel = (0, relation_1.judgeRelation)(_this.schema, entity2, attr);
if (typeof rel === 'string') {
return translateInner(rel, sortAttr[attr], "".concat(path).concat(attr, "/"));
}
else {
(0, assert_1.default)(rel === 2);
return translateInner(attr, sortAttr[attr], "".concat(path).concat(attr, "/"));
}
}
};
var sortText = '';
sorter.forEach(function (sortNode, index) {
var $attr = sortNode.$attr, $direction = sortNode.$direction;
sortText += translateInner(entity, $attr, './');
if ($direction) {
sortText += " ".concat($direction);
}
if (index < sorter.length - 1) {
sortText += ',';
}
});
return sortText;
};
SqlTranslator.prototype.translateProjection = function (entity, projection, aliasDict, projectionRefAlias, commonPrefix, disableAs) {
var _this = this;
var schema = this.schema;
var as = '';
var translateInner = function (entity2, projection2, path) {
var alias = aliasDict[path];
var attributes = schema[entity2].attributes;
var projText = '';
var prefix = path.slice(2).replace(/\//g, '.');
var attrs = Object.keys(projection2).filter(function (attr) {
if (attr.toLowerCase().startsWith(types_1.EXPRESSION_PREFIX)) {
return true;
}
var rel = (0, relation_1.judgeRelation)(_this.schema, entity2, attr);
return [1, 2].includes(rel) || typeof rel === 'string';
});
attrs.forEach(function (attr, idx) {
var prefix2 = commonPrefix ? "".concat(commonPrefix, ".").concat(prefix) : prefix;
if (attr.toLowerCase().startsWith(types_1.EXPRESSION_PREFIX)) {
var exprText = _this.translateExpression(entity2, alias, projection2[attr], projectionRefAlias);
if (disableAs) {
projText += " ".concat(exprText);
}
else {
projText += " ".concat(exprText, " as `").concat(prefix2).concat(attr, "`");
if (!as) {
as = "`".concat(prefix2).concat(attr, "`");
}
else {
as += ", `".concat(prefix2).concat(attr, "`");
}
}
}
else {
var rel = (0, relation_1.judgeRelation)(_this.schema, entity2, attr);
if (typeof rel === 'string') {
projText += translateInner(rel, projection2[attr], "".concat(path).concat(attr, "/"));
}
else if (rel === 2) {
projText += translateInner(attr, projection2[attr], "".concat(path).concat(attr, "/"));
}
else if (rel === 1) {
var type = attributes[attr].type;
if (projection2[attr] === 1) {
if (disableAs) {
projText += " ".concat(_this.translateAttrProjection(type, alias, attr));
}
else {
projText += " ".concat(_this.translateAttrProjection(type, alias, attr), " as `").concat(prefix2).concat(attr, "`");
if (!as) {
as = "`".concat(prefix2).concat(attr, "`");
}
else {
as += ", `".concat(prefix2).concat(attr, "`");
}
}
}
else {
(0, assert_1.default)(typeof projection2 === 'string');
if (disableAs) {
projText += " ".concat(_this.translateAttrProjection(type, alias, attr));
}
else {
projText += " ".concat(_this.translateAttrProjection(type, alias, attr), " as `").concat(prefix2).concat(projection2[attr], "`");
if (!as) {
as = "`".concat(prefix2).concat(projection2[attr], "`");
}
else {
as += "`".concat(prefix2).concat(projection2[attr], "`");
}
}
}
}
}
if (idx < attrs.length - 1) {
projText += ',';
}
});
return projText;
};
return {
projText: translateInner(entity, projection, './'),
as: as,
};
};
SqlTranslator.prototype.translateSelectInner = function (entity, selection, initialNumber, refAlias, option) {
var data = selection.data, filter = selection.filter, sorter = selection.sorter, indexFrom = selection.indexFrom, count = selection.count;
var _a = this.analyzeJoin(entity, {
projection: data,
filter: filter,
sorter: sorter,
}, initialNumber), fromText = _a.from, aliasDict = _a.aliasDict, projectionRefAlias = _a.projectionRefAlias, extraWhere = _a.extraWhere, filterRefAlias = _a.filterRefAlias, currentNumber = _a.currentNumber;
(0, assert_1.default)((0, lodash_1.intersection)((0, lodash_1.keys)(refAlias), (0, lodash_1.keys)(filterRefAlias)).length === 0, 'filter中的#node结点定义有重复');
(0, lodash_1.assign)(refAlias, filterRefAlias);
var projText = this.translateProjection(entity, data, aliasDict, projectionRefAlias).projText;
var _b = this.translateFilter(entity, selection, aliasDict, refAlias, currentNumber, extraWhere, option), filterText = _b.stmt, currentNumber2 = _b.currentNumber;
var sorterText = sorter && this.translateSorter(entity, sorter, aliasDict);
return {
stmt: this.populateSelectStmt(projText, fromText, aliasDict, filterText, sorterText, undefined, indexFrom, count, option, selection),
currentNumber: currentNumber2,
filterStmt: filterText,
};
};
SqlTranslator.prototype.translateSelect = function (entity, selection, option) {
var stmt = this.translateSelectInner(entity, selection, 1, {}, option).stmt;
return stmt;
};
SqlTranslator.prototype.translateWhere = function (entity, selection, option) {
var filterStmt = this.translateSelectInner(entity, selection, 1, {}, option).filterStmt;
return filterStmt;
};
SqlTranslator.prototype.translateAggregate = function (entity, aggregation, option) {
var data = aggregation.data, filter = aggregation.filter, sorter = aggregation.sorter, indexFrom = aggregation.indexFrom, count = aggregation.count;
var _a = this.analyzeJoin(entity, {
aggregation: data,
filter: filter,
sorter: sorter,
}, 1), fromText = _a.from, aliasDict = _a.aliasDict, projectionRefAlias = _a.projectionRefAlias, extraWhere = _a.extraWhere, filterRefAlias = _a.filterRefAlias, currentNumber = _a.currentNumber;
var projText = '';
var groupByText = '';
for (var k in data) {
if (k === '#aggr') {
var _b = this.translateProjection(entity, data[k], aliasDict, projectionRefAlias, '#data'), projSubText = _b.projText, as = _b.as;
if (!projText) {
projText = projSubText;
}
else {
projText += ", ".concat(projSubText);
}
groupByText = as;
}
else {
var projSubText = this.translateProjection(entity, data[k], aliasDict, projectionRefAlias, undefined, true).projText;
var projSubText2 = '';
if (k.startsWith('#max')) {
projSubText2 = "max(".concat(projSubText, ") as `").concat(k, "`");
}
else if (k.startsWith('#min')) {
projSubText2 = "min(".concat(projSubText, ") as `").concat(k, "`");
}
else if (k.startsWith('#count')) {
projSubText2 = "count(".concat(projSubText, ") as `").concat(k, "`");
}
else if (k.startsWith('#sum')) {
projSubText2 = "sum(".concat(projSubText, ") as `").concat(k, "`");
}
else {
(0, assert_1.default)(k.startsWith('#avg'));
projSubText2 = "avg(".concat(projSubText, ") as `").concat(k, "`");
}
if (!projText) {
projText = projSubText2;
}
else {
projText += ", ".concat(projSubText2);
}
}
}
var filterText = this.translateFilter(entity, aggregation, aliasDict, {}, currentNumber, extraWhere, option).stmt;
var sorterText = sorter && this.translateSorter(entity, sorter, aliasDict);
return this.populateSelectStmt(projText, fromText, aliasDict, filterText, sorterText, groupByText, indexFrom, count, option, undefined, aggregation);
};
SqlTranslator.prototype.translateCount = function (entity, selection, option) {
var filter = selection.filter, count = selection.count;
var _a = this.analyzeJoin(entity, {
filter: filter,
}), fromText = _a.from, aliasDict = _a.aliasDict, extraWhere = _a.extraWhere, filterRefAlias = _a.filterRefAlias, currentNumber = _a.currentNumber;
var projText = 'count(1) cnt';
var filterText = this.translateFilter(entity, selection, aliasDict, filterRefAlias, currentNumber, extraWhere, option).stmt;
if (count) {
var subQuerySql = this.populateSelectStmt('1', fromText, aliasDict, filterText, undefined, undefined, undefined, undefined, option, Object.assign({}, selection, { indexFrom: 0, count: count }));
return "select count(1) cnt from (".concat(subQuerySql, ") __tmp");
}
return this.populateSelectStmt(projText, fromText, aliasDict, filterText, undefined, undefined, undefined, undefined, option, selection);
};
SqlTranslator.prototype.translateRemove = function (entity, operation, option) {
var filter = operation.filter, sorter = operation.sorter, indexFrom = operation.indexFrom, count = operation.count;
(0, assert_1.default)(!sorter, '当前remove不支持sorter行为');
var _a = this.analyzeJoin(entity, { filter: filter, sorter: sorter }), aliasDict = _a.aliasDict, filterRefAlias = _a.filterRefAlias, extraWhere = _a.extraWhere, fromText = _a.from, currentNumber = _a.currentNumber;
var alias = aliasDict['./'];
var filterText = this.translateFilter(entity, operation, aliasDict, filterRefAlias, currentNumber, extraWhere, { includedDeleted: true }).stmt;
// const sorterText = sorter && sorter.length > 0 ? this.translateSorter(entity, sorter, aliasDict) : undefined;
return this.populateRemoveStmt(alias, fromText, aliasDict, filterText, /* sorterText */ undefined, indexFrom, count, option);
};
SqlTranslator.prototype.translateUpdate = function (entity, operation, option) {
var attributes = this.schema[entity].attributes;
var filter = operation.filter, sorter = operation.sorter, indexFrom = operation.indexFrom, count = operation.count, data = operation.data;
(0, assert_1.default)(!sorter, '当前update不支持sorter行为');
var _a = this.analyzeJoin(entity, { filter: filter, sorter: sorter }), aliasDict = _a.aliasDict, filterRefAlias = _a.filterRefAlias, extraWhere = _a.extraWhere, fromText = _a.from, currentNumber = _a.currentNumber;
var alias = aliasDict['./'];
var updateText = '';
for (var attr in data) {
if (updateText) {
updateText += ',';
}
(0, assert_1.default)(attributes.hasOwnProperty(attr));
var value = this.translateAttrValue(attributes[attr].type, data[attr]);
updateText += "`".concat(alias, "`.`").concat(attr, "` = ").concat(value);
}
var filterText = this.translateFilter(entity, operation, aliasDict, filterRefAlias, currentNumber, extraWhere).stmt;
// const sorterText = sorter && this.translateSorter(entity, sorter, aliasDict);
return this.populateUpdateStmt(updateText, fromText, aliasDict, filterText, /* sorterText */ undefined, indexFrom, count, option);
};
SqlTranslator.prototype.translateDestroyEntity = function (entity, truncate) {
var schema = this.schema;
var _a = schema[entity], _b = _a.storageName, storageName = _b === void 0 ? entity : _b, view = _a.view;
var sql;
if (view) {
sql = "drop view if exists `".concat(storageName, "`");
}
else {
sql = truncate ? "truncate table `".concat(storageName, "`") : "drop table if exists `".concat(storageName, "`");
}
return sql;
};
SqlTranslator.prototype.escapeStringValue = function (value) {
var result = "'".concat(value.replace(/'/g, '\\\''), "'");
return result;
};
return SqlTranslator;
}());
exports.SqlTranslator = SqlTranslator;