Compare commits
3 Commits
6ec189001f
...
ef44cc4dc4
| Author | SHA1 | Date |
|---|---|---|
|
|
ef44cc4dc4 | |
|
|
846cccb325 | |
|
|
1d464a38a9 |
|
|
@ -523,17 +523,13 @@ class PostgreSQLTranslator extends sqlTranslator_1.SqlTranslator {
|
|||
stmt2 += ' AND ';
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
// 如果是数组,检查是否有任意元素匹配
|
||||
if (p) {
|
||||
const accessor = this.buildJsonAccessor(columnRef, p, false);
|
||||
// 使用 jsonb 数组重叠检查
|
||||
stmt2 += `(${accessor} ?| array[${value.map(v => `'${v}'`).join(', ')}])`;
|
||||
}
|
||||
else {
|
||||
stmt2 += `(${columnRef} ?| array[${value.map((v) => `'${v}'`).join(', ')}])`;
|
||||
}
|
||||
// 如果是数组,检查是否有任意元素匹配
|
||||
const accessor = p ? this.buildJsonAccessor(columnRef, p, false) : columnRef;
|
||||
// 使用 @> 操作符检查数组是否包含任意一个值(支持数字和字符串)
|
||||
const conditions = value.map(v => `${accessor} @> '${JSON.stringify(v)}'::jsonb`);
|
||||
stmt2 += `(${conditions.join(' OR ')})`;
|
||||
}
|
||||
else {
|
||||
else if (typeof value === 'object' && value !== null) {
|
||||
// 对象重叠检查 - 检查是否有共同的键
|
||||
const keys = Object.keys(value);
|
||||
if (p) {
|
||||
|
|
@ -544,6 +540,17 @@ class PostgreSQLTranslator extends sqlTranslator_1.SqlTranslator {
|
|||
stmt2 += `(${columnRef} ?| array[${keys.map(k => `'${k}'`).join(', ')}])`;
|
||||
}
|
||||
}
|
||||
else {
|
||||
(0, assert_1.default)(typeof value === 'string');
|
||||
// 单个键的重叠检查
|
||||
if (p) {
|
||||
const accessor = this.buildJsonAccessor(columnRef, p, false);
|
||||
stmt2 += `(${accessor} ? '${value}')`;
|
||||
}
|
||||
else {
|
||||
stmt2 += `(${columnRef} ? '${value}')`;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (attr2 === '$length') {
|
||||
// PostgreSQL 使用 jsonb_array_length
|
||||
|
|
@ -570,17 +577,40 @@ class PostgreSQLTranslator extends sqlTranslator_1.SqlTranslator {
|
|||
}
|
||||
}
|
||||
else if (attr2 === '$exists') {
|
||||
// 检查键是否存在
|
||||
if (stmt2) {
|
||||
stmt2 += ' AND ';
|
||||
}
|
||||
const keyToCheck = o[attr2];
|
||||
if (p) {
|
||||
const accessor = this.buildJsonAccessor(columnRef, p, false);
|
||||
stmt2 += `(${accessor} ? '${keyToCheck}')`;
|
||||
const existsValue = o[attr2];
|
||||
if (typeof existsValue === 'boolean') {
|
||||
// $exists: true/false - 检查当前路径的值是否存在(不为 null)
|
||||
if (p) {
|
||||
const accessor = this.buildJsonAccessor(columnRef, p, true);
|
||||
if (existsValue) {
|
||||
stmt2 += `(${accessor} IS NOT NULL)`;
|
||||
}
|
||||
else {
|
||||
stmt2 += `(${accessor} IS NULL)`;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (existsValue) {
|
||||
stmt2 += `(${columnRef} IS NOT NULL)`;
|
||||
}
|
||||
else {
|
||||
stmt2 += `(${columnRef} IS NULL)`;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
stmt2 += `(${columnRef} ? '${keyToCheck}')`;
|
||||
// $exists: 'keyName' - 检查 JSON 对象是否包含指定的键
|
||||
const keyToCheck = existsValue;
|
||||
if (p) {
|
||||
const accessor = this.buildJsonAccessor(columnRef, p, false);
|
||||
stmt2 += `(${accessor} ? '${keyToCheck}')`;
|
||||
}
|
||||
else {
|
||||
stmt2 += `(${columnRef} ? '${keyToCheck}')`;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (attr2.startsWith('$')) {
|
||||
|
|
|
|||
|
|
@ -638,7 +638,7 @@ class SqlTranslator {
|
|||
filter: filter2[attr]
|
||||
}, currentNumber, filterRefAlias, option);
|
||||
currentNumber = ct2;
|
||||
whereText += `(${refAlia2}.id ${predicate} (${stmt}))`;
|
||||
whereText += `(${this.quoteIdentifier(alias)}.${this.quoteIdentifier('id')} ${predicate} (${stmt}))`;
|
||||
}
|
||||
else {
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ const GeoTypes = [
|
|||
function transformGeoData(data: Geo): string {
|
||||
if (data instanceof Array) {
|
||||
const element = data[0];
|
||||
|
||||
|
||||
if (element instanceof Array) {
|
||||
// GeometryCollection
|
||||
return `ST_GeomFromText('GEOMETRYCOLLECTION(${data.map(
|
||||
|
|
@ -55,43 +55,43 @@ function transformGeoData(data: Geo): string {
|
|||
} else {
|
||||
// Multi 类型
|
||||
const geoType = GeoTypes.find(ele => ele.type === element.type);
|
||||
|
||||
|
||||
if (!geoType) {
|
||||
throw new Error(`${element.type} is not supported in PostgreSQL`);
|
||||
}
|
||||
|
||||
|
||||
const multiGeoType = GeoTypes.find(
|
||||
ele => ele.element === geoType.type && ele.multiple
|
||||
);
|
||||
|
||||
|
||||
if (!multiGeoType) {
|
||||
throw new Error(`Multi type for ${element.type} not found`);
|
||||
}
|
||||
|
||||
|
||||
const innerWkt = data.map(ele => {
|
||||
const wkt = transformGeoData(ele);
|
||||
// 提取括号内的坐标部分
|
||||
const match = wkt.match(/\(([^)]+)\)/);
|
||||
return match ? match[0] : '';
|
||||
}).join(',');
|
||||
|
||||
|
||||
return `ST_GeomFromText('${multiGeoType.name.toUpperCase()}(${innerWkt})')`;
|
||||
}
|
||||
} else {
|
||||
const { type, coordinate } = data;
|
||||
const geoType = GeoTypes.find(ele => ele.type === type);
|
||||
|
||||
|
||||
if (!geoType) {
|
||||
throw new Error(`${type} is not supported in PostgreSQL`);
|
||||
}
|
||||
|
||||
|
||||
const { element, name } = geoType;
|
||||
|
||||
|
||||
if (!element) {
|
||||
// Point: coordinate 是 [x, y]
|
||||
return `ST_GeomFromText('POINT(${(coordinate as [number, number]).join(' ')})')`;
|
||||
}
|
||||
|
||||
|
||||
if (type === 'path') {
|
||||
// LineString: coordinate 是 [[x1,y1], [x2,y2], ...]
|
||||
const points = (coordinate as [number, number][])
|
||||
|
|
@ -99,7 +99,7 @@ function transformGeoData(data: Geo): string {
|
|||
.join(',');
|
||||
return `ST_GeomFromText('LINESTRING(${points})')`;
|
||||
}
|
||||
|
||||
|
||||
if (type === 'polygon') {
|
||||
// Polygon: coordinate 是 [[[x1,y1], [x2,y2], ...], [...]](外环和内环)
|
||||
const rings = (coordinate as [number, number][][])
|
||||
|
|
@ -107,7 +107,7 @@ function transformGeoData(data: Geo): string {
|
|||
.join(',');
|
||||
return `ST_GeomFromText('POLYGON(${rings})')`;
|
||||
}
|
||||
|
||||
|
||||
throw new Error(`Unsupported geometry type: ${type}`);
|
||||
}
|
||||
}
|
||||
|
|
@ -468,16 +468,16 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
if (value === null || value === undefined) {
|
||||
return 'NULL';
|
||||
}
|
||||
|
||||
|
||||
// PostgreSQL 标准 SQL 转义
|
||||
// 1. 单引号转义为两个单引号
|
||||
// 2. 反斜杠在 standard_conforming_strings=on(默认)时不需要特殊处理
|
||||
const escaped = String(value).replace(/'/g, "''");
|
||||
|
||||
|
||||
return `'${escaped}'`;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* LIKE 模式转义
|
||||
* 转义 LIKE 语句中的特殊字符
|
||||
|
|
@ -488,11 +488,11 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
.replace(/\\/g, '\\\\') // 反斜杠必须先处理
|
||||
.replace(/%/g, '\\%') // 百分号
|
||||
.replace(/_/g, '\\_'); // 下划线
|
||||
|
||||
|
||||
// 再进行字符串值转义
|
||||
return escaped.replace(/'/g, "''");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* PostgreSQL 标识符转义
|
||||
* 用于表名、列名等
|
||||
|
|
@ -596,15 +596,13 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
stmt2 += ' AND ';
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
// 如果是数组,检查是否有任意元素匹配
|
||||
if (p) {
|
||||
const accessor = this.buildJsonAccessor(columnRef, p, false);
|
||||
// 使用 jsonb 数组重叠检查
|
||||
stmt2 += `(${accessor} ?| array[${value.map(v => `'${v}'`).join(', ')}])`;
|
||||
} else {
|
||||
stmt2 += `(${columnRef} ?| array[${value.map((v: any) => `'${v}'`).join(', ')}])`;
|
||||
}
|
||||
} else {
|
||||
// 如果是数组,检查是否有任意元素匹配
|
||||
const accessor = p ? this.buildJsonAccessor(columnRef, p, false) : columnRef;
|
||||
// 使用 @> 操作符检查数组是否包含任意一个值(支持数字和字符串)
|
||||
const conditions = value.map(v => `${accessor} @> '${JSON.stringify(v)}'::jsonb`);
|
||||
stmt2 += `(${conditions.join(' OR ')})`;
|
||||
|
||||
} else if (typeof value === 'object' && value !== null) {
|
||||
// 对象重叠检查 - 检查是否有共同的键
|
||||
const keys = Object.keys(value);
|
||||
if (p) {
|
||||
|
|
@ -613,6 +611,15 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
} else {
|
||||
stmt2 += `(${columnRef} ?| array[${keys.map(k => `'${k}'`).join(', ')}])`;
|
||||
}
|
||||
} else {
|
||||
assert(typeof value === 'string');
|
||||
// 单个键的重叠检查
|
||||
if (p) {
|
||||
const accessor = this.buildJsonAccessor(columnRef, p, false);
|
||||
stmt2 += `(${accessor} ? '${value}')`;
|
||||
} else {
|
||||
stmt2 += `(${columnRef} ? '${value}')`;
|
||||
}
|
||||
}
|
||||
} else if (attr2 === '$length') {
|
||||
// PostgreSQL 使用 jsonb_array_length
|
||||
|
|
@ -638,16 +645,36 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
stmt2 += `(${lengthExpr} ${this.translatePredicate(op, length[op])})`;
|
||||
}
|
||||
} else if (attr2 === '$exists') {
|
||||
// 检查键是否存在
|
||||
if (stmt2) {
|
||||
stmt2 += ' AND ';
|
||||
}
|
||||
const keyToCheck = o[attr2];
|
||||
if (p) {
|
||||
const accessor = this.buildJsonAccessor(columnRef, p, false);
|
||||
stmt2 += `(${accessor} ? '${keyToCheck}')`;
|
||||
const existsValue = o[attr2];
|
||||
|
||||
if (typeof existsValue === 'boolean') {
|
||||
// $exists: true/false - 检查当前路径的值是否存在(不为 null)
|
||||
if (p) {
|
||||
const accessor = this.buildJsonAccessor(columnRef, p, true);
|
||||
if (existsValue) {
|
||||
stmt2 += `(${accessor} IS NOT NULL)`;
|
||||
} else {
|
||||
stmt2 += `(${accessor} IS NULL)`;
|
||||
}
|
||||
} else {
|
||||
if (existsValue) {
|
||||
stmt2 += `(${columnRef} IS NOT NULL)`;
|
||||
} else {
|
||||
stmt2 += `(${columnRef} IS NULL)`;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stmt2 += `(${columnRef} ? '${keyToCheck}')`;
|
||||
// $exists: 'keyName' - 检查 JSON 对象是否包含指定的键
|
||||
const keyToCheck = existsValue;
|
||||
if (p) {
|
||||
const accessor = this.buildJsonAccessor(columnRef, p, false);
|
||||
stmt2 += `(${accessor} ? '${keyToCheck}')`;
|
||||
} else {
|
||||
stmt2 += `(${columnRef} ? '${keyToCheck}')`;
|
||||
}
|
||||
}
|
||||
} else if (attr2.startsWith('$')) {
|
||||
// 其他操作符:$gt, $lt, $eq 等
|
||||
|
|
@ -801,17 +828,17 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
const { config } = ele;
|
||||
return config && config.type === 'fulltext';
|
||||
});
|
||||
|
||||
|
||||
assert(ftIndex, `Entity ${String(entity)} does not have a fulltext index`);
|
||||
|
||||
|
||||
const { attributes } = ftIndex;
|
||||
|
||||
|
||||
// PostgreSQL 全文搜索使用 to_tsvector 和 to_tsquery
|
||||
// 将多个列合并成一个文档
|
||||
const columns = attributes.map(({ name }) =>
|
||||
const columns = attributes.map(({ name }) =>
|
||||
`COALESCE("${alias}"."${name as string}", '')`
|
||||
).join(" || ' ' || ");
|
||||
|
||||
|
||||
// 处理搜索词:将空格分隔的词转换为 & 连接
|
||||
const searchTerms = $search
|
||||
.trim()
|
||||
|
|
@ -826,7 +853,7 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
console.error('Full-text search: no valid search terms after escaping, returning FALSE condition');
|
||||
return 'FALSE';
|
||||
}
|
||||
|
||||
|
||||
// 在 translateFullTextSearch 中使用
|
||||
const pgLanguage = $language ? this.languageConfigMap[$language] : undefined;
|
||||
|
||||
|
|
@ -1073,7 +1100,7 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
// PostgreSQL 使用 POWER
|
||||
return 'POWER(%s, %s)';
|
||||
}
|
||||
|
||||
|
||||
// ========== 比较运算 ==========
|
||||
case '$gt': {
|
||||
assert(argumentNumber === 2);
|
||||
|
|
@ -1099,7 +1126,7 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
assert(argumentNumber === 2);
|
||||
return '%s <> %s';
|
||||
}
|
||||
|
||||
|
||||
// ========== 字符串操作 ==========
|
||||
case '$startsWith': {
|
||||
assert(argumentNumber === 2);
|
||||
|
|
@ -1123,7 +1150,7 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
result += ')';
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// ========== 布尔运算 ==========
|
||||
case '$true': {
|
||||
return '%s = TRUE';
|
||||
|
|
@ -1154,7 +1181,7 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
case '$not': {
|
||||
return 'NOT %s';
|
||||
}
|
||||
|
||||
|
||||
// ========== 日期时间函数 ==========
|
||||
case '$year': {
|
||||
return 'EXTRACT(YEAR FROM %s)::integer';
|
||||
|
|
@ -1209,7 +1236,7 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
// 参数: date, amount, unit
|
||||
return '(%s + INTERVAL \'1 %s\' * %s)';
|
||||
}
|
||||
|
||||
|
||||
// ========== 地理空间函数 (PostGIS) ==========
|
||||
case '$contains': {
|
||||
assert(argumentNumber === 2);
|
||||
|
|
@ -1227,7 +1254,7 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
assert(argumentNumber === 2);
|
||||
return 'ST_Intersects(%s, %s)';
|
||||
}
|
||||
|
||||
|
||||
default: {
|
||||
throw new Error(`unrecognized function ${fnName}`);
|
||||
}
|
||||
|
|
@ -1237,26 +1264,26 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
private translateAttrInExpression<T extends keyof ED>(entity: T, attr: string, exprText: string): string {
|
||||
const { attributes } = this.schema[entity];
|
||||
const attrDef = attributes[attr];
|
||||
|
||||
|
||||
if (!attrDef) {
|
||||
return exprText;
|
||||
}
|
||||
|
||||
|
||||
const { type } = attrDef;
|
||||
|
||||
|
||||
if (['date', 'time', 'datetime'].includes(type)) {
|
||||
// 从 Unix 时间戳(毫秒)转成 timestamp 类型参加 expr 的运算
|
||||
// PostgreSQL 使用 TO_TIMESTAMP,参数为秒
|
||||
return `TO_TIMESTAMP(${exprText}::double precision / 1000)`;
|
||||
}
|
||||
|
||||
|
||||
return exprText;
|
||||
}
|
||||
|
||||
protected translateExpression<T extends keyof ED>(
|
||||
entity: T,
|
||||
alias: string,
|
||||
expression: RefOrExpression<keyof ED[T]["OpSchema"]>,
|
||||
entity: T,
|
||||
alias: string,
|
||||
expression: RefOrExpression<keyof ED[T]["OpSchema"]>,
|
||||
refDict: Record<string, [string, keyof ED]>
|
||||
): string {
|
||||
const translateConstant = (constant: number | string | Date): string => {
|
||||
|
|
@ -1271,11 +1298,11 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
return `${constant}`;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const translateInner = (expr: any): string => {
|
||||
const k = Object.keys(expr);
|
||||
let result: string;
|
||||
|
||||
|
||||
if (k.includes('#attr')) {
|
||||
const attrName = (expr)['#attr'];
|
||||
const attrText = `"${alias}"."${attrName}"`;
|
||||
|
|
@ -1292,11 +1319,11 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
assert(k.length === 1);
|
||||
const fnKey = k[0];
|
||||
const fnArgs = (expr)[fnKey];
|
||||
|
||||
|
||||
if (fnArgs instanceof Array) {
|
||||
const fnName = this.translateFnName(fnKey, fnArgs.length);
|
||||
const args: string[] = [fnName];
|
||||
|
||||
|
||||
args.push(...fnArgs.map((ele: any) => {
|
||||
if (['string', 'number'].includes(typeof ele) || ele instanceof Date) {
|
||||
return translateConstant(ele);
|
||||
|
|
@ -1309,7 +1336,7 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
} else {
|
||||
const fnName = this.translateFnName(fnKey, 1);
|
||||
const args: string[] = [fnName];
|
||||
|
||||
|
||||
if (['string', 'number'].includes(typeof fnArgs) || fnArgs instanceof Date) {
|
||||
args.push(translateConstant(fnArgs));
|
||||
} else {
|
||||
|
|
@ -1319,7 +1346,7 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
result = format.apply(null, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
|
@ -1338,19 +1365,19 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
option?: PostgreSQLSelectOption
|
||||
): string {
|
||||
let sql = `SELECT ${projectionText} FROM ${fromText}`;
|
||||
|
||||
|
||||
if (filterText) {
|
||||
sql += ` WHERE ${filterText}`;
|
||||
}
|
||||
|
||||
|
||||
if (groupByText) {
|
||||
sql += ` GROUP BY ${groupByText}`;
|
||||
}
|
||||
|
||||
|
||||
if (sorterText) {
|
||||
sql += ` ORDER BY ${sorterText}`;
|
||||
}
|
||||
|
||||
|
||||
// PostgreSQL 语法: LIMIT count OFFSET offset
|
||||
if (typeof count === 'number') {
|
||||
sql += ` LIMIT ${count}`;
|
||||
|
|
@ -1358,7 +1385,7 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
if (typeof indexFrom === 'number' && indexFrom > 0) {
|
||||
sql += ` OFFSET ${indexFrom}`;
|
||||
}
|
||||
|
||||
|
||||
// FOR UPDATE 锁定
|
||||
if (option?.forUpdate) {
|
||||
sql += ' FOR UPDATE';
|
||||
|
|
@ -1444,11 +1471,11 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
|
||||
// 构建过滤条件
|
||||
const { stmt: filterText } = this.translateFilter(
|
||||
entity,
|
||||
filter,
|
||||
aliasDict,
|
||||
filterRefAlias,
|
||||
currentNumber,
|
||||
entity,
|
||||
filter,
|
||||
aliasDict,
|
||||
filterRefAlias,
|
||||
currentNumber,
|
||||
{ includedDeleted: option?.includedDeleted } as OP
|
||||
);
|
||||
|
||||
|
|
@ -1693,7 +1720,7 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
extraCondition?: string;
|
||||
}>): string {
|
||||
const conditions: string[] = [];
|
||||
|
||||
|
||||
for (const join of joinInfos) {
|
||||
let condition = `"${join.leftAlias}"."${join.leftKey}" = "${join.alias}"."${join.rightKey}"`;
|
||||
if (join.extraCondition) {
|
||||
|
|
@ -1701,7 +1728,7 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
}
|
||||
conditions.push(condition);
|
||||
}
|
||||
|
||||
|
||||
return conditions.join(' AND ');
|
||||
}
|
||||
|
||||
|
|
@ -1717,29 +1744,29 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
): string {
|
||||
const { schema } = this;
|
||||
const { attributes, storageName = entity } = schema[entity];
|
||||
|
||||
|
||||
// 基础 INSERT 语句
|
||||
let sql = this.translateInsert(entity, data);
|
||||
|
||||
|
||||
// ON CONFLICT 子句
|
||||
const conflictColumns = conflictKeys.map(k => this.quoteIdentifier(k)).join(', ');
|
||||
sql += ` ON CONFLICT (${conflictColumns})`;
|
||||
|
||||
|
||||
// DO UPDATE SET 子句
|
||||
const dataFull = data.reduce((prev, cur) => Object.assign({}, cur, prev), {});
|
||||
const attrsToUpdate = updateAttrs || Object.keys(dataFull).filter(
|
||||
attr => attributes.hasOwnProperty(attr) && !conflictKeys.includes(attr) && attr !== 'id'
|
||||
);
|
||||
|
||||
|
||||
if (attrsToUpdate.length > 0) {
|
||||
const updateParts = attrsToUpdate.map(attr =>
|
||||
const updateParts = attrsToUpdate.map(attr =>
|
||||
`${this.quoteIdentifier(attr)} = EXCLUDED.${this.quoteIdentifier(attr)}`
|
||||
);
|
||||
sql += ` DO UPDATE SET ${updateParts.join(', ')}`;
|
||||
} else {
|
||||
sql += ' DO NOTHING';
|
||||
}
|
||||
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -812,7 +812,7 @@ export abstract class SqlTranslator<ED extends EntityDict & BaseEntityDict> {
|
|||
}, currentNumber, filterRefAlias, option);
|
||||
|
||||
currentNumber = ct2;
|
||||
whereText += `(${refAlia2}.id ${predicate} (${stmt}))`;
|
||||
whereText += `(${this.quoteIdentifier(alias)}.${this.quoteIdentifier('id')} ${predicate} (${stmt}))`;
|
||||
}
|
||||
else {
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -880,9 +880,6 @@ describe('test mysqlstore', function () {
|
|||
port: '',
|
||||
},
|
||||
},
|
||||
dangerousVersions: [],
|
||||
warningVersions: [],
|
||||
soaVersion: '',
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -1233,9 +1230,6 @@ describe('test mysqlstore', function () {
|
|||
port: '',
|
||||
},
|
||||
},
|
||||
dangerousVersions: [],
|
||||
warningVersions: [],
|
||||
soaVersion: '',
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -1284,9 +1278,6 @@ describe('test mysqlstore', function () {
|
|||
port: '',
|
||||
},
|
||||
},
|
||||
dangerousVersions: [],
|
||||
warningVersions: [],
|
||||
soaVersion: '',
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -1306,9 +1297,6 @@ describe('test mysqlstore', function () {
|
|||
port: '',
|
||||
},
|
||||
},
|
||||
dangerousVersions: [],
|
||||
warningVersions: [],
|
||||
soaVersion: '',
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue