diff --git a/integration-tests/__tests__/alter-database.spec.js b/integration-tests/__tests__/alter-database.spec.js index 90a80f15..dae829f2 100644 --- a/integration-tests/__tests__/alter-database.spec.js +++ b/integration-tests/__tests__/alter-database.spec.js @@ -5,10 +5,12 @@ const { testWrapper } = require('../tools'); const engines = require('../engines'); const { getAlterDatabaseScript, extendDatabaseInfo, generateDbPairingId } = require('dbgate-tools'); -function flatSource() { +const initSql = ['CREATE TABLE t1 (id int primary key)', 'CREATE TABLE t2 (id int primary key)']; + +function flatSource(engineCond = x => !x.skipReferences) { return _.flatten( engines - .filter(x => !x.skipReferences) + .filter(engineCond) .map(engine => (engine.objects || []).map(object => [engine.label, object.type, object, engine])) ); } @@ -66,5 +68,24 @@ describe('Alter database', () => { expect(db[type].length).toEqual(0); }) ); -}); + test.each(flatSource(x => x.supportRenameSqlObject))( + 'Rename object - %s - %s', + testWrapper(async (conn, driver, type, object, engine) => { + for (const sql of initSql) await driver.query(conn, sql, { discardResult: true }); + + await driver.query(conn, object.create1, { discardResult: true }); + + const structure = extendDatabaseInfo(await driver.analyseFull(conn)); + + const dmp = driver.createDumper(); + dmp.renameSqlObject(structure[type][0], 'renamed1'); + + await driver.query(conn, dmp.s); + + const structure2 = await driver.analyseFull(conn); + expect(structure2[type].length).toEqual(1); + expect(structure2[type][0].pureName).toEqual('renamed1'); + }) + ); +}); diff --git a/integration-tests/engines.js b/integration-tests/engines.js index 516e1e89..eb14d8c4 100644 --- a/integration-tests/engines.js +++ b/integration-tests/engines.js @@ -96,6 +96,7 @@ const engines = [ }, ], supportSchemas: true, + supportRenameSqlObject: true, defaultSchemaName: 'public', dumpFile: 'data/chinook-postgre.sql', dumpChecks: [ @@ -129,6 +130,7 @@ const engines = [ }, ], supportSchemas: true, + supportRenameSqlObject: true, defaultSchemaName: 'dbo', // skipSeparateSchemas: true, }, @@ -184,9 +186,9 @@ const engines = [ const filterLocal = [ // filter local testing - 'MySQL', + '-MySQL', '-MariaDB', - '-PostgreSQL', + 'PostgreSQL', '-SQL Server', '-SQLite', '-CockroachDB', diff --git a/packages/tools/src/SqlDumper.ts b/packages/tools/src/SqlDumper.ts index 4636377c..85f369c9 100644 --- a/packages/tools/src/SqlDumper.ts +++ b/packages/tools/src/SqlDumper.ts @@ -588,6 +588,8 @@ export class SqlDumper implements AlterProcessor { renameTable(obj: TableInfo, newname: string) {} + renameSqlObject(obj: SqlObjectInfo, newname: string) {} + beginTransaction() { this.putCmd('^begin ^transaction'); } diff --git a/packages/tools/src/alterPlan.ts b/packages/tools/src/alterPlan.ts index c40f9aa1..6de602ce 100644 --- a/packages/tools/src/alterPlan.ts +++ b/packages/tools/src/alterPlan.ts @@ -39,6 +39,12 @@ interface AlterOperation_RenameTable { newName: string; } +interface AlterOperation_RenameSqlObject { + operationType: 'renameSqlObject'; + object: SqlObjectInfo; + newName: string; +} + interface AlterOperation_CreateColumn { operationType: 'createColumn'; newObject: ColumnInfo; @@ -120,7 +126,8 @@ type AlterOperation = | AlterOperation_DropSqlObject | AlterOperation_RecreateTable | AlterOperation_FillPreloadedRows - | AlterOperation_SetTableOption; + | AlterOperation_SetTableOption + | AlterOperation_RenameSqlObject; export class AlterPlan { recreates = { @@ -217,6 +224,14 @@ export class AlterPlan { }); } + renameSqlObject(table: TableInfo, newName: string) { + this.operations.push({ + operationType: 'renameSqlObject', + object: table, + newName, + }); + } + renameColumn(column: ColumnInfo, newName: string) { this.operations.push({ operationType: 'renameColumn', @@ -595,6 +610,9 @@ export function runAlterOperation(op: AlterOperation, processor: AlterProcessor) case 'renameTable': processor.renameTable(op.object, op.newName); break; + case 'renameSqlObject': + processor.renameSqlObject(op.object, op.newName); + break; case 'renameConstraint': processor.renameConstraint(op.object, op.newName); break; diff --git a/packages/tools/src/database-info-alter-processor.ts b/packages/tools/src/database-info-alter-processor.ts index 90031d17..3a993772 100644 --- a/packages/tools/src/database-info-alter-processor.ts +++ b/packages/tools/src/database-info-alter-processor.ts @@ -112,6 +112,11 @@ export class DatabaseInfoAlterProcessor { this.db.tables.find(x => x.pureName == table.pureName && x.schemaName == table.schemaName).pureName = newName; } + renameSqlObject(obj: SqlObjectInfo, newName: string) { + this.db[obj.objectTypeField].find(x => x.pureName == obj.pureName && x.schemaName == obj.schemaName).pureName = + newName; + } + renameColumn(column: ColumnInfo, newName: string) { const table = this.db.tables.find(x => x.pureName == column.pureName && x.schemaName == column.schemaName); table.columns.find(x => x.columnName == column.columnName).columnName = newName; diff --git a/packages/tools/src/diffTools.ts b/packages/tools/src/diffTools.ts index e441b56e..fb38c35d 100644 --- a/packages/tools/src/diffTools.ts +++ b/packages/tools/src/diffTools.ts @@ -583,7 +583,9 @@ export function createAlterDatabasePlan( } } else { if (newobj == null) { - if (!opts.noDropSqlObject) { + if (opts.allowSqlObjectMarkDropped) { + plan.renameSqlObject(oldobj, '_deleted_' + oldobj.pureName); + } else if (!opts.noDropSqlObject) { plan.dropSqlObject(oldobj); } } else if (!testEqualSqlObjects(oldobj.createSql, newobj.createSql, opts)) { diff --git a/packages/types/alter-processor.d.ts b/packages/types/alter-processor.d.ts index fae6d4fe..869da055 100644 --- a/packages/types/alter-processor.d.ts +++ b/packages/types/alter-processor.d.ts @@ -10,6 +10,7 @@ export interface AlterProcessor { changeConstraint(oldConstraint: ConstraintInfo, newConstraint: ConstraintInfo); dropConstraint(constraint: ConstraintInfo); renameTable(table: TableInfo, newName: string); + renameSqlObject(obj: SqlObjectInfo, newName: string); renameColumn(column: ColumnInfo, newName: string); renameConstraint(constraint: ConstraintInfo, newName: string); recreateTable(oldTable: TableInfo, newTable: TableInfo); diff --git a/packages/types/dialect.d.ts b/packages/types/dialect.d.ts index 964cab2b..6df3e216 100644 --- a/packages/types/dialect.d.ts +++ b/packages/types/dialect.d.ts @@ -34,6 +34,7 @@ export interface SqlDialect { dropUnique?: boolean; createCheck?: boolean; dropCheck?: boolean; + renameSqlObject?: boolean; specificNullabilityImplementation?: boolean; omitForeignKeys?: boolean; diff --git a/plugins/dbgate-plugin-mssql/src/frontend/MsSqlDumper.js b/plugins/dbgate-plugin-mssql/src/frontend/MsSqlDumper.js index 61f27cf9..68f59953 100644 --- a/plugins/dbgate-plugin-mssql/src/frontend/MsSqlDumper.js +++ b/plugins/dbgate-plugin-mssql/src/frontend/MsSqlDumper.js @@ -175,5 +175,6 @@ MsSqlDumper.prototype.changeTriggerSchema = MsSqlDumper.prototype.changeObjectSc MsSqlDumper.prototype.renameTable = MsSqlDumper.prototype.renameObject; MsSqlDumper.prototype.changeTableSchema = MsSqlDumper.prototype.changeObjectSchema; +MsSqlDumper.prototype.renameSqlObject = MsSqlDumper.prototype.renameObject; module.exports = MsSqlDumper; diff --git a/plugins/dbgate-plugin-mssql/src/frontend/driver.js b/plugins/dbgate-plugin-mssql/src/frontend/driver.js index f9f1e3fa..14456db7 100644 --- a/plugins/dbgate-plugin-mssql/src/frontend/driver.js +++ b/plugins/dbgate-plugin-mssql/src/frontend/driver.js @@ -37,6 +37,7 @@ const dialect = { dropUnique: true, createCheck: true, dropCheck: true, + renameSqlObject: true, dropReferencesWhenDropTable: true, diff --git a/plugins/dbgate-plugin-postgres/src/frontend/Dumper.js b/plugins/dbgate-plugin-postgres/src/frontend/Dumper.js index a6aa44d6..dd269f59 100644 --- a/plugins/dbgate-plugin-postgres/src/frontend/Dumper.js +++ b/plugins/dbgate-plugin-postgres/src/frontend/Dumper.js @@ -38,6 +38,10 @@ class Dumper extends SqlDumper { this.putCmd('^alter ^table %f ^rename ^to %i', obj, newname); } + renameSqlObject(obj, newname) { + this.putCmd('^alter %k %f ^rename ^to %i', this.getSqlObjectSqlName(obj.objectTypeField), obj, newname); + } + renameColumn(column, newcol) { this.putCmd('^alter ^table %f ^rename ^column %i ^to %i', column, column.columnName, newcol); } diff --git a/plugins/dbgate-plugin-postgres/src/frontend/drivers.js b/plugins/dbgate-plugin-postgres/src/frontend/drivers.js index 7dd8d129..6b13f6be 100644 --- a/plugins/dbgate-plugin-postgres/src/frontend/drivers.js +++ b/plugins/dbgate-plugin-postgres/src/frontend/drivers.js @@ -34,6 +34,7 @@ const dialect = { createCheck: true, dropCheck: true, allowMultipleValuesInsert: true, + renameSqlObject: true, dropReferencesWhenDropTable: true, requireStandaloneSelectForScopeIdentity: true,