Compare commits
2 Commits
cb8b0428b4
...
62bc866606
| Author | SHA1 | Date |
|---|---|---|
|
|
62bc866606 | |
|
|
eee2f7c874 |
|
|
@ -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') {
|
||||
|
|
|
|||
|
|
@ -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,14 +1890,13 @@ class PostgreSQLTranslator extends sqlTranslator_1.SqlTranslator {
|
|||
let attr;
|
||||
// 处理用户定义类型(枚举)
|
||||
if (dataType === 'USER-DEFINED') {
|
||||
// 查询枚举值
|
||||
const enumSql = `
|
||||
SELECT e.enumlabel
|
||||
FROM pg_type t
|
||||
JOIN pg_enum e ON t.oid = e.enumtypid
|
||||
WHERE t.typname = '${udtName}'
|
||||
ORDER BY e.enumsortorder;
|
||||
`;
|
||||
SELECT e.enumlabel
|
||||
FROM pg_type t
|
||||
JOIN pg_enum e ON t.oid = e.enumtypid
|
||||
WHERE t.typname = '${udtName}'
|
||||
ORDER BY e.enumsortorder;
|
||||
`;
|
||||
const [enumResult] = await execFn(enumSql);
|
||||
const enumeration = enumResult.map((r) => r.enumlabel);
|
||||
attr = {
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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') {
|
||||
|
|
|
|||
|
|
@ -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,14 +2187,13 @@ export class PostgreSQLTranslator<ED extends EntityDict & BaseEntityDict> extend
|
|||
|
||||
// 处理用户定义类型(枚举)
|
||||
if (dataType === 'USER-DEFINED') {
|
||||
// 查询枚举值
|
||||
const enumSql = `
|
||||
SELECT e.enumlabel
|
||||
FROM pg_type t
|
||||
JOIN pg_enum e ON t.oid = e.enumtypid
|
||||
WHERE t.typname = '${udtName}'
|
||||
ORDER BY e.enumsortorder;
|
||||
`;
|
||||
SELECT e.enumlabel
|
||||
FROM pg_type t
|
||||
JOIN pg_enum e ON t.oid = e.enumtypid
|
||||
WHERE t.typname = '${udtName}'
|
||||
ORDER BY e.enumsortorder;
|
||||
`;
|
||||
const [enumResult] = await execFn(enumSql);
|
||||
const enumeration = enumResult.map((r: any) => r.enumlabel);
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue