mirror of
https://github.com/dbgate/dbgate
synced 2024-11-07 20:26:23 +00:00
db diff report
This commit is contained in:
parent
336edfc93f
commit
17286e0c3e
@ -29,6 +29,8 @@
|
||||
"dbgate-query-splitter": "^4.1.1",
|
||||
"dbgate-sqltree": "^4.1.1",
|
||||
"dbgate-tools": "^4.1.1",
|
||||
"diff": "^5.0.0",
|
||||
"diff2html": "^3.4.13",
|
||||
"eslint": "^6.8.0",
|
||||
"express": "^4.17.1",
|
||||
"express-basic-auth": "^1.2.0",
|
||||
|
@ -3,16 +3,27 @@ const connections = require('./connections');
|
||||
const archive = require('./archive');
|
||||
const socket = require('../utility/socket');
|
||||
const { fork } = require('child_process');
|
||||
const { DatabaseAnalyser, getAlterDatabaseScript, generateDbPairingId, matchPairedObjects } = require('dbgate-tools');
|
||||
const {
|
||||
DatabaseAnalyser,
|
||||
computeDbDiffRows,
|
||||
getCreateObjectScript,
|
||||
getAlterDatabaseScript,
|
||||
generateDbPairingId,
|
||||
matchPairedObjects,
|
||||
extendDatabaseInfo,
|
||||
} = require('dbgate-tools');
|
||||
const { html, parse } = require('diff2html');
|
||||
const { handleProcessCommunication } = require('../utility/processComm');
|
||||
const config = require('./config');
|
||||
const fs = require('fs-extra');
|
||||
const exportDbModel = require('../utility/exportDbModel');
|
||||
const { archivedir, resolveArchiveFolder } = require('../utility/directories');
|
||||
const { archivedir, resolveArchiveFolder, uploadsdir } = require('../utility/directories');
|
||||
const path = require('path');
|
||||
const importDbModel = require('../utility/importDbModel');
|
||||
const requireEngineDriver = require('../utility/requireEngineDriver');
|
||||
const generateDeploySql = require('../shell/generateDeploySql');
|
||||
const { createTwoFilesPatch } = require('diff');
|
||||
const diff2htmlPage = require('../utility/diff2htmlPage');
|
||||
|
||||
module.exports = {
|
||||
/** @type {import('dbgate-types').OpenedDatabaseConnection[]} */
|
||||
@ -285,4 +296,55 @@ module.exports = {
|
||||
// const res = await this.sendRequest(opened, { msgtype: 'queryData', sql });
|
||||
// return res;
|
||||
// },
|
||||
|
||||
async getUnifiedDiff({ sourceConid, sourceDatabase, targetConid, targetDatabase }) {
|
||||
const dbDiffOptions = {
|
||||
// schemaMode: 'ignore',
|
||||
};
|
||||
|
||||
const sourceDb = generateDbPairingId(
|
||||
extendDatabaseInfo(await this.structure({ conid: sourceConid, database: sourceDatabase }))
|
||||
);
|
||||
const targetDb = generateDbPairingId(
|
||||
extendDatabaseInfo(await this.structure({ conid: targetConid, database: targetDatabase }))
|
||||
);
|
||||
// const sourceConnection = await connections.get({conid:sourceConid})
|
||||
const connection = await connections.get({ conid: targetConid });
|
||||
const driver = requireEngineDriver(connection);
|
||||
const targetDbPaired = matchPairedObjects(sourceDb, targetDb, dbDiffOptions);
|
||||
const diffRows = computeDbDiffRows(sourceDb, targetDbPaired, dbDiffOptions, driver);
|
||||
|
||||
// console.log('sourceDb', sourceDb);
|
||||
// console.log('targetDb', targetDb);
|
||||
// console.log('sourceConid, sourceDatabase', sourceConid, sourceDatabase);
|
||||
|
||||
let res = '';
|
||||
for (const row of diffRows) {
|
||||
// console.log('PAIR', row.source && row.source.pureName, row.target && row.target.pureName);
|
||||
const unifiedDiff = createTwoFilesPatch(
|
||||
(row.source && row.source.pureName) || '',
|
||||
(row.target && row.target.pureName) || '',
|
||||
getCreateObjectScript(row.source, driver),
|
||||
getCreateObjectScript(row.target, driver),
|
||||
'',
|
||||
''
|
||||
);
|
||||
res += unifiedDiff;
|
||||
}
|
||||
return res;
|
||||
},
|
||||
|
||||
generateDbDiffReport_meta: 'post',
|
||||
async generateDbDiffReport({ sourceConid, sourceDatabase, targetConid, targetDatabase }) {
|
||||
const unifiedDiff = await this.getUnifiedDiff({ sourceConid, sourceDatabase, targetConid, targetDatabase });
|
||||
|
||||
const diffJson = parse(unifiedDiff);
|
||||
// $: diffHtml = html(diffJson, { outputFormat: 'side-by-side', drawFileList: false });
|
||||
const diffHtml = html(diffJson, {});
|
||||
|
||||
const fileName = `${uuidv1()}.html`;
|
||||
await fs.writeFile(path.join(uploadsdir(), fileName), diff2htmlPage(diffHtml));
|
||||
|
||||
return fileName;
|
||||
},
|
||||
};
|
||||
|
@ -25,4 +25,12 @@ module.exports = {
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
get_meta: {
|
||||
method: 'get',
|
||||
raw: true,
|
||||
},
|
||||
get(req, res) {
|
||||
res.sendFile(path.join(uploadsdir(), req.query.file));
|
||||
},
|
||||
};
|
||||
|
8
packages/api/src/utility/diff2htmlPage.js
Normal file
8
packages/api/src/utility/diff2htmlPage.js
Normal file
@ -0,0 +1,8 @@
|
||||
const diff2htmlCss =
|
||||
'.d2h-d-none{display:none}.d2h-wrapper{text-align:left}.d2h-file-header{background-color:#f7f7f7;border-bottom:1px solid #d8d8d8;font-family:Source Sans Pro,Helvetica Neue,Helvetica,Arial,sans-serif;height:35px;padding:5px 10px}.d2h-file-header,.d2h-file-stats{display:-webkit-box;display:-ms-flexbox;display:flex}.d2h-file-stats{font-size:14px;margin-left:auto}.d2h-lines-added{border:1px solid #b4e2b4;border-radius:5px 0 0 5px;color:#399839;padding:2px;text-align:right;vertical-align:middle}.d2h-lines-deleted{border:1px solid #e9aeae;border-radius:0 5px 5px 0;color:#c33;margin-left:1px;padding:2px;text-align:left;vertical-align:middle}.d2h-file-name-wrapper{-webkit-box-align:center;-ms-flex-align:center;align-items:center;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:15px;width:100%}.d2h-file-name{overflow-x:hidden;text-overflow:ellipsis;white-space:nowrap}.d2h-file-wrapper{border:1px solid #ddd;border-radius:3px;margin-bottom:1em}.d2h-file-collapse{-webkit-box-pack:end;-ms-flex-pack:end;-webkit-box-align:center;-ms-flex-align:center;align-items:center;border:1px solid #ddd;border-radius:3px;cursor:pointer;display:none;font-size:12px;justify-content:flex-end;padding:4px 8px}.d2h-file-collapse.d2h-selected{background-color:#c8e1ff}.d2h-file-collapse-input{margin:0 4px 0 0}.d2h-diff-table{border-collapse:collapse;font-family:Menlo,Consolas,monospace;font-size:13px;width:100%}.d2h-files-diff{width:100%}.d2h-file-diff{overflow-y:hidden}.d2h-file-side-diff{display:inline-block;margin-bottom:-8px;margin-right:-4px;overflow-x:scroll;overflow-y:hidden;width:50%}.d2h-code-line{padding:0 8em}.d2h-code-line,.d2h-code-side-line{display:inline-block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;white-space:nowrap;width:100%}.d2h-code-side-line{padding:0 4.5em}.d2h-code-line-ctn{word-wrap:normal;background:none;display:inline-block;padding:0;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text;vertical-align:middle;white-space:pre;width:100%}.d2h-code-line del,.d2h-code-side-line del{background-color:#ffb6ba}.d2h-code-line del,.d2h-code-line ins,.d2h-code-side-line del,.d2h-code-side-line ins{border-radius:.2em;display:inline-block;margin-top:-1px;text-decoration:none;vertical-align:middle}.d2h-code-line ins,.d2h-code-side-line ins{background-color:#97f295;text-align:left}.d2h-code-line-prefix{word-wrap:normal;background:none;display:inline;padding:0;white-space:pre}.line-num1{float:left}.line-num1,.line-num2{-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden;padding:0 .5em;text-overflow:ellipsis;width:3.5em}.line-num2{float:right}.d2h-code-linenumber{background-color:#fff;border:solid #eee;border-width:0 1px;-webkit-box-sizing:border-box;box-sizing:border-box;color:rgba(0,0,0,.3);cursor:pointer;display:inline-block;position:absolute;text-align:right;width:7.5em}.d2h-code-linenumber:after{content:"\200b"}.d2h-code-side-linenumber{background-color:#fff;border:solid #eee;border-width:0 1px;-webkit-box-sizing:border-box;box-sizing:border-box;color:rgba(0,0,0,.3);cursor:pointer;display:inline-block;overflow:hidden;padding:0 .5em;position:absolute;text-align:right;text-overflow:ellipsis;width:4em}.d2h-code-side-linenumber:after{content:"\200b"}.d2h-code-side-emptyplaceholder,.d2h-emptyplaceholder{background-color:#f1f1f1;border-color:#e1e1e1}.d2h-code-line-prefix,.d2h-code-linenumber,.d2h-code-side-linenumber,.d2h-emptyplaceholder{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.d2h-code-linenumber,.d2h-code-side-linenumber{direction:rtl}.d2h-del{background-color:#fee8e9;border-color:#e9aeae}.d2h-ins{background-color:#dfd;border-color:#b4e2b4}.d2h-info{background-color:#f8fafd;border-color:#d5e4f2;color:rgba(0,0,0,.3)}.d2h-file-diff .d2h-del.d2h-change{background-color:#fdf2d0}.d2h-file-diff .d2h-ins.d2h-change{background-color:#ded}.d2h-file-list-wrapper{margin-bottom:10px}.d2h-file-list-wrapper a{color:#3572b0;text-decoration:none}.d2h-file-list-wrapper a:visited{color:#3572b0}.d2h-file-list-header{text-align:left}.d2h-file-list-title{font-weight:700}.d2h-file-list-line{display:-webkit-box;display:-ms-flexbox;display:flex;text-align:left}.d2h-file-list{display:block;list-style:none;margin:0;padding:0}.d2h-file-list>li{border-bottom:1px solid #ddd;margin:0;padding:5px 10px}.d2h-file-list>li:last-child{border-bottom:none}.d2h-file-switch{cursor:pointer;display:none;font-size:10px}.d2h-icon{fill:currentColor;margin-right:10px;vertical-align:middle}.d2h-deleted{color:#c33}.d2h-added{color:#399839}.d2h-changed{color:#d0b44c}.d2h-moved{color:#3572b0}.d2h-tag{background-color:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:10px;margin-left:5px;padding:0 2px}.d2h-deleted-tag{border:1px solid #c33}.d2h-added-tag{border:1px solid #399839}.d2h-changed-tag{border:1px solid #d0b44c}.d2h-moved-tag{border:1px solid #3572b0}';
|
||||
|
||||
function diff2htmlPage(content) {
|
||||
return `<html><head><style>${diff2htmlCss}</style><body>${content}</body></html>`;
|
||||
}
|
||||
|
||||
module.exports = diff2htmlPage;
|
@ -1,4 +1,4 @@
|
||||
import { DbDiffOptions, testEqualColumns, testEqualTables } from 'dbgate-tools';
|
||||
import { DbDiffOptions, testEqualColumns, testEqualTables } from './diffTools';
|
||||
import { DatabaseInfo, EngineDriver, TableInfo } from 'dbgate-types';
|
||||
|
||||
export function computeDiffRowsCore(sourceList, targetList, testEqual) {
|
||||
@ -69,7 +69,7 @@ export function computeTableDiffColumns(
|
||||
}));
|
||||
}
|
||||
|
||||
export function getCreateTableScript(table: TableInfo, driver: EngineDriver) {
|
||||
export function getCreateObjectScript(table: TableInfo, driver: EngineDriver) {
|
||||
if (!table || !driver) return '';
|
||||
const dmp = driver.createDumper();
|
||||
dmp.createTable(table);
|
@ -15,3 +15,4 @@ export * from './diffTools';
|
||||
export * from './schemaEditorTools';
|
||||
export * from './yamlModelConv';
|
||||
export * from './stringTools';
|
||||
export * from './computeDiffRows';
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
{#if isNative}
|
||||
<select
|
||||
value={value || defaultValue}
|
||||
value={options.find(x => x.value == value) ? value : defaultValue}
|
||||
{...$$restProps}
|
||||
on:change={e => {
|
||||
dispatch('change', e.target['value']);
|
||||
|
@ -74,6 +74,7 @@
|
||||
'icon menu': 'mdi mdi-menu',
|
||||
'icon add-column': 'mdi mdi-table-column-plus-after',
|
||||
'icon add-key': 'mdi mdi-key-plus',
|
||||
'icon report': 'mdi mdi-file-chart',
|
||||
|
||||
'img ok': 'mdi mdi-check-circle color-icon-green',
|
||||
'img ok-inv': 'mdi mdi-check-circle color-icon-inv-green',
|
||||
|
@ -1,12 +1,35 @@
|
||||
<script lang="ts" context="module">
|
||||
export const matchingProps = [];
|
||||
|
||||
const getCurrentEditor = () => getActiveComponent('CompareModelTab');
|
||||
|
||||
registerCommand({
|
||||
id: 'compareModels.reportDiff',
|
||||
category: 'Compare models',
|
||||
toolbarName: 'Report',
|
||||
name: 'Report diff',
|
||||
icon: 'icon report',
|
||||
toolbar: true,
|
||||
isRelatedToTab: true,
|
||||
onClick: () => getCurrentEditor().showReport(),
|
||||
testEnabled: () => getCurrentEditor() != null,
|
||||
});
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { findEngineDriver, generateDbPairingId, getAlterTableScript, matchPairedObjects } from 'dbgate-tools';
|
||||
import {
|
||||
findEngineDriver,
|
||||
generateDbPairingId,
|
||||
getAlterTableScript,
|
||||
matchPairedObjects,
|
||||
computeDbDiffRows,
|
||||
computeTableDiffColumns,
|
||||
getCreateObjectScript,
|
||||
} from 'dbgate-tools';
|
||||
|
||||
import _ from 'lodash';
|
||||
import { derived, writable } from 'svelte/store';
|
||||
import registerCommand from '../commands/registerCommand';
|
||||
import DiffView from '../elements/DiffView.svelte';
|
||||
import ScrollableTableControl from '../elements/ScrollableTableControl.svelte';
|
||||
import TabControl from '../elements/TabControl.svelte';
|
||||
@ -20,13 +43,17 @@
|
||||
import SqlEditor from '../query/SqlEditor.svelte';
|
||||
import useEditorData from '../query/useEditorData';
|
||||
import { extensions } from '../stores';
|
||||
import { computeDbDiffRows, computeTableDiffColumns, getCreateTableScript } from '../utility/computeDiffRows';
|
||||
import axiosInstance from '../utility/axiosInstance';
|
||||
import createActivator, { getActiveComponent } from '../utility/createActivator';
|
||||
import { useConnectionInfo, useDatabaseInfo } from '../utility/metadataLoaders';
|
||||
import resolveApi from '../utility/resolveApi';
|
||||
|
||||
export let tabid;
|
||||
|
||||
let pairIndex = 0;
|
||||
|
||||
export const activator = createActivator('CompareModelTab', true);
|
||||
|
||||
// let values = writable({
|
||||
// sourceConid: null,
|
||||
// sourceDatabase: null,
|
||||
@ -64,6 +91,24 @@
|
||||
driver
|
||||
).sql;
|
||||
|
||||
export async function showReport() {
|
||||
const resp = await axiosInstance.post('database-connections/generate-db-diff-report', {
|
||||
sourceConid: $values?.sourceConid,
|
||||
sourceDatabase: $values?.sourceDatabase,
|
||||
targetConid: $values?.targetConid,
|
||||
targetDatabase: $values?.targetDatabase,
|
||||
});
|
||||
|
||||
window.open(`${resolveApi()}/uploads/get?file=${resp.data}`, '_blank');
|
||||
|
||||
// window.open(
|
||||
// `${resolveApi()}/database-connections/get-diff-html?sourceConid=` +
|
||||
// `${$values?.sourceConid}&sourceDatabase=${$values?.sourceDatabase}&` +
|
||||
// `targetConid=${$values?.targetConid}&targetDatabase=${$values?.targetDatabase}`,
|
||||
// '_blank'
|
||||
// );
|
||||
}
|
||||
|
||||
const { editorState, editorValue, setEditorData } = useEditorData({
|
||||
tabid,
|
||||
// onInitialData: value => {
|
||||
@ -162,8 +207,8 @@
|
||||
<DiffView
|
||||
leftTitle={diffRows[pairIndex]?.source?.pureName}
|
||||
rightTitle={diffRows[pairIndex]?.source?.pureName}
|
||||
leftText={getCreateTableScript(diffRows[pairIndex]?.source, driver)}
|
||||
rightText={getCreateTableScript(diffRows[pairIndex]?.target, driver)}
|
||||
leftText={getCreateObjectScript(diffRows[pairIndex]?.source, driver)}
|
||||
rightText={getCreateObjectScript(diffRows[pairIndex]?.target, driver)}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user