修正了expression中的一些BUG

This commit is contained in:
Xu Chang 2023-01-12 20:05:54 +08:00
parent de6e08b7cc
commit eb0f952e2f
6 changed files with 116 additions and 41 deletions

View File

@ -97,7 +97,8 @@ export declare class MySqlTranslator<ED extends EntityDict> extends SqlTranslato
replace?: boolean;
}): string[];
private translateFnName;
protected translateExpression<T extends keyof ED>(alias: string, expression: RefOrExpression<keyof ED[T]["OpSchema"]>, refDict: Record<string, string>): string;
private translateAttrInExpression;
protected translateExpression<T extends keyof ED>(entity: T, alias: string, expression: RefOrExpression<keyof ED[T]["OpSchema"]>, refDict: Record<string, [string, keyof ED]>): string;
protected populateSelectStmt<T extends keyof ED>(projectionText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, groupByText?: string, indexFrom?: number, count?: number, option?: MySqlSelectOption): string;
protected populateUpdateStmt(updateText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, indexFrom?: number, count?: number, option?: MysqlOperateOption): string;
protected populateRemoveStmt(removeText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, indexFrom?: number, count?: number, option?: MysqlOperateOption): string;

View File

@ -357,21 +357,32 @@ var MySqlTranslator = /** @class */ (function (_super) {
MySqlTranslator.prototype.translateFnName = function (fnName, argumentNumber) {
switch (fnName) {
case '$add': {
return '%s + %s';
var result = '%s';
while (--argumentNumber > 0) {
result += ' + %s';
}
return result;
}
case '$subtract': {
(0, assert_1.default)(argumentNumber === 2);
return '%s - %s';
}
case '$multiply': {
return '%s * %s';
var result = '%s';
while (--argumentNumber > 0) {
result += ' * %s';
}
return result;
}
case '$divide': {
(0, assert_1.default)(argumentNumber === 2);
return '%s / %s';
}
case '$abs': {
return 'ABS(%s)';
}
case '$round': {
(0, assert_1.default)(argumentNumber === 2);
return 'ROUND(%s, %s)';
}
case '$ceil': {
@ -381,33 +392,42 @@ var MySqlTranslator = /** @class */ (function (_super) {
return 'FLOOR(%s)';
}
case '$pow': {
(0, assert_1.default)(argumentNumber === 2);
return 'POW(%s, %s)';
}
case '$gt': {
(0, assert_1.default)(argumentNumber === 2);
return '%s > %s';
}
case '$gte': {
(0, assert_1.default)(argumentNumber === 2);
return '%s >= %s';
}
case '$lt': {
(0, assert_1.default)(argumentNumber === 2);
return '%s < %s';
}
case '$lte': {
return '%s <= %s';
}
case '$eq': {
(0, assert_1.default)(argumentNumber === 2);
return '%s = %s';
}
case '$ne': {
(0, assert_1.default)(argumentNumber === 2);
return '%s <> %s';
}
case '$startsWith': {
(0, assert_1.default)(argumentNumber === 2);
return '%s like CONCAT(%s, \'%\')';
}
case '$endsWith': {
(0, assert_1.default)(argumentNumber === 2);
return '%s like CONCAT(\'%\', %s)';
}
case '$includes': {
(0, assert_1.default)(argumentNumber === 2);
return '%s like CONCAT(\'%\', %s, \'%\')';
}
case '$true': {
@ -464,12 +484,15 @@ var MySqlTranslator = /** @class */ (function (_super) {
return 'DAYOFYEAR(%s)';
}
case '$dateDiff': {
(0, assert_1.default)(argumentNumber === 3);
return 'DATEDIFF(%s, %s, %s)';
}
case '$contains': {
(0, assert_1.default)(argumentNumber === 2);
return 'ST_CONTAINS(%s, %s)';
}
case '$distance': {
(0, assert_1.default)(argumentNumber === 2);
return 'ST_DISTANCE(%s, %s)';
}
default: {
@ -477,15 +500,24 @@ var MySqlTranslator = /** @class */ (function (_super) {
}
}
};
MySqlTranslator.prototype.translateExpression = function (alias, expression, refDict) {
MySqlTranslator.prototype.translateAttrInExpression = function (entity, attr, exprText) {
var attributes = this.schema[entity].attributes;
var type = attributes[attr].type;
if (['date', 'time', 'datetime'].includes(type)) {
// 从unix时间戵转成date类型参加expr的运算
return "from_unixtime(".concat(exprText, " / 1000)");
}
return exprText;
};
MySqlTranslator.prototype.translateExpression = function (entity, alias, expression, refDict) {
var _this = this;
var translateConstant = function (constant) {
if (typeof constant === 'string') {
return " ".concat(new Date(constant).valueOf());
}
else if (constant instanceof Date) {
if (constant instanceof Date) {
return " ".concat(constant.valueOf());
}
else if (typeof constant === 'string') {
return " '".concat(constant, "'");
}
else {
(0, assert_1.default)(typeof constant === 'number');
return " ".concat(constant);
@ -496,14 +528,14 @@ var MySqlTranslator = /** @class */ (function (_super) {
var result;
if (k.includes('#attr')) {
var attrText = "`".concat(alias, "`.`").concat((expr)['#attr'], "`");
result = attrText;
result = _this.translateAttrInExpression(entity, (expr)['#attr'], attrText);
}
else if (k.includes('#refId')) {
var refId = (expr)['#refId'];
var refAttr = (expr)['#refAttr'];
(0, assert_1.default)(refDict[refId]);
var attrText = "`".concat(refDict[refId], "`.`").concat(refAttr, "`");
result = attrText;
var attrText = "`".concat(refDict[refId][0], "`.`").concat(refAttr, "`");
result = _this.translateAttrInExpression(entity, (expr)['#attr'], attrText);
}
else {
(0, assert_1.default)(k.length === 1);

View File

@ -18,7 +18,7 @@ export declare abstract class SqlTranslator<ED extends EntityDict> {
protected abstract populateSelectStmt<T extends keyof ED, OP extends SqlSelectOption>(projectionText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, groupByText?: string, indexFrom?: number, count?: number, option?: OP, selection?: ED[T]['Selection'], aggregation?: ED[T]['Aggregation']): string;
protected abstract populateUpdateStmt<OP extends SqlOperateOption>(updateText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, indexFrom?: number, count?: number, option?: OP): string;
protected abstract populateRemoveStmt<OP extends SqlOperateOption>(removeText: string, fromText: string, aliasDict: Record<string, string>, filterText: string, sorterText?: string, indexFrom?: number, count?: number, option?: OP): string;
protected abstract translateExpression<T extends keyof ED>(alias: string, expression: RefOrExpression<keyof ED[T]['OpSchema']>, refDict: Record<string, string>): string;
protected abstract translateExpression<T extends keyof ED>(entity: T, alias: string, expression: RefOrExpression<keyof ED[T]['OpSchema']>, refDict: Record<string, [string, keyof ED]>): string;
private getStorageName;
translateInsert<T extends keyof ED>(entity: T, data: DeduceCreateOperationData<ED[T]['OpSchema']>[]): string;
/**

View File

@ -195,6 +195,8 @@ var SqlTranslator = /** @class */ (function () {
alias: alias,
});
}
else if (['$text'].includes(op)) {
}
else {
var rel = (0, relation_1.judgeRelation)(_this.schema, entityName, op);
if (typeof rel === 'string') {
@ -246,7 +248,7 @@ var SqlTranslator = /** @class */ (function () {
if (node['#id']) {
(0, assert_1.default)(!filterRefAlias[node['#id']]);
(0, lodash_1.assign)(filterRefAlias, (_b = {},
_b[node['#id']] = alias,
_b[node['#id']] = [alias, entityName],
_b));
}
};
@ -368,7 +370,7 @@ var SqlTranslator = /** @class */ (function () {
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,
_b[node['#id']] = [alias, entityName],
_b));
}
};
@ -546,7 +548,7 @@ var SqlTranslator = /** @class */ (function () {
}
else if (attr.toLowerCase().startsWith(types_1.EXPRESSION_PREFIX)) {
// expression
whereText += " (".concat(_this.translateExpression(alias, filter2[attr], filterRefAlias), ")");
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);
@ -606,7 +608,7 @@ var SqlTranslator = /** @class */ (function () {
var attr = Object.keys(sortAttr)[0];
var alias = aliasDict[path];
if (attr.toLocaleLowerCase().startsWith(types_1.EXPRESSION_PREFIX)) {
return _this.translateExpression(alias, sortAttr[attr], {});
return _this.translateExpression(entity2, alias, sortAttr[attr], {});
}
else if (sortAttr[attr] === 1) {
return "`".concat(alias, "`.`").concat(attr, "`");
@ -654,7 +656,7 @@ var SqlTranslator = /** @class */ (function () {
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(alias, projection2[attr], projectionRefAlias);
var exprText = _this.translateExpression(entity2, alias, projection2[attr], projectionRefAlias);
if (disableAs) {
projText += " ".concat(exprText);
}

View File

@ -557,21 +557,32 @@ export class MySqlTranslator<ED extends EntityDict> extends SqlTranslator<ED> {
private translateFnName(fnName: string, argumentNumber: number): string {
switch(fnName) {
case '$add': {
return '%s + %s';
let result = '%s';
while (--argumentNumber > 0) {
result += ' + %s';
}
return result;
}
case '$subtract': {
assert(argumentNumber === 2);
return '%s - %s';
}
case '$multiply': {
return '%s * %s';
let result = '%s';
while (--argumentNumber > 0) {
result += ' * %s';
}
return result;
}
case '$divide': {
assert(argumentNumber === 2);
return '%s / %s';
}
case '$abs': {
return 'ABS(%s)';
}
case '$round': {
assert(argumentNumber === 2);
return 'ROUND(%s, %s)';
}
case '$ceil': {
@ -581,33 +592,42 @@ export class MySqlTranslator<ED extends EntityDict> extends SqlTranslator<ED> {
return 'FLOOR(%s)';
}
case '$pow': {
assert(argumentNumber === 2);
return 'POW(%s, %s)';
}
case '$gt': {
assert(argumentNumber === 2);
return '%s > %s';
}
case '$gte': {
assert(argumentNumber === 2);
return '%s >= %s';
}
case '$lt': {
assert(argumentNumber === 2);
return '%s < %s';
}
case '$lte': {
return '%s <= %s';
}
case '$eq': {
assert(argumentNumber === 2);
return '%s = %s';
}
case '$ne': {
assert(argumentNumber === 2);
return '%s <> %s';
}
case '$startsWith': {
assert(argumentNumber === 2);
return '%s like CONCAT(%s, \'%\')';
}
case '$endsWith': {
assert(argumentNumber === 2);
return '%s like CONCAT(\'%\', %s)';
}
case '$includes': {
assert(argumentNumber === 2);
return '%s like CONCAT(\'%\', %s, \'%\')';
}
case '$true': {
@ -664,12 +684,15 @@ export class MySqlTranslator<ED extends EntityDict> extends SqlTranslator<ED> {
return 'DAYOFYEAR(%s)';
}
case '$dateDiff': {
assert(argumentNumber === 3);
return 'DATEDIFF(%s, %s, %s)';
}
case '$contains': {
assert(argumentNumber === 2);
return 'ST_CONTAINS(%s, %s)';
}
case '$distance': {
assert(argumentNumber === 2);
return 'ST_DISTANCE(%s, %s)';
}
default: {
@ -678,14 +701,24 @@ export class MySqlTranslator<ED extends EntityDict> extends SqlTranslator<ED> {
}
}
protected translateExpression<T extends keyof ED>(alias: string, expression: RefOrExpression<keyof ED[T]["OpSchema"]>, refDict: Record<string, string>): string {
private translateAttrInExpression<T extends keyof ED>(entity: T, attr: string, exprText: string) {
const { attributes } = this.schema[entity];
const { type } = attributes[attr];
if (['date', 'time', 'datetime'].includes(type)) {
// 从unix时间戵转成date类型参加expr的运算
return `from_unixtime(${exprText} / 1000)`;
}
return exprText
}
protected translateExpression<T extends keyof ED>(entity: T, alias: string, expression: RefOrExpression<keyof ED[T]["OpSchema"]>, refDict: Record<string, [string, keyof ED]>): string {
const translateConstant = (constant: number | string | Date): string => {
if (typeof constant === 'string') {
return ` ${new Date(constant).valueOf()}`;
}
else if (constant instanceof Date) {
if (constant instanceof Date) {
return ` ${constant.valueOf()}`;
}
else if (typeof constant === 'string') {
return ` '${constant}'`;
}
else {
assert(typeof constant === 'number');
return ` ${constant}`;
@ -696,15 +729,15 @@ export class MySqlTranslator<ED extends EntityDict> extends SqlTranslator<ED> {
let result: string;
if (k.includes('#attr')) {
const attrText = `\`${alias}\`.\`${(expr)['#attr']}\``;
result = attrText;
result = this.translateAttrInExpression(entity, (expr)['#attr'], attrText);
}
else if (k.includes('#refId')) {
const refId = (expr)['#refId'];
const refAttr = (expr)['#refAttr'];
assert(refDict[refId]);
const attrText = `\`${refDict[refId]}\`.\`${refAttr}\``;
result = attrText;
const attrText = `\`${refDict[refId][0]}\`.\`${refAttr}\``;
result = this.translateAttrInExpression(entity, (expr)['#attr'], attrText);
}
else {
assert (k.length === 1);

View File

@ -160,7 +160,11 @@ export abstract class SqlTranslator<ED extends EntityDict> {
count?: number,
option?: OP): string;
protected abstract translateExpression<T extends keyof ED>(alias: string, expression: RefOrExpression<keyof ED[T]['OpSchema']>, refDict: Record<string, string>): string;
protected abstract translateExpression<T extends keyof ED>(
entity: T,
alias: string,
expression: RefOrExpression<keyof ED[T]['OpSchema']>,
refDict: Record<string, [string, keyof ED]>): string;
private getStorageName<T extends keyof ED>(entity: T) {
const { storageName } = this.schema[entity];
@ -237,16 +241,16 @@ export abstract class SqlTranslator<ED extends EntityDict> {
sorter?: ED[T]['Selection']['sorter'];
}, initialNumber?: number): {
aliasDict: Record<string, string>;
projectionRefAlias: Record<string, string>;
filterRefAlias: Record<string, string>;
projectionRefAlias: Record<string, [string, keyof ED]>;
filterRefAlias: Record<string, [string, keyof ED]>;
from: string;
extraWhere: string;
currentNumber: number;
} {
const { schema } = this;
let number = initialNumber || 1;
const projectionRefAlias: Record<string, string> = {};
const filterRefAlias: Record<string, string> = {};
const projectionRefAlias: Record<string, [string, keyof ED]> = {};
const filterRefAlias: Record<string, [string, keyof ED]> = {};
let extraWhere = '';
const alias = `${entity as string}_${number++}`;
@ -280,6 +284,9 @@ export abstract class SqlTranslator<ED extends EntityDict> {
entityName,
alias,
})
}
else if (['$text'].includes(op)) {
}
else {
const rel = judgeRelation(this.schema, entityName, op);
@ -333,7 +340,7 @@ export abstract class SqlTranslator<ED extends EntityDict> {
if (node!['#id']) {
assert(!filterRefAlias[node!['#id']]);
assign(filterRefAlias, {
[node!['#id']]: alias,
[node!['#id']]: [alias, entityName],
});
}
};
@ -472,7 +479,7 @@ export abstract class SqlTranslator<ED extends EntityDict> {
if (node['#id']) {
assert(!projectionRefAlias[node['#id']], `projection上有重复的#id定义「${node['#id']}`);
assign(projectionRefAlias, {
[node['#id']]: alias,
[node['#id']]: [alias, entityName],
});
}
};
@ -541,7 +548,7 @@ export abstract class SqlTranslator<ED extends EntityDict> {
return ' is null';
}
private translateEvaluation<T extends keyof ED>(attr: string, value: any, entity: T, alias: string, type: DataType | Ref, initialNumber: number, refAlias: Record<string, string>): {
private translateEvaluation<T extends keyof ED>(attr: string, value: any, entity: T, alias: string, type: DataType | Ref, initialNumber: number, refAlias: Record<string, [string, keyof ED]>): {
stmt: string;
currentNumber: number;
} {
@ -624,7 +631,7 @@ export abstract class SqlTranslator<ED extends EntityDict> {
entity: T,
selection: Pick<ED[T]['Selection'], 'filter'>,
aliasDict: Record<string, string>,
filterRefAlias: Record<string, string>,
filterRefAlias: Record<string, [string, keyof ED]>,
initialNumber: number,
extraWhere?: string,
option?: OP): {
@ -682,7 +689,7 @@ export abstract class SqlTranslator<ED extends EntityDict> {
}
else if (attr.toLowerCase().startsWith(EXPRESSION_PREFIX)) {
// expression
whereText += ` (${this.translateExpression(alias, filter2[attr], filterRefAlias)})`;
whereText += ` (${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!);
@ -746,7 +753,7 @@ export abstract class SqlTranslator<ED extends EntityDict> {
const alias = aliasDict[path];
if (attr.toLocaleLowerCase().startsWith(EXPRESSION_PREFIX)) {
return this.translateExpression(alias, sortAttr[attr] as any, {});
return this.translateExpression(entity2, alias, sortAttr[attr] as any, {});
}
else if (sortAttr[attr] === 1) {
return `\`${alias}\`.\`${attr}\``;
@ -785,7 +792,7 @@ export abstract class SqlTranslator<ED extends EntityDict> {
entity: T,
projection: ED[T]['Selection']['data'],
aliasDict: Record<string, string>,
projectionRefAlias: Record<string, string>,
projectionRefAlias: Record<string, [string, keyof ED]>,
commonPrefix?: string,
disableAs?: boolean): {
projText: string,
@ -812,7 +819,7 @@ export abstract class SqlTranslator<ED extends EntityDict> {
(attr, idx) => {
const prefix2 = commonPrefix ? `${commonPrefix}.${prefix}` : prefix;
if (attr.toLowerCase().startsWith(EXPRESSION_PREFIX)) {
const exprText = this.translateExpression(alias, projection2[attr], projectionRefAlias);
const exprText = this.translateExpression(entity2, alias, projection2[attr], projectionRefAlias);
if (disableAs) {
projText += ` ${exprText}`;
}
@ -882,7 +889,7 @@ export abstract class SqlTranslator<ED extends EntityDict> {
};
}
private translateSelectInner<T extends keyof ED, OP extends SqlSelectOption>(entity: T, selection: ED[T]['Selection'], initialNumber: number, refAlias: Record<string, string>, option?: OP): {
private translateSelectInner<T extends keyof ED, OP extends SqlSelectOption>(entity: T, selection: ED[T]['Selection'], initialNumber: number, refAlias: Record<string, [string, keyof ED]>, option?: OP): {
stmt: string;
currentNumber: number;
} {