Compare commits

...

2 Commits

4 changed files with 112 additions and 88 deletions

View File

@ -81,16 +81,6 @@ class MySqlTranslator extends sqlTranslator_1.SqlTranslator {
makeUpSchema() {
for (const entity in this.schema) {
const { attributes, indexes } = this.schema[entity];
// 非特殊索引自动添加 $$deleteAt$$ (by qcqcqc)
for (const index of indexes || []) {
if (index.config?.type) {
continue;
}
const indexAttrNames = index.attributes.map(attr => attr.name);
if (!indexAttrNames.includes('$$deleteAt$$')) {
index.attributes.push({ name: '$$deleteAt$$' });
}
}
const geoIndexes = [];
for (const attr in attributes) {
if (attributes[attr].type === 'geometry') {

View File

@ -171,16 +171,6 @@ class PostgreSQLTranslator extends sqlTranslator_1.SqlTranslator {
makeUpSchema() {
for (const entity in this.schema) {
const { attributes, indexes } = this.schema[entity];
// 非特殊索引自动添加 $$deleteAt$$
for (const index of indexes || []) {
if (index.config?.type) {
continue;
}
const indexAttrNames = index.attributes.map(attr => attr.name);
if (!indexAttrNames.includes('$$deleteAt$$')) {
index.attributes.push({ name: '$$deleteAt$$' });
}
}
const geoIndexes = [];
for (const attr in attributes) {
if (attributes[attr].type === 'geometry') {
@ -1842,7 +1832,7 @@ class PostgreSQLTranslator extends sqlTranslator_1.SqlTranslator {
'double precision': 'double precision',
'boolean': 'boolean',
'text': 'text',
'jsonb': 'object', // 框架使用 jsonb 存储 object/array
'jsonb': 'object',
'json': 'object',
'bytea': 'bytea',
'character varying': 'varchar',
@ -1852,6 +1842,7 @@ class PostgreSQLTranslator extends sqlTranslator_1.SqlTranslator {
'date': 'date',
'uuid': 'uuid',
'geometry': 'geometry',
'numeric': 'decimal',
};
const mappedType = typeMap[type];
if (mappedType) {
@ -1899,7 +1890,6 @@ class PostgreSQLTranslator extends sqlTranslator_1.SqlTranslator {
let attr;
// 处理用户定义类型(枚举)
if (dataType === 'USER-DEFINED') {
// 查询枚举值
const enumSql = `
SELECT e.enumlabel
FROM pg_type t
@ -1917,23 +1907,42 @@ class PostgreSQLTranslator extends sqlTranslator_1.SqlTranslator {
else {
// 构建完整的类型字符串
let fullType = dataType;
if (maxLength) {
const integerTypes = ['bigint', 'integer', 'smallint', 'serial', 'bigserial', 'smallserial'];
if (maxLength && !integerTypes.includes(dataType)) {
fullType = `${dataType}(${maxLength})`;
}
else if (precision !== null && scale !== null) {
else if (precision !== null && scale !== null && !integerTypes.includes(dataType)) {
fullType = `${dataType}(${precision},${scale})`;
}
else if (precision !== null) {
else if (precision !== null && !integerTypes.includes(dataType)) {
fullType = `${dataType}(${precision})`;
}
attr = this.reTranslateToAttribute(fullType);
}
// 处理约束
attr.notNull = isNullable === 'NO';
// 处理默认值(简化处理,复杂的默认值可能需要更精细的解析)
// ========== 类型还原逻辑 ==========
// 框架将某些语义类型存储为 bigint需要根据列名还原
if (attr.type === 'bigint') {
// 1. 检查是否是序列列
if (colName === '$$seq$$' || (defaultValue && defaultValue.includes('nextval'))) {
attr.type = 'sequence';
attr.sequenceStart = 10000; // 默认起始值
}
// 2. 检查是否是时间戳列
else if (['$$createAt$$', '$$updateAt$$', '$$deleteAt$$'].includes(colName)) {
attr.type = 'datetime';
}
// 3. 检查其他可能的时间类型列(根据命名约定)
else if (colName.endsWith('At') || colName.endsWith('Time')) {
// 可选:根据业务约定判断是否应该是 datetime
// 这里保守处理,只转换框架标准字段
}
}
// 处理约束 - 只在为 true 时添加
if (isNullable === 'NO') {
attr.notNull = true;
}
// 处理默认值
if (defaultValue && !defaultValue.includes('nextval')) {
// 跳过序列默认值
// 简单处理:移除类型转换
let cleanDefault = defaultValue.replace(/::[a-z]+/gi, '').replace(/'/g, '');
if (cleanDefault === 'true') {
attr.default = true;
@ -1944,13 +1953,26 @@ class PostgreSQLTranslator extends sqlTranslator_1.SqlTranslator {
else if (!isNaN(Number(cleanDefault))) {
attr.default = Number(cleanDefault);
}
else {
else if (cleanDefault !== '') {
attr.default = cleanDefault;
}
}
// 检查是否是序列列IDENTITY
if (colName === '$$seq$$' || (defaultValue && defaultValue.includes('nextval'))) {
attr.sequenceStart = 10000; // 默认起始值
// 检查唯一约束
const uniqueSql = `
SELECT COUNT(*) as cnt
FROM pg_index ix
JOIN pg_class t ON t.oid = ix.indrelid
JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(ix.indkey)
WHERE t.relname = '${tableName}'
AND a.attname = '${colName}'
AND ix.indisunique = true
AND NOT ix.indisprimary
AND array_length(ix.indkey, 1) = 1;
`;
const [uniqueResult] = await execFn(uniqueSql);
const uniqueCount = parseInt(uniqueResult[0]?.cnt || '0', 10);
if (uniqueCount > 0) {
attr.unique = true;
}
attributes[colName] = attr;
}
@ -2085,15 +2107,13 @@ class PostgreSQLTranslator extends sqlTranslator_1.SqlTranslator {
let sql = `"${attr}" `;
const { type, params, default: defaultValue, unique, notNull, sequenceStart, enumeration, } = attrDef;
// 处理序列类型IDENTITY
if (typeof sequenceStart === 'number') {
sql += `bigint GENERATED BY DEFAULT AS IDENTITY (START WITH ${sequenceStart}) UNIQUE`;
if (type === 'sequence' || (typeof sequenceStart === 'number')) {
sql += `bigint GENERATED BY DEFAULT AS IDENTITY (START WITH ${sequenceStart || 10000}) UNIQUE`;
return sql;
}
// 处理枚举类型
if (type === 'enum') {
(0, assert_1.default)(enumeration, 'Enum type requires enumeration values');
// 注意:这里返回的是占位符,实际的枚举类型名在 translateCreateEntity 中确定
// 为了比较一致性,我们使用枚举值的字符串表示
sql += `enum(${enumeration.map(v => `'${v}'`).join(',')})`;
}
else {

View File

@ -109,16 +109,6 @@ export class MySqlTranslator<ED extends EntityDict & BaseEntityDict> extends Sql
private makeUpSchema() {
for (const entity in this.schema) {
const { attributes, indexes } = this.schema[entity];
// 非特殊索引自动添加 $$deleteAt$$ (by qcqcqc)
for (const index of indexes || []) {
if (index.config?.type) {
continue;
}
const indexAttrNames = index.attributes.map(attr => attr.name);
if (!indexAttrNames.includes('$$deleteAt$$')) {
index.attributes.push({ name: '$$deleteAt$$' });
}
}
const geoIndexes: Index<ED[keyof ED]['OpSchema']>[] = [];
for (const attr in attributes) {
if (attributes[attr].type === 'geometry') {

View File

@ -210,16 +210,6 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
private makeUpSchema() {
for (const entity in this.schema) {
const { attributes, indexes } = this.schema[entity];
// 非特殊索引自动添加 $$deleteAt$$
for (const index of indexes || []) {
if (index.config?.type) {
continue;
}
const indexAttrNames = index.attributes.map(attr => attr.name);
if (!indexAttrNames.includes('$$deleteAt$$')) {
index.attributes.push({ name: '$$deleteAt$$' });
}
}
const geoIndexes: Index<ED[keyof ED]['OpSchema']>[] = [];
for (const attr in attributes) {
if (attributes[attr].type === 'geometry') {
@ -2119,7 +2109,7 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
'double precision': 'double precision',
'boolean': 'boolean',
'text': 'text',
'jsonb': 'object', // 框架使用 jsonb 存储 object/array
'jsonb': 'object',
'json': 'object',
'bytea': 'bytea',
'character varying': 'varchar',
@ -2129,6 +2119,7 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
'date': 'date',
'uuid': 'uuid',
'geometry': 'geometry',
'numeric': 'decimal',
};
const mappedType = typeMap[type];
@ -2179,6 +2170,7 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
const attributes: Attributes<any> = {};
for (const col of columnsResult) {
const {
column_name: colName,
@ -2195,7 +2187,6 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
// 处理用户定义类型(枚举)
if (dataType === 'USER-DEFINED') {
// 查询枚举值
const enumSql = `
SELECT e.enumlabel
FROM pg_type t
@ -2213,24 +2204,46 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
} else {
// 构建完整的类型字符串
let fullType = dataType;
if (maxLength) {
const integerTypes = ['bigint', 'integer', 'smallint', 'serial', 'bigserial', 'smallserial'];
if (maxLength && !integerTypes.includes(dataType)) {
fullType = `${dataType}(${maxLength})`;
} else if (precision !== null && scale !== null) {
} else if (precision !== null && scale !== null && !integerTypes.includes(dataType)) {
fullType = `${dataType}(${precision},${scale})`;
} else if (precision !== null) {
} else if (precision !== null && !integerTypes.includes(dataType)) {
fullType = `${dataType}(${precision})`;
}
attr = this.reTranslateToAttribute(fullType);
}
// 处理约束
attr.notNull = isNullable === 'NO';
// ========== 类型还原逻辑 ==========
// 框架将某些语义类型存储为 bigint需要根据列名还原
if (attr.type === 'bigint') {
// 1. 检查是否是序列列
if (colName === '$$seq$$' || (defaultValue && defaultValue.includes('nextval'))) {
attr.type = 'sequence';
attr.sequenceStart = 10000; // 默认起始值
}
// 2. 检查是否是时间戳列
else if (['$$createAt$$', '$$updateAt$$', '$$deleteAt$$'].includes(colName)) {
attr.type = 'datetime';
}
// 3. 检查其他可能的时间类型列(根据命名约定)
else if (colName.endsWith('At') || colName.endsWith('Time')) {
// 可选:根据业务约定判断是否应该是 datetime
// 这里保守处理,只转换框架标准字段
}
}
// 处理默认值(简化处理,复杂的默认值可能需要更精细的解析)
// 处理约束 - 只在为 true 时添加
if (isNullable === 'NO') {
attr.notNull = true;
}
// 处理默认值
if (defaultValue && !defaultValue.includes('nextval')) {
// 跳过序列默认值
// 简单处理:移除类型转换
let cleanDefault = defaultValue.replace(/::[a-z]+/gi, '').replace(/'/g, '');
if (cleanDefault === 'true') {
attr.default = true;
@ -2238,14 +2251,27 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
attr.default = false;
} else if (!isNaN(Number(cleanDefault))) {
attr.default = Number(cleanDefault);
} else {
} else if (cleanDefault !== '') {
attr.default = cleanDefault;
}
}
// 检查是否是序列列IDENTITY
if (colName === '$$seq$$' || (defaultValue && defaultValue.includes('nextval'))) {
attr.sequenceStart = 10000; // 默认起始值
// 检查唯一约束
const uniqueSql = `
SELECT COUNT(*) as cnt
FROM pg_index ix
JOIN pg_class t ON t.oid = ix.indrelid
JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = ANY(ix.indkey)
WHERE t.relname = '${tableName}'
AND a.attname = '${colName}'
AND ix.indisunique = true
AND NOT ix.indisprimary
AND array_length(ix.indkey, 1) = 1;
`;
const [uniqueResult] = await execFn(uniqueSql);
const uniqueCount = parseInt(uniqueResult[0]?.cnt || '0', 10);
if (uniqueCount > 0) {
attr.unique = true;
}
attributes[colName] = attr;
@ -2409,16 +2435,14 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
} = attrDef;
// 处理序列类型IDENTITY
if (typeof sequenceStart === 'number') {
sql += `bigint GENERATED BY DEFAULT AS IDENTITY (START WITH ${sequenceStart}) UNIQUE`;
if (type === 'sequence' || (typeof sequenceStart === 'number')) {
sql += `bigint GENERATED BY DEFAULT AS IDENTITY (START WITH ${sequenceStart || 10000}) UNIQUE`;
return sql;
}
// 处理枚举类型
if (type === 'enum') {
assert(enumeration, 'Enum type requires enumeration values');
// 注意:这里返回的是占位符,实际的枚举类型名在 translateCreateEntity 中确定
// 为了比较一致性,我们使用枚举值的字符串表示
sql += `enum(${enumeration.map(v => `'${v}'`).join(',')})`;
} else {
sql += this.populateDataTypeDef(type, params, enumeration);