mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
deploy DB WIP
This commit is contained in:
parent
425bed050b
commit
e653b793d8
@ -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}`);
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -4,13 +4,15 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import _ from 'lodash';
|
||||
import { filterName } from 'dbgate-tools';
|
||||
|
||||
import { currentArchive } from '../stores';
|
||||
import { currentArchive, currentDatabase } from '../stores';
|
||||
|
||||
import axiosInstance from '../utility/axiosInstance';
|
||||
import openNewTab from '../utility/openNewTab';
|
||||
import AppObjectCore from './AppObjectCore.svelte';
|
||||
import newQuery from '../query/newQuery';
|
||||
|
||||
export let data;
|
||||
|
||||
@ -25,14 +27,33 @@
|
||||
icon: 'img shell',
|
||||
tabComponent: 'ShellTab',
|
||||
},
|
||||
{ editor: `await dbgateApi.deployDb()` }
|
||||
{
|
||||
editor: `await dbgateApi.deployDb(${JSON.stringify({
|
||||
..._.omit($currentDatabase.connection, '_id', 'displayName'),
|
||||
database: $currentDatabase.name,
|
||||
})}, 'archive:${data.name}')`,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const handleGenerateDeploySql = async () => {
|
||||
const resp = await axiosInstance.post('database-connections/generate-deploy-sql', {
|
||||
conid: $currentDatabase.connection._id,
|
||||
database: $currentDatabase.name,
|
||||
archiveFolder: data.name,
|
||||
});
|
||||
|
||||
newQuery({ initialData: resp.data });
|
||||
};
|
||||
|
||||
function createMenu() {
|
||||
return [
|
||||
data.name != 'default' && { text: 'Delete', onClick: handleDelete },
|
||||
data.name != 'default' && { text: 'Generate deploy script', onClick: handleGenerateDeployScript },
|
||||
data.name != 'default' &&
|
||||
$currentDatabase && [
|
||||
{ text: 'Generate deploy DB SQL', onClick: handleGenerateDeploySql },
|
||||
{ text: 'Shell: Deploy DB', onClick: handleGenerateDeployScript },
|
||||
],
|
||||
];
|
||||
}
|
||||
</script>
|
||||
|
Loading…
Reference in New Issue
Block a user