mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-05-01 02:43:59 +00:00
compare model tab
This commit is contained in:
@@ -368,6 +368,18 @@ function planAlterTable(plan: AlterPlan, oldTable: TableInfo, newTable: TableInf
|
|||||||
constraintPairs.filter(x => x[0] == null).forEach(x => plan.createConstraint(x[1]));
|
constraintPairs.filter(x => x[0] == null).forEach(x => plan.createConstraint(x[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function testEqualTables(
|
||||||
|
a: TableInfo,
|
||||||
|
b: TableInfo,
|
||||||
|
opts: DbDiffOptions,
|
||||||
|
db: DatabaseInfo,
|
||||||
|
driver: EngineDriver
|
||||||
|
) {
|
||||||
|
const plan = new AlterPlan(db, driver.dialect, opts);
|
||||||
|
planAlterTable(plan, a, b, opts);
|
||||||
|
return plan.operations.length == 0;
|
||||||
|
}
|
||||||
|
|
||||||
export function createAlterTablePlan(
|
export function createAlterTablePlan(
|
||||||
oldTable: TableInfo,
|
oldTable: TableInfo,
|
||||||
newTable: TableInfo,
|
newTable: TableInfo,
|
||||||
@@ -470,6 +482,8 @@ export function getAlterDatabaseScript(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function matchPairedObjects(db1: DatabaseInfo, db2: DatabaseInfo, opts: DbDiffOptions) {
|
export function matchPairedObjects(db1: DatabaseInfo, db2: DatabaseInfo, opts: DbDiffOptions) {
|
||||||
|
if (!db1 || !db2) return null;
|
||||||
|
|
||||||
const res = _cloneDeep(db2);
|
const res = _cloneDeep(db2);
|
||||||
|
|
||||||
for (const objectTypeField of ['tables', 'views', 'procedures', 'matviews', 'functions']) {
|
for (const objectTypeField of ['tables', 'views', 'procedures', 'matviews', 'functions']) {
|
||||||
|
|||||||
@@ -156,6 +156,20 @@ registerCommand({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registerCommand({
|
||||||
|
id: 'new.modelCompare',
|
||||||
|
category: 'New',
|
||||||
|
icon: 'img compare',
|
||||||
|
name: 'Compare DB Models',
|
||||||
|
onClick: () => {
|
||||||
|
openNewTab({
|
||||||
|
title: 'Compare',
|
||||||
|
icon: 'img compare',
|
||||||
|
tabComponent: 'CompareModelTab',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
registerCommand({
|
registerCommand({
|
||||||
id: 'new.freetable',
|
id: 'new.freetable',
|
||||||
category: 'New',
|
category: 'New',
|
||||||
|
|||||||
@@ -50,6 +50,8 @@
|
|||||||
'icon arrow-begin': 'mdi mdi-arrow-collapse-left',
|
'icon arrow-begin': 'mdi mdi-arrow-collapse-left',
|
||||||
'icon arrow-end': 'mdi mdi-arrow-collapse-right',
|
'icon arrow-end': 'mdi mdi-arrow-collapse-right',
|
||||||
'icon arrow-right': 'mdi mdi-arrow-right',
|
'icon arrow-right': 'mdi mdi-arrow-right',
|
||||||
|
'icon arrow-left-bold': 'mdi mdi-arrow-left-bold',
|
||||||
|
'icon arrow-right-bold': 'mdi mdi-arrow-right-bold',
|
||||||
'icon triple-left': 'mdi mdi-chevron-triple-left',
|
'icon triple-left': 'mdi mdi-chevron-triple-left',
|
||||||
'icon triple-right': 'mdi mdi-chevron-triple-right',
|
'icon triple-right': 'mdi mdi-chevron-triple-right',
|
||||||
'icon format-code': 'mdi mdi-code-tags-check',
|
'icon format-code': 'mdi mdi-code-tags-check',
|
||||||
@@ -97,6 +99,7 @@
|
|||||||
'img favorite': 'mdi mdi-star color-icon-yellow',
|
'img favorite': 'mdi mdi-star color-icon-yellow',
|
||||||
'img query-design': 'mdi mdi-vector-polyline-edit color-icon-red',
|
'img query-design': 'mdi mdi-vector-polyline-edit color-icon-red',
|
||||||
'img yaml': 'mdi mdi-code-brackets color-icon-red',
|
'img yaml': 'mdi mdi-code-brackets color-icon-red',
|
||||||
|
'img compare': 'mdi mdi-compare color-icon-red',
|
||||||
|
|
||||||
'img free-table': 'mdi mdi-table color-icon-green',
|
'img free-table': 'mdi mdi-table color-icon-green',
|
||||||
'img macro': 'mdi mdi-hammer-wrench',
|
'img macro': 'mdi mdi-hammer-wrench',
|
||||||
|
|||||||
@@ -149,7 +149,7 @@
|
|||||||
setPreviewSource={previewSource.set}
|
setPreviewSource={previewSource.set}
|
||||||
/>
|
/>
|
||||||
<div class="arrow">
|
<div class="arrow">
|
||||||
<FontIcon icon="icon arrow-right" />
|
<FontIcon icon="icon arrow-right-bold" />
|
||||||
</div>
|
</div>
|
||||||
<SourceTargetConfig
|
<SourceTargetConfig
|
||||||
direction="target"
|
direction="target"
|
||||||
|
|||||||
95
packages/web/src/tabs/CompareModelTab.svelte
Normal file
95
packages/web/src/tabs/CompareModelTab.svelte
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
<script lang="ts" context="module">
|
||||||
|
export const matchingProps = [];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { findEngineDriver, matchPairedObjects } from 'dbgate-tools';
|
||||||
|
|
||||||
|
import _ from 'lodash';
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
import TableControl from '../elements/TableControl.svelte';
|
||||||
|
import FormProviderCore from '../forms/FormProviderCore.svelte';
|
||||||
|
import FontIcon from '../icons/FontIcon.svelte';
|
||||||
|
import FormConnectionSelect from '../impexp/FormConnectionSelect.svelte';
|
||||||
|
import FormDatabaseSelect from '../impexp/FormDatabaseSelect.svelte';
|
||||||
|
import { extensions } from '../stores';
|
||||||
|
import { computeDiffRows } from '../utility/computeDiffRows';
|
||||||
|
import { useConnectionInfo, useDatabaseInfo } from '../utility/metadataLoaders';
|
||||||
|
|
||||||
|
let values = writable({
|
||||||
|
sourceConid: null,
|
||||||
|
sourceDatabase: null,
|
||||||
|
targetConid: null,
|
||||||
|
targetDatabase: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
const dbDiffOptions: any = {
|
||||||
|
ignoreCase: true,
|
||||||
|
schemaMode: 'ignore',
|
||||||
|
ignoreConstraintNames: true,
|
||||||
|
|
||||||
|
noDropTable: true,
|
||||||
|
noDropColumn: true,
|
||||||
|
noDropConstraint: true,
|
||||||
|
noDropSqlObject: true,
|
||||||
|
noRenameTable: true,
|
||||||
|
noRenameColumn: true,
|
||||||
|
ignoreForeignKeyActions: true,
|
||||||
|
ignoreDataTypes: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
$: sourceDb = useDatabaseInfo({ conid: $values.sourceConid, database: $values.sourceDatabase });
|
||||||
|
$: targetDb = useDatabaseInfo({ conid: $values.targetConid, database: $values.targetDatabase });
|
||||||
|
|
||||||
|
$: connection = useConnectionInfo({ conid: $values.targetConid });
|
||||||
|
$: driver = findEngineDriver($connection, $extensions);
|
||||||
|
|
||||||
|
$: targetDbPaired = matchPairedObjects($sourceDb, $targetDb, dbDiffOptions);
|
||||||
|
$: diffRows = computeDiffRows($sourceDb, targetDbPaired, dbDiffOptions, driver);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="wrapper">
|
||||||
|
<FormProviderCore {values}>
|
||||||
|
<div class="flex">
|
||||||
|
<div class="col-3">
|
||||||
|
<FormConnectionSelect name="sourceConid" label="Server" />
|
||||||
|
</div>
|
||||||
|
<div class="col-3">
|
||||||
|
<FormDatabaseSelect conidName="sourceConid" name="sourceDatabase" label="Database" />
|
||||||
|
</div>
|
||||||
|
<div class="arrow">
|
||||||
|
<FontIcon icon="icon arrow-right-bold" />
|
||||||
|
</div>
|
||||||
|
<div class="col-3">
|
||||||
|
<FormConnectionSelect name="targetConid" label="Target" />
|
||||||
|
</div>
|
||||||
|
<div class="col-3">
|
||||||
|
<FormDatabaseSelect conidName="targetConid" name="targetDatabase" label="Database" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormProviderCore>
|
||||||
|
|
||||||
|
<TableControl
|
||||||
|
rows={diffRows}
|
||||||
|
columns={[
|
||||||
|
{ fieldName: 'type', header: 'Type' },
|
||||||
|
{ fieldName: 'sourceSchemaName', header: 'Schema' },
|
||||||
|
{ fieldName: 'sourcePureName', header: 'Name' },
|
||||||
|
{ fieldName: 'state', header: 'Action' },
|
||||||
|
{ fieldName: 'targetSchemaName', header: 'Schema' },
|
||||||
|
{ fieldName: 'targetPureName', header: 'Name' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.wrapper {
|
||||||
|
overflow: auto;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.arrow {
|
||||||
|
font-size: 30px;
|
||||||
|
color: var(--theme-icon-blue);
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -15,6 +15,7 @@ import * as FavoriteEditorTab from './FavoriteEditorTab.svelte';
|
|||||||
import * as QueryDesignTab from './QueryDesignTab.svelte';
|
import * as QueryDesignTab from './QueryDesignTab.svelte';
|
||||||
import * as CommandListTab from './CommandListTab.svelte';
|
import * as CommandListTab from './CommandListTab.svelte';
|
||||||
import * as YamlEditorTab from './YamlEditorTab.svelte';
|
import * as YamlEditorTab from './YamlEditorTab.svelte';
|
||||||
|
import * as CompareModelTab from './CompareModelTab.svelte';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
TableDataTab,
|
TableDataTab,
|
||||||
@@ -34,4 +35,5 @@ export default {
|
|||||||
QueryDesignTab,
|
QueryDesignTab,
|
||||||
CommandListTab,
|
CommandListTab,
|
||||||
YamlEditorTab,
|
YamlEditorTab,
|
||||||
|
CompareModelTab,
|
||||||
};
|
};
|
||||||
|
|||||||
44
packages/web/src/utility/computeDiffRows.ts
Normal file
44
packages/web/src/utility/computeDiffRows.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import { DbDiffOptions, testEqualTables } from 'dbgate-tools';
|
||||||
|
import { DatabaseInfo, EngineDriver } from 'dbgate-types';
|
||||||
|
|
||||||
|
export function computeDiffRows(
|
||||||
|
sourceDb: DatabaseInfo,
|
||||||
|
targetDb: DatabaseInfo,
|
||||||
|
opts: DbDiffOptions,
|
||||||
|
driver: EngineDriver
|
||||||
|
) {
|
||||||
|
if (!sourceDb || !targetDb) return [];
|
||||||
|
const res = [];
|
||||||
|
for (const obj of sourceDb.tables) {
|
||||||
|
const paired = targetDb.tables.find(x => x.pairingId == obj.pairingId);
|
||||||
|
if (paired) {
|
||||||
|
res.push({
|
||||||
|
source: obj,
|
||||||
|
target: paired,
|
||||||
|
state: testEqualTables(obj, paired, opts, targetDb, driver) ? 'equal' : 'changed',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.push({
|
||||||
|
source: obj,
|
||||||
|
state: 'removed',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const obj of targetDb.tables) {
|
||||||
|
const paired = sourceDb.tables.find(x => x.pairingId == obj.pairingId);
|
||||||
|
if (!paired) {
|
||||||
|
res.push({
|
||||||
|
target: obj,
|
||||||
|
state: 'added',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.map(row => ({
|
||||||
|
...row,
|
||||||
|
sourceSchemaName: row?.source?.schemaName,
|
||||||
|
sourcePureName: row?.source?.pureName,
|
||||||
|
targetSchemaName: row?.target?.schemaName,
|
||||||
|
targetPureName: row?.target?.pureName,
|
||||||
|
}));
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user