diff --git a/packages/tools/src/diffTools.ts b/packages/tools/src/diffTools.ts index 1f50f0a5..924e2833 100644 --- a/packages/tools/src/diffTools.ts +++ b/packages/tools/src/diffTools.ts @@ -25,6 +25,7 @@ import _isEqual from 'lodash/isEqual'; import _pick from 'lodash/pick'; import _compact from 'lodash/compact'; import _isString from 'lodash/isString'; +import { detectChangesInPreloadedRows } from './structureTools'; type DbDiffSchemaMode = 'strict' | 'ignore' | 'ignoreImplicit'; @@ -507,7 +508,7 @@ function createPairs(oldList, newList, additionalCondition = null) { function planTablePreload(plan: AlterPlan, oldTable: TableInfo, newTable: TableInfo) { const key = newTable.preloadedRowsKey || newTable.primaryKey?.columns?.map(x => x.columnName); - if (newTable.preloadedRows?.length > 0 && key?.length > 0) { + if (newTable.preloadedRows?.length > 0 && key?.length > 0 && detectChangesInPreloadedRows(oldTable, newTable)) { plan.fillPreloadedRows( newTable, oldTable?.preloadedRows, @@ -597,8 +598,6 @@ function planAlterTable(plan: AlterPlan, oldTable: TableInfo, newTable: TableInf constraintPairs.filter(x => x[0] == null).forEach(x => plan.createConstraint(x[1])); - planTablePreload(plan, oldTable, newTable); - planChangeTableOptions(plan, oldTable, newTable, opts); // console.log('oldTable', oldTable); @@ -635,7 +634,15 @@ export function testEqualTables( // if (plan.operations.length > 0) { // console.log('************** plan.operations', a, b, plan.operations); // } - return plan.operations.length == 0; + if (plan.operations.length > 0) { + return false; + } + + if (detectChangesInPreloadedRows(a, b)) { + return false; + } + + return true; } export function testEqualSqlObjects(a: SqlObjectInfo, b: SqlObjectInfo, opts: DbDiffOptions) { @@ -658,6 +665,7 @@ export function createAlterTablePlan( plan.dropTable(oldTable); } else { planAlterTable(plan, oldTable, newTable, opts); + planTablePreload(plan, oldTable, newTable); } plan.transformPlan(); return plan; @@ -719,6 +727,7 @@ export function createAlterDatabasePlan( } } else { planAlterTable(plan, oldobj, newobj, opts); + planTablePreload(plan, oldobj, newobj); } } else { if (newobj == null) { diff --git a/packages/tools/src/structureTools.ts b/packages/tools/src/structureTools.ts index 15ff4251..1f5099c9 100644 --- a/packages/tools/src/structureTools.ts +++ b/packages/tools/src/structureTools.ts @@ -1,6 +1,14 @@ -import type { DatabaseInfo, TableInfo, ApplicationDefinition, ViewInfo, CollectionInfo } from 'dbgate-types'; +import type { + DatabaseInfo, + TableInfo, + ApplicationDefinition, + ViewInfo, + CollectionInfo, + NamedObjectInfo, +} from 'dbgate-types'; import _flatten from 'lodash/flatten'; import _uniq from 'lodash/uniq'; +import _keys from 'lodash/keys'; export function addTableDependencies(db: DatabaseInfo): DatabaseInfo { if (!db.tables) { @@ -220,3 +228,61 @@ export function skipNamesInStructureByRegex(db: DatabaseInfo, regex: RegExp) { triggers: (db.triggers || []).filter(tbl => !regex.test(tbl.pureName)), }; } + +export function detectChangesInPreloadedRows(oldTable: TableInfo, newTable: TableInfo): boolean { + const key = + newTable.preloadedRowsKey || + oldTable.preloadedRowsKey || + newTable.primaryKey?.columns?.map(x => x.columnName) || + oldTable.primaryKey?.columns?.map(x => x.columnName); + const oldRows = oldTable?.preloadedRows || []; + const newRows = newTable?.preloadedRows || []; + const insertOnly = newTable.preloadedRowsInsertOnly || oldTable.preloadedRowsInsertOnly; + + if (newRows.length != oldRows.length) { + return true; + } + + for (const row of newRows) { + const old = oldRows?.find(r => key.every(col => r[col] == row[col])); + const rowKeys = _keys(row); + if (old) { + const updated = []; + for (const col of rowKeys) { + if (row[col] != old[col] && !insertOnly?.includes(col)) { + updated.push(col); + } + } + if (updated.length > 0) { + return true; + } + } else { + return true; + } + } + + for (const row of oldRows || []) { + const newr = oldRows?.find(r => key.every(col => r[col] == row[col])); + if (!newr) { + return true; + } + } + + return false; +} + +export function removePreloadedRowsFromStructure(db: DatabaseInfo): DatabaseInfo { + if (!db) { + return db; + } + + return { + ...db, + tables: (db.tables || []).map(tbl => ({ + ...tbl, + preloadedRows: undefined, + preloadedRowsKey: undefined, + preloadedRowsInsertOnly: undefined, + })), + }; +}