mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-26 23:46:23 +00:00
delete cascade WIP
This commit is contained in:
@@ -11,6 +11,11 @@ export interface ChangeSetItem {
|
|||||||
fields?: { [column: string]: string };
|
fields?: { [column: string]: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ChangeSetDeleteCascade {
|
||||||
|
title: string;
|
||||||
|
commands: Command[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface ChangeSet {
|
export interface ChangeSet {
|
||||||
inserts: ChangeSetItem[];
|
inserts: ChangeSetItem[];
|
||||||
updates: ChangeSetItem[];
|
updates: ChangeSetItem[];
|
||||||
@@ -118,7 +123,11 @@ export function setChangeSetValue(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setChangeSetRowData(changeSet: ChangeSet, definition: ChangeSetRowDefinition, document: any): ChangeSet {
|
export function setChangeSetRowData(
|
||||||
|
changeSet: ChangeSet,
|
||||||
|
definition: ChangeSetRowDefinition,
|
||||||
|
document: any
|
||||||
|
): ChangeSet {
|
||||||
if (!changeSet || !definition) return changeSet;
|
if (!changeSet || !definition) return changeSet;
|
||||||
let [fieldName, existingItem] = findExistingChangeSetItem(changeSet, definition);
|
let [fieldName, existingItem] = findExistingChangeSetItem(changeSet, definition);
|
||||||
if (fieldName == 'deletes') {
|
if (fieldName == 'deletes') {
|
||||||
@@ -257,7 +266,7 @@ function insertToSql(
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractCondition(item: ChangeSetItem): Condition {
|
function extractCondition(item: ChangeSetItem, alias?: string): Condition {
|
||||||
return {
|
return {
|
||||||
conditionType: 'and',
|
conditionType: 'and',
|
||||||
conditions: _.keys(item.condition).map(columnName => ({
|
conditions: _.keys(item.condition).map(columnName => ({
|
||||||
@@ -271,6 +280,7 @@ function extractCondition(item: ChangeSetItem): Condition {
|
|||||||
pureName: item.pureName,
|
pureName: item.pureName,
|
||||||
schemaName: item.schemaName,
|
schemaName: item.schemaName,
|
||||||
},
|
},
|
||||||
|
alias,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
right: {
|
right: {
|
||||||
@@ -318,6 +328,102 @@ export function changeSetToSql(changeSet: ChangeSet, dbinfo: DatabaseInfo): Comm
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getDeleteCascades(changeSet: ChangeSet, dbinfo: DatabaseInfo): ChangeSetDeleteCascade[] {
|
||||||
|
const res: ChangeSetDeleteCascade[] = [];
|
||||||
|
const allForeignKeys = _.flatten(dbinfo.tables.map(x => x.foreignKeys));
|
||||||
|
for (const baseCmd of changeSet.deletes) {
|
||||||
|
const table = dbinfo.tables.find(x => x.pureName == baseCmd.pureName && x.schemaName == baseCmd.schemaName);
|
||||||
|
const dependencies = allForeignKeys.filter(
|
||||||
|
x => x.refSchemaName == table.schemaName && x.refTableName == table.pureName
|
||||||
|
);
|
||||||
|
for (const fk of dependencies) {
|
||||||
|
const refCmd: Delete = {
|
||||||
|
commandType: 'delete',
|
||||||
|
from: {
|
||||||
|
name: {
|
||||||
|
pureName: fk.pureName,
|
||||||
|
schemaName: fk.schemaName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
conditionType: 'exists',
|
||||||
|
subQuery: {
|
||||||
|
commandType: 'select',
|
||||||
|
from: {
|
||||||
|
name: {
|
||||||
|
pureName: fk.pureName,
|
||||||
|
schemaName: fk.schemaName,
|
||||||
|
},
|
||||||
|
alias: 't1',
|
||||||
|
relations: [
|
||||||
|
{
|
||||||
|
joinType: 'INNER JOIN',
|
||||||
|
alias: 't2',
|
||||||
|
name: {
|
||||||
|
pureName: fk.refTableName,
|
||||||
|
schemaName: fk.refSchemaName,
|
||||||
|
},
|
||||||
|
conditions: fk.columns.map(column => ({
|
||||||
|
conditionType: 'binary',
|
||||||
|
operator: '=',
|
||||||
|
left: {
|
||||||
|
exprType: 'column',
|
||||||
|
columnName: column.columnName,
|
||||||
|
source: { alias: 't1' },
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
exprType: 'column',
|
||||||
|
columnName: column.refColumnName,
|
||||||
|
source: { alias: 't2' },
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
where: {
|
||||||
|
conditionType: 'and',
|
||||||
|
conditions: [
|
||||||
|
extractCondition(baseCmd, 't2'),
|
||||||
|
// @ts-ignore
|
||||||
|
...fk.columns.map(column => ({
|
||||||
|
conditionType: 'binary',
|
||||||
|
operator: '=',
|
||||||
|
left: {
|
||||||
|
exprType: 'column',
|
||||||
|
columnName: column.columnName,
|
||||||
|
source: { alias: 't1' },
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
exprType: 'column',
|
||||||
|
columnName: column.refColumnName,
|
||||||
|
source: {
|
||||||
|
name: {
|
||||||
|
pureName: fk.refTableName,
|
||||||
|
schemaName: fk.refSchemaName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let resItem = res.find(x => x.title == fk.pureName);
|
||||||
|
if (!resItem) {
|
||||||
|
resItem = {
|
||||||
|
title: fk.pureName,
|
||||||
|
commands: [],
|
||||||
|
};
|
||||||
|
res.push(resItem);
|
||||||
|
}
|
||||||
|
resItem.commands.push(refCmd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
export function revertChangeSetRowChanges(changeSet: ChangeSet, definition: ChangeSetRowDefinition): ChangeSet {
|
export function revertChangeSetRowChanges(changeSet: ChangeSet, definition: ChangeSetRowDefinition): ChangeSet {
|
||||||
// console.log('definition', definition);
|
// console.log('definition', definition);
|
||||||
const [field, item] = findExistingChangeSetItem(changeSet, definition);
|
const [field, item] = findExistingChangeSetItem(changeSet, definition);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import _ from 'lodash';
|
import { keys } from 'localforage';
|
||||||
|
import _, { isEmpty } from 'lodash';
|
||||||
import FormStyledButton from '../elements/FormStyledButton.svelte';
|
import FormStyledButton from '../elements/FormStyledButton.svelte';
|
||||||
import FormCheckboxField from '../forms/FormCheckboxField.svelte';
|
import FormCheckboxField from '../forms/FormCheckboxField.svelte';
|
||||||
import FormProvider from '../forms/FormProvider.svelte';
|
import FormProvider from '../forms/FormProvider.svelte';
|
||||||
@@ -15,6 +16,7 @@
|
|||||||
export let onConfirm;
|
export let onConfirm;
|
||||||
export let engine;
|
export let engine;
|
||||||
export let recreates;
|
export let recreates;
|
||||||
|
export let deleteCascadesScripts;
|
||||||
|
|
||||||
$: isRecreated = _.sum(_.values(recreates || {})) > 0;
|
$: isRecreated = _.sum(_.values(recreates || {})) > 0;
|
||||||
|
|
||||||
@@ -26,9 +28,41 @@
|
|||||||
<div slot="header">Save changes</div>
|
<div slot="header">Save changes</div>
|
||||||
|
|
||||||
<div class="editor">
|
<div class="editor">
|
||||||
<SqlEditor {engine} value={sql} readOnly />
|
<FormValues let:values>
|
||||||
|
<SqlEditor
|
||||||
|
{engine}
|
||||||
|
value={values.deleteReferencesCascade
|
||||||
|
? deleteCascadesScripts
|
||||||
|
.filter(({ script, title }) => values[`deleteReferences_${title}`] !== false)
|
||||||
|
.map(({ script, title }) => script)
|
||||||
|
.join('\n')
|
||||||
|
: sql}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
</FormValues>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{#if !_.isEmpty(deleteCascadesScripts)}
|
||||||
|
<FormCheckboxField
|
||||||
|
templateProps={{ noMargin: true }}
|
||||||
|
label="Delete references CASCADE"
|
||||||
|
name="deleteReferencesCascade"
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<FormValues let:values>
|
||||||
|
{#if values.deleteReferencesCascade}
|
||||||
|
{#each _.sortBy(deleteCascadesScripts, 'title') as deleteTable}
|
||||||
|
<FormCheckboxField
|
||||||
|
defaultValue={true}
|
||||||
|
templateProps={{ noMargin: true }}
|
||||||
|
label={deleteTable.title}
|
||||||
|
name={`deleteReferences_${deleteTable.title}`}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
|
</FormValues>
|
||||||
|
|
||||||
{#if isRecreated}
|
{#if isRecreated}
|
||||||
<div class="form-margin">
|
<div class="form-margin">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
|
|
||||||
export const matchingProps = ['conid', 'database', 'schemaName', 'pureName'];
|
export const matchingProps = ['conid', 'database', 'schemaName', 'pureName'];
|
||||||
export const allowAddToFavorites = props => true;
|
export const allowAddToFavorites = props => true;
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import _ from 'lodash';
|
||||||
import App from '../App.svelte';
|
import App from '../App.svelte';
|
||||||
import TableDataGrid from '../datagrid/TableDataGrid.svelte';
|
import TableDataGrid from '../datagrid/TableDataGrid.svelte';
|
||||||
import useGridConfig from '../utility/useGridConfig';
|
import useGridConfig from '../utility/useGridConfig';
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
createChangeSet,
|
createChangeSet,
|
||||||
createGridCache,
|
createGridCache,
|
||||||
createGridConfig,
|
createGridConfig,
|
||||||
|
getDeleteCascades,
|
||||||
TableFormViewDisplay,
|
TableFormViewDisplay,
|
||||||
TableGridDisplay,
|
TableGridDisplay,
|
||||||
} from 'dbgate-datalib';
|
} from 'dbgate-datalib';
|
||||||
@@ -87,11 +88,18 @@
|
|||||||
export function save() {
|
export function save() {
|
||||||
const driver = findEngineDriver($connection, $extensions);
|
const driver = findEngineDriver($connection, $extensions);
|
||||||
const script = changeSetToSql($changeSetStore?.value, $dbinfo);
|
const script = changeSetToSql($changeSetStore?.value, $dbinfo);
|
||||||
|
const deleteCascades = getDeleteCascades($changeSetStore?.value, $dbinfo);
|
||||||
const sql = scriptToSql(driver, script);
|
const sql = scriptToSql(driver, script);
|
||||||
|
const deleteCascadesScripts = _.map(deleteCascades, ({ title, commands }) => ({
|
||||||
|
title,
|
||||||
|
script: scriptToSql(driver, commands),
|
||||||
|
}));
|
||||||
|
console.log('deleteCascadesScripts', deleteCascadesScripts);
|
||||||
showModal(ConfirmSqlModal, {
|
showModal(ConfirmSqlModal, {
|
||||||
sql,
|
sql,
|
||||||
onConfirm: () => handleConfirmSql(sql),
|
onConfirm: () => handleConfirmSql(sql),
|
||||||
engine: driver.engine,
|
engine: driver.engine,
|
||||||
|
deleteCascadesScripts,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +113,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
registerMenu({ command: 'tableData.save', tag: 'save' });
|
registerMenu({ command: 'tableData.save', tag: 'save' });
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<TableDataGrid
|
<TableDataGrid
|
||||||
|
|||||||
Reference in New Issue
Block a user