import { asRenameKey, getColumnType, isDefaultEqual } from 'src/sql-tools/helpers'; import { Comparer, DatabaseColumn, Reason, SchemaDiff } from 'src/sql-tools/types'; export const compareColumns = { getRenameKey: (column) => { return asRenameKey([ column.tableName, column.type, column.nullable, column.default, column.storage, column.primary, column.isArray, column.length, column.identity, column.enumName, column.numericPrecision, column.numericScale, ]); }, onRename: (source, target) => [ { type: 'ColumnRename', tableName: source.tableName, oldName: target.name, newName: source.name, reason: Reason.Rename, }, ], onMissing: (source) => [ { type: 'ColumnAdd', column: source, reason: Reason.MissingInTarget, }, ], onExtra: (target) => [ { type: 'ColumnDrop', tableName: target.tableName, columnName: target.name, reason: Reason.MissingInSource, }, ], onCompare: (source, target) => { const sourceType = getColumnType(source); const targetType = getColumnType(target); const isTypeChanged = sourceType !== targetType; if (isTypeChanged) { // TODO: convert between types via UPDATE when possible return dropAndRecreateColumn(source, target, `column type is different (${sourceType} vs ${targetType})`); } const items: SchemaDiff[] = []; if (source.nullable !== target.nullable) { items.push({ type: 'ColumnAlter', tableName: source.tableName, columnName: source.name, changes: { nullable: source.nullable, }, reason: `nullable is different (${source.nullable} vs ${target.nullable})`, }); } if (!isDefaultEqual(source, target)) { items.push({ type: 'ColumnAlter', tableName: source.tableName, columnName: source.name, changes: { default: String(source.default ?? 'NULL'), }, reason: `default is different (${source.default ?? 'null'} vs ${target.default})`, }); } if (source.comment !== target.comment) { items.push({ type: 'ColumnAlter', tableName: source.tableName, columnName: source.name, changes: { comment: String(source.comment), }, reason: `comment is different (${source.comment} vs ${target.comment})`, }); } return items; }, } satisfies Comparer; const dropAndRecreateColumn = (source: DatabaseColumn, target: DatabaseColumn, reason: string): SchemaDiff[] => { return [ { type: 'ColumnDrop', tableName: target.tableName, columnName: target.name, reason, }, { type: 'ColumnAdd', column: source, reason }, ]; };