From 037cd6a41b2521822f11fdc4c29403ee86de3ca7 Mon Sep 17 00:00:00 2001 From: Hieuzest Date: Tue, 9 Apr 2024 20:57:01 +0800 Subject: [PATCH] fix(sql): move typedef utils inside driver class (#79) --- packages/mysql/src/index.ts | 112 +++++++++++++++--------------- packages/postgres/src/index.ts | 122 ++++++++++++++++----------------- 2 files changed, 117 insertions(+), 117 deletions(-) diff --git a/packages/mysql/src/index.ts b/packages/mysql/src/index.ts index 75060dd2..aa372ed7 100644 --- a/packages/mysql/src/index.ts +++ b/packages/mysql/src/index.ts @@ -13,60 +13,6 @@ declare module 'mysql' { const timeRegex = /(\d+):(\d+):(\d+)(\.(\d+))?/ -function getIntegerType(length = 4) { - if (length <= 1) return 'tinyint' - if (length <= 2) return 'smallint' - if (length <= 3) return 'mediumint' - if (length <= 4) return 'int' - return 'bigint' -} - -function getTypeDef({ deftype: type, length, precision, scale }: Field) { - switch (type) { - case 'float': - case 'double': - case 'date': return type - case 'time': return 'time(3)' - case 'timestamp': return 'datetime(3)' - case 'boolean': return 'bit' - case 'integer': - if ((length || 0) > 8) this.logger.warn(`type ${type}(${length}) exceeds the max supported length`) - return getIntegerType(length) - case 'primary': - case 'unsigned': - if ((length || 0) > 8) this.logger.warn(`type ${type}(${length}) exceeds the max supported length`) - return `${getIntegerType(length)} unsigned` - case 'decimal': return `decimal(${precision ?? 10}, ${scale ?? 0}) unsigned` - case 'char': return `char(${length || 255})` - case 'string': return (length || 255) > 65536 ? 'longtext' : `varchar(${length || 255})` - case 'text': return (length || 255) > 65536 ? 'longtext' : `text(${length || 65535})` - case 'binary': return (length || 65537) > 65536 ? 'longblob' : `blob` - case 'list': return `text(${length || 65535})` - case 'json': return `text(${length || 65535})` - default: throw new Error(`unsupported type: ${type}`) - } -} - -function isDefUpdated(field: Field, column: ColumnInfo, def: string) { - const typename = def.split(/[ (]/)[0] - if (typename === 'text') return !column.DATA_TYPE.endsWith('text') - if (typename !== column.DATA_TYPE) return true - switch (field.deftype) { - case 'integer': - case 'unsigned': - case 'char': - case 'string': - return !!field.length && !!column.CHARACTER_MAXIMUM_LENGTH && column.CHARACTER_MAXIMUM_LENGTH !== field.length - case 'decimal': - return column.NUMERIC_PRECISION !== field.precision || column.NUMERIC_SCALE !== field.scale - case 'text': - case 'list': - case 'json': - return false - default: return false - } -} - function createIndex(keys: string | string[]) { return makeArray(keys).map(escapeId).join(', ') } @@ -200,9 +146,9 @@ export class MySQLDriver extends Driver { if (key === primary && autoInc) { def += ' int unsigned not null auto_increment' } else { - const typedef = getTypeDef(fields[key]!) + const typedef = this.getTypeDef(fields[key]!) if (column && !shouldUpdate) { - shouldUpdate = isDefUpdated(fields[key]!, column, typedef) + shouldUpdate = this.isDefUpdated(fields[key]!, column, typedef) } def += ' ' + typedef if (makeArray(primary).includes(key)) { @@ -528,6 +474,60 @@ INSERT INTO mtt VALUES(json_extract(j, concat('$[', i, ']'))); SET i=i+1; END WH }) }) } + + private getTypeDef({ deftype: type, length, precision, scale }: Field) { + const getIntegerType = (length = 4) => { + if (length <= 1) return 'tinyint' + if (length <= 2) return 'smallint' + if (length <= 3) return 'mediumint' + if (length <= 4) return 'int' + return 'bigint' + } + + switch (type) { + case 'float': + case 'double': + case 'date': return type + case 'time': return 'time(3)' + case 'timestamp': return 'datetime(3)' + case 'boolean': return 'bit' + case 'integer': + if ((length || 0) > 8) this.logger.warn(`type ${type}(${length}) exceeds the max supported length`) + return getIntegerType(length) + case 'primary': + case 'unsigned': + if ((length || 0) > 8) this.logger.warn(`type ${type}(${length}) exceeds the max supported length`) + return `${getIntegerType(length)} unsigned` + case 'decimal': return `decimal(${precision ?? 10}, ${scale ?? 0}) unsigned` + case 'char': return `char(${length || 255})` + case 'string': return (length || 255) > 65536 ? 'longtext' : `varchar(${length || 255})` + case 'text': return (length || 255) > 65536 ? 'longtext' : `text(${length || 65535})` + case 'binary': return (length || 65537) > 65536 ? 'longblob' : `blob` + case 'list': return `text(${length || 65535})` + case 'json': return `text(${length || 65535})` + default: throw new Error(`unsupported type: ${type}`) + } + } + + private isDefUpdated(field: Field, column: ColumnInfo, def: string) { + const typename = def.split(/[ (]/)[0] + if (typename === 'text') return !column.DATA_TYPE.endsWith('text') + if (typename !== column.DATA_TYPE) return true + switch (field.deftype) { + case 'integer': + case 'unsigned': + case 'char': + case 'string': + return !!field.length && !!column.CHARACTER_MAXIMUM_LENGTH && column.CHARACTER_MAXIMUM_LENGTH !== field.length + case 'decimal': + return column.NUMERIC_PRECISION !== field.precision || column.NUMERIC_SCALE !== field.scale + case 'text': + case 'list': + case 'json': + return false + default: return false + } + } } export namespace MySQLDriver { diff --git a/packages/postgres/src/index.ts b/packages/postgres/src/index.ts index f189c505..58e365f1 100644 --- a/packages/postgres/src/index.ts +++ b/packages/postgres/src/index.ts @@ -57,65 +57,6 @@ interface QueryTask { const timeRegex = /(\d+):(\d+):(\d+)(\.(\d+))?/ -function getTypeDef(field: Field & { autoInc?: boolean }) { - let { deftype: type, length, precision, scale, autoInc } = field - switch (type) { - case 'primary': - case 'unsigned': - case 'integer': - length ||= 4 - if (precision) return `numeric(${precision}, ${scale ?? 0})` - else if (length <= 2) return autoInc ? 'smallserial' : 'smallint' - else if (length <= 4) return autoInc ? 'serial' : 'integer' - else { - if (length > 8) this.logger.warn(`type ${type}(${length}) exceeds the max supported length`) - return autoInc ? 'bigserial' : 'bigint' - } - case 'decimal': return `numeric(${precision ?? 10}, ${scale ?? 0})` - case 'float': return 'real' - case 'double': return 'double precision' - case 'char': return `varchar(${length || 64}) ` - case 'string': return `varchar(${length || 255})` - case 'text': return `text` - case 'boolean': return 'boolean' - case 'list': return 'text[]' - case 'json': return 'jsonb' - case 'date': return 'timestamp with time zone' - case 'time': return 'time with time zone' - case 'timestamp': return 'timestamp with time zone' - case 'binary': return 'bytea' - default: throw new Error(`unsupported type: ${type}`) - } -} - -function isDefUpdated(field: Field & { autoInc?: boolean }, column: ColumnInfo, def: string) { - const typename = def.split(/[ (]/)[0] - if (field.autoInc) return false - if (['unsigned', 'integer'].includes(field.deftype!)) { - if (column.data_type !== typename) return true - } else if (typename === 'text[]') { - if (column.data_type !== 'ARRAY') return true - } else if (Field.date.includes(field.deftype!)) { - if (column.data_type !== def) return true - } else if (typename === 'varchar') { - if (column.data_type !== 'character varying') return true - } else if (typename !== column.data_type) return true - switch (field.deftype) { - case 'integer': - case 'unsigned': - case 'char': - case 'string': - return !!field.length && !!column.character_maximum_length && column.character_maximum_length !== field.length - case 'decimal': - return column.numeric_precision !== field.precision || column.numeric_scale !== field.scale - case 'text': - case 'list': - case 'json': - return false - default: return false - } -} - function createIndex(keys: string | string[]) { return makeArray(keys).map(escapeId).join(', ') } @@ -235,9 +176,9 @@ export class PostgresDriver extends Driver { const column = columns.find(info => legacy.includes(info.column_name)) let shouldUpdate = column?.column_name !== key const field = Object.assign({ autoInc: primary.includes(key) && table.autoInc }, fields[key]!) - const typedef = getTypeDef(field) + const typedef = this.getTypeDef(field) if (column && !shouldUpdate) { - shouldUpdate = isDefUpdated(field, column, typedef) + shouldUpdate = this.isDefUpdated(field, column, typedef) } if (!column) { @@ -479,6 +420,65 @@ export class PostgresDriver extends Driver { await conn.unsafe(`COMMIT`) }) } + + private getTypeDef(field: Field & { autoInc?: boolean }) { + let { deftype: type, length, precision, scale, autoInc } = field + switch (type) { + case 'primary': + case 'unsigned': + case 'integer': + length ||= 4 + if (precision) return `numeric(${precision}, ${scale ?? 0})` + else if (length <= 2) return autoInc ? 'smallserial' : 'smallint' + else if (length <= 4) return autoInc ? 'serial' : 'integer' + else { + if (length > 8) this.logger.warn(`type ${type}(${length}) exceeds the max supported length`) + return autoInc ? 'bigserial' : 'bigint' + } + case 'decimal': return `numeric(${precision ?? 10}, ${scale ?? 0})` + case 'float': return 'real' + case 'double': return 'double precision' + case 'char': return `varchar(${length || 64}) ` + case 'string': return `varchar(${length || 255})` + case 'text': return `text` + case 'boolean': return 'boolean' + case 'list': return 'text[]' + case 'json': return 'jsonb' + case 'date': return 'timestamp with time zone' + case 'time': return 'time with time zone' + case 'timestamp': return 'timestamp with time zone' + case 'binary': return 'bytea' + default: throw new Error(`unsupported type: ${type}`) + } + } + + private isDefUpdated(field: Field & { autoInc?: boolean }, column: ColumnInfo, def: string) { + const typename = def.split(/[ (]/)[0] + if (field.autoInc) return false + if (['unsigned', 'integer'].includes(field.deftype!)) { + if (column.data_type !== typename) return true + } else if (typename === 'text[]') { + if (column.data_type !== 'ARRAY') return true + } else if (Field.date.includes(field.deftype!)) { + if (column.data_type !== def) return true + } else if (typename === 'varchar') { + if (column.data_type !== 'character varying') return true + } else if (typename !== column.data_type) return true + switch (field.deftype) { + case 'integer': + case 'unsigned': + case 'char': + case 'string': + return !!field.length && !!column.character_maximum_length && column.character_maximum_length !== field.length + case 'decimal': + return column.numeric_precision !== field.precision || column.numeric_scale !== field.scale + case 'text': + case 'list': + case 'json': + return false + default: return false + } + } } export namespace PostgresDriver {