diff --git a/packages/api/src/controllers/databaseConnections.js b/packages/api/src/controllers/databaseConnections.js index 20080faf7..b13671bce 100644 --- a/packages/api/src/controllers/databaseConnections.js +++ b/packages/api/src/controllers/databaseConnections.js @@ -3,13 +3,15 @@ const connections = require('./connections'); const archive = require('./archive'); const socket = require('../utility/socket'); const { fork } = require('child_process'); -const { DatabaseAnalyser } = require('dbgate-tools'); +const { DatabaseAnalyser, getAlterDatabaseScript, generateDbPairingId, matchPairedObjects } = require('dbgate-tools'); const { handleProcessCommunication } = require('../utility/processComm'); const config = require('./config'); const fs = require('fs-extra'); const exportDbModel = require('../utility/exportDbModel'); const { archivedir } = require('../utility/directories'); const path = require('path'); +const importDbModel = require('../utility/importDbModel'); +const requireEngineDriver = require('../utility/requireEngineDriver'); module.exports = { /** @type {import('dbgate-types').OpenedDatabaseConnection[]} */ @@ -253,6 +255,22 @@ module.exports = { return { archiveFolder }; }, + generateDeploySql_meta: 'post', + async generateDeploySql({ conid, database, archiveFolder }) { + const deployedModel = generateDbPairingId(await importDbModel(path.join(archivedir(), archiveFolder))); + const currentModel = generateDbPairingId(await this.structure({ conid, database })); + const currentModelPaired = matchPairedObjects(deployedModel, currentModel); + const connection = await connections.get({ conid }); + const driver = requireEngineDriver(connection); + const { sql } = getAlterDatabaseScript(currentModelPaired, deployedModel, {}, deployedModel, driver); + return { + deployedModel, + currentModel, + currentModelPaired, + sql, + }; + return sql; + }, // runCommand_meta: 'post', // async runCommand({ conid, database, sql }) { // console.log(`Running SQL command , conid=${conid}, database=${database}, sql=${sql}`); diff --git a/packages/api/src/shell/index.js b/packages/api/src/shell/index.js index 2e3a42b83..4a2946c2b 100644 --- a/packages/api/src/shell/index.js +++ b/packages/api/src/shell/index.js @@ -19,6 +19,7 @@ const requirePlugin = require('./requirePlugin'); const download = require('./download'); const executeQuery = require('./executeQuery'); const loadFile = require('./loadFile'); +const deployDb = require('./deployDb'); const initializeApiEnvironment = require('./initializeApiEnvironment'); const dbgateApi = { @@ -42,6 +43,7 @@ const dbgateApi = { registerPlugins, executeQuery, loadFile, + deployDb, initializeApiEnvironment, }; diff --git a/packages/api/src/utility/importDbModel.js b/packages/api/src/utility/importDbModel.js index 760dfd145..182a11db2 100644 --- a/packages/api/src/utility/importDbModel.js +++ b/packages/api/src/utility/importDbModel.js @@ -2,22 +2,27 @@ const fs = require('fs-extra'); const path = require('path'); const yaml = require('js-yaml'); const { tableInfoFromYaml, DatabaseAnalyser } = require('dbgate-tools'); +const { startsWith } = require('lodash'); +const { archivedir } = require('./directories'); async function importDbModel(inputDir) { const tablesYaml = []; const model = DatabaseAnalyser.createEmptyStructure(); - for (const file of await fs.readdir(inputDir)) { + const dir = inputDir.startsWith('archive:') + ? path.join(archivedir(), inputDir.substring('archive:'.length)) + : inputDir; + + for (const file of await fs.readdir(dir)) { if (file.endsWith('.table.yaml') || file.endsWith('.sql')) { - const content = await fs.readFile(path.join(inputDir, file), { encoding: 'utf-8' }); + const content = await fs.readFile(path.join(dir, file), { encoding: 'utf-8' }); if (file.endsWith('.table.yaml')) { const json = yaml.load(content); tablesYaml.push(json); } - if (file.endsWith('.view.sql')) { model.views.push({ pureName: file.slice(0, -'.view.sql'.length), diff --git a/packages/tools/src/alterPlan.ts b/packages/tools/src/alterPlan.ts index d94b40db1..d47100a03 100644 --- a/packages/tools/src/alterPlan.ts +++ b/packages/tools/src/alterPlan.ts @@ -384,7 +384,7 @@ export class AlterPlan { const res = []; const recreates = {}; for (const op of this.operations) { - if (op.operationType == 'recreateTable') { + if (op.operationType == 'recreateTable' && op.table) { const existingRecreate = recreates[`${op.table.schemaName}||${op.table.pureName}`]; if (existingRecreate) { existingRecreate.operations.push(...op.operations); diff --git a/packages/tools/src/diffTools.ts b/packages/tools/src/diffTools.ts index 137650d48..251a56bec 100644 --- a/packages/tools/src/diffTools.ts +++ b/packages/tools/src/diffTools.ts @@ -357,9 +357,9 @@ export function createAlterDatabasePlan( for (const newobj of newDb[objectTypeField] || []) { const oldobj = (oldDb[objectTypeField] || []).find(x => x.pairingId == newobj.pairingId); if (objectTypeField == 'tables') { - if (newobj == null) plan.createTable(newobj); + if (oldobj == null) plan.createTable(newobj); } else { - if (newobj == null) plan.createSqlObject(newobj); + if (oldobj == null) plan.createSqlObject(newobj); } } } @@ -402,3 +402,25 @@ export function getAlterDatabaseScript( recreates: plan.recreates, }; } + +export function matchPairedObjects(db1: DatabaseInfo, db2: DatabaseInfo) { + const res = _.cloneDeep(db2); + + for (const objectTypeField of ['tables', 'views', 'procedures', 'matviews', 'functions']) { + for (const obj2 of res[objectTypeField] || []) { + const obj1 = db1[objectTypeField].find(x => x.pureName == obj2.pureName); + if (obj1) { + obj2.pairingId = obj1.pairingId; + + if (objectTypeField == 'tables') { + for (const col2 of obj2.columns) { + const col1 = obj1.columns.find(x => x.columnName == col2.columnName); + if (col1) col2.pairingId = col1.pairingId; + } + } + } + } + } + + return res; +} diff --git a/packages/web/src/appobj/ArchiveFolderAppObject.svelte b/packages/web/src/appobj/ArchiveFolderAppObject.svelte index 693f7643c..5185f7cf1 100644 --- a/packages/web/src/appobj/ArchiveFolderAppObject.svelte +++ b/packages/web/src/appobj/ArchiveFolderAppObject.svelte @@ -4,13 +4,15 @@