diff --git a/integration-tests/__tests__/deploy-database.spec.js b/integration-tests/__tests__/deploy-database.spec.js index d640a397f..bb6c595f5 100644 --- a/integration-tests/__tests__/deploy-database.spec.js +++ b/integration-tests/__tests__/deploy-database.spec.js @@ -10,7 +10,6 @@ const connectUtility = require('dbgate-api/src/utility/connectUtility'); function checkStructure(structure, model, { checkRenameDeletedObjects = false, disallowExtraObjects = false }) { const expected = databaseInfoFromYamlModel(model); - expect(structure.tables.length).toEqual(expected.tables.length); for (const expectedTable of expected.tables) { const realTable = structure.tables.find(x => x.pureName == expectedTable.pureName); @@ -50,8 +49,13 @@ function checkStructure(structure, model, { checkRenameDeletedObjects = false, d } async function testDatabaseDeploy(conn, driver, dbModelsYaml, options) { - const { testEmptyLastScript, checkDeletedObjects, finalCheckAgainstModel, finalCheckAgainstFirstModel } = - options || {}; + const { + testEmptyLastScript, + checkDeletedObjects, + finalCheckAgainstModel, + finalCheckAgainstFirstModel, + dbdiffOptionsExtra, + } = options || {}; let index = 0; for (const loadedDbModel of dbModelsYaml) { const { sql, isEmpty } = await generateDeploySql({ @@ -59,6 +63,7 @@ async function testDatabaseDeploy(conn, driver, dbModelsYaml, options) { connection: conn.isPreparedOnly ? conn : undefined, driver, loadedDbModel, + dbdiffOptionsExtra, }); console.debug('Generated deploy script:', sql); expect(sql.toUpperCase().includes('DROP ')).toBeFalsy(); @@ -73,6 +78,7 @@ async function testDatabaseDeploy(conn, driver, dbModelsYaml, options) { connection: conn.isPreparedOnly ? conn : undefined, driver, loadedDbModel, + dbdiffOptionsExtra, }); index++; @@ -447,4 +453,36 @@ describe('Deploy database', () => { ); }) ); + + test.each(engines.map(engine => [engine.label, engine]))( + 'Mark table removed - %s', + testWrapper(async (conn, driver, engine) => { + await testDatabaseDeploy( + conn, + driver, + [ + [ + { + name: 't1.table.yaml', + json: { + name: 't1', + columns: [ + { name: 'id', type: 'int' }, + { name: 'val', type: 'int' }, + ], + primaryKey: ['id'], + }, + }, + ], + [], + ], + { + checkRenameDeletedObjects: true, + dbdiffOptionsExtra: { + allowTableMarkDropped: true, + }, + } + ); + }) + ); }); diff --git a/packages/api/src/shell/deployDb.js b/packages/api/src/shell/deployDb.js index ff722da04..17243b820 100644 --- a/packages/api/src/shell/deployDb.js +++ b/packages/api/src/shell/deployDb.js @@ -9,6 +9,7 @@ async function deployDb({ modelFolder, loadedDbModel, modelTransforms, + dbdiffOptionsExtra, }) { const { sql } = await generateDeploySql({ connection, @@ -18,6 +19,7 @@ async function deployDb({ modelFolder, loadedDbModel, modelTransforms, + dbdiffOptionsExtra, }); // console.log('RUNNING DEPLOY SCRIPT:', sql); await executeQuery({ connection, systemConnection, driver, sql, logScriptItems: true }); diff --git a/packages/api/src/shell/generateDeploySql.js b/packages/api/src/shell/generateDeploySql.js index 3766793ee..5ba4f10d3 100644 --- a/packages/api/src/shell/generateDeploySql.js +++ b/packages/api/src/shell/generateDeploySql.js @@ -19,6 +19,7 @@ async function generateDeploySql({ modelFolder = undefined, loadedDbModel = undefined, modelTransforms = undefined, + dbdiffOptionsExtra = {}, }) { if (!driver) driver = requireEngineDriver(connection); @@ -48,6 +49,8 @@ async function generateDeploySql({ noDropSqlObject: true, noRenameTable: true, noRenameColumn: true, + + ...dbdiffOptionsExtra, }; const currentModelPaired = matchPairedObjects(deployedModel, currentModel, opts); const currentModelPairedPreloaded = await enrichWithPreloadedRows(deployedModel, currentModelPaired, dbhan, driver); diff --git a/packages/tools/src/alterPlan.ts b/packages/tools/src/alterPlan.ts index 116228b9b..c40f9aa1b 100644 --- a/packages/tools/src/alterPlan.ts +++ b/packages/tools/src/alterPlan.ts @@ -441,7 +441,7 @@ export class AlterPlan { // console.log('*****************RECREATED NEEDED', op, operationType, isAllowed); // console.log(this.dialect); - if (this.opts.noDropTable) { + if (this.opts.noDropTable && !this.opts.allowTableRecreateWhenNoDrop) { // skip this operation, as it cannot be achieved return []; } diff --git a/packages/tools/src/diffTools.ts b/packages/tools/src/diffTools.ts index adb103adb..9f28c8bd2 100644 --- a/packages/tools/src/diffTools.ts +++ b/packages/tools/src/diffTools.ts @@ -35,9 +35,17 @@ export interface DbDiffOptions { ignoreConstraintNames?: boolean; noDropTable?: boolean; + allowTableRecreateWhenNoDrop?: boolean; + allowTableMarkDropped?: boolean; + noDropColumn?: boolean; + allowColumnMarkDropped?: boolean; + noDropConstraint?: boolean; + noDropSqlObject?: boolean; + allowSqlObjectMarkDropped?: boolean; + noRenameTable?: boolean; noRenameColumn?: boolean; @@ -565,7 +573,9 @@ export function createAlterDatabasePlan( const newobj = (newDb[objectTypeField] || []).find(x => x.pairingId == oldobj.pairingId); if (objectTypeField == 'tables') { if (newobj == null) { - if (!opts.noDropTable) { + if (opts.allowTableMarkDropped) { + plan.renameTable(oldobj, '_deleted_' + oldobj.pureName); + } else if (!opts.noDropTable) { plan.dropTable(oldobj); } } else {