mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-05-03 14:03:57 +00:00
recursive delete cascade
This commit is contained in:
@@ -300,7 +300,7 @@ function changeSetUpdateToSql(item: ChangeSetItem): Update {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function changeSetDeleteToSql(item: ChangeSetItem): Delete {
|
function changeSetDeleteToSql(item: ChangeSetItem): Delete {
|
||||||
return {
|
return {
|
||||||
from: {
|
from: {
|
||||||
name: {
|
name: {
|
||||||
|
|||||||
@@ -1,23 +1,38 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { Command, Insert, Update, Delete, UpdateField, Condition, AllowIdentityInsert } from 'dbgate-sqltree';
|
import { Command, Insert, Update, Delete, UpdateField, Condition, AllowIdentityInsert } from 'dbgate-sqltree';
|
||||||
import { NamedObjectInfo, DatabaseInfo } from 'dbgate-types';
|
import { NamedObjectInfo, DatabaseInfo, ForeignKeyInfo, TableInfo } from 'dbgate-types';
|
||||||
import { ChangeSet, extractChangeSetCondition, changeSetDeleteToSql } from './ChangeSet';
|
import { ChangeSet, ChangeSetItem, extractChangeSetCondition } from './ChangeSet';
|
||||||
|
|
||||||
export interface ChangeSetDeleteCascade {
|
export interface ChangeSetDeleteCascade {
|
||||||
title: string;
|
title: string;
|
||||||
commands: Command[];
|
commands: Command[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDeleteCascades(changeSet: ChangeSet, dbinfo: DatabaseInfo): ChangeSetDeleteCascade[] {
|
// function getDeleteScript()
|
||||||
const res: ChangeSetDeleteCascade[] = [];
|
|
||||||
const allForeignKeys = _.flatten(dbinfo.tables.map(x => x.foreignKeys));
|
function processDependencies(
|
||||||
for (const baseCmd of changeSet.deletes) {
|
changeSet: ChangeSet,
|
||||||
const table = dbinfo.tables.find(x => x.pureName == baseCmd.pureName && x.schemaName == baseCmd.schemaName);
|
result: ChangeSetDeleteCascade[],
|
||||||
if (!table.primaryKey) continue;
|
allForeignKeys: ForeignKeyInfo[],
|
||||||
|
fkPath: ForeignKeyInfo[],
|
||||||
|
table: TableInfo,
|
||||||
|
baseCmd: ChangeSetItem,
|
||||||
|
dbinfo: DatabaseInfo
|
||||||
|
) {
|
||||||
const dependencies = allForeignKeys.filter(
|
const dependencies = allForeignKeys.filter(
|
||||||
x => x.refSchemaName == table.schemaName && x.refTableName == table.pureName
|
x => x.refSchemaName == table.schemaName && x.refTableName == table.pureName
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const fk of dependencies) {
|
for (const fk of dependencies) {
|
||||||
|
if (fk.pureName == baseCmd.pureName) continue;
|
||||||
|
if (result.find(x => x.title == fk.pureName)) continue;
|
||||||
|
|
||||||
|
const depTable = dbinfo.tables.find(x => x.pureName == fk.pureName && x.schemaName == fk.schemaName);
|
||||||
|
const subFkPath = [...fkPath, fk];
|
||||||
|
if (depTable) {
|
||||||
|
processDependencies(changeSet, result, allForeignKeys, subFkPath, depTable, baseCmd, dbinfo);
|
||||||
|
}
|
||||||
|
|
||||||
const refCmd: Delete = {
|
const refCmd: Delete = {
|
||||||
commandType: 'delete',
|
commandType: 'delete',
|
||||||
from: {
|
from: {
|
||||||
@@ -35,36 +50,34 @@ export function getDeleteCascades(changeSet: ChangeSet, dbinfo: DatabaseInfo): C
|
|||||||
pureName: fk.pureName,
|
pureName: fk.pureName,
|
||||||
schemaName: fk.schemaName,
|
schemaName: fk.schemaName,
|
||||||
},
|
},
|
||||||
alias: 't1',
|
alias: 't0',
|
||||||
relations: [
|
relations: subFkPath.map((fkItem, fkIndex) => ({
|
||||||
{
|
|
||||||
joinType: 'INNER JOIN',
|
joinType: 'INNER JOIN',
|
||||||
alias: 't2',
|
alias: `t${fkIndex + 1}`,
|
||||||
name: {
|
name: {
|
||||||
pureName: fk.refTableName,
|
pureName: fkItem.refTableName,
|
||||||
schemaName: fk.refSchemaName,
|
schemaName: fkItem.refSchemaName,
|
||||||
},
|
},
|
||||||
conditions: fk.columns.map(column => ({
|
conditions: fkItem.columns.map(column => ({
|
||||||
conditionType: 'binary',
|
conditionType: 'binary',
|
||||||
operator: '=',
|
operator: '=',
|
||||||
left: {
|
left: {
|
||||||
exprType: 'column',
|
exprType: 'column',
|
||||||
columnName: column.columnName,
|
columnName: column.columnName,
|
||||||
source: { alias: 't1' },
|
source: { alias: `t${fkIndex}` },
|
||||||
},
|
},
|
||||||
right: {
|
right: {
|
||||||
exprType: 'column',
|
exprType: 'column',
|
||||||
columnName: column.refColumnName,
|
columnName: column.refColumnName,
|
||||||
source: { alias: 't2' },
|
source: { alias: `t${fkIndex + 1}` },
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
},
|
})),
|
||||||
],
|
|
||||||
},
|
},
|
||||||
where: {
|
where: {
|
||||||
conditionType: 'and',
|
conditionType: 'and',
|
||||||
conditions: [
|
conditions: [
|
||||||
extractChangeSetCondition(baseCmd, 't2'),
|
extractChangeSetCondition(baseCmd, `t${subFkPath.length}`),
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
...table.primaryKey.columns.map(column => ({
|
...table.primaryKey.columns.map(column => ({
|
||||||
conditionType: 'binary',
|
conditionType: 'binary',
|
||||||
@@ -72,16 +85,13 @@ export function getDeleteCascades(changeSet: ChangeSet, dbinfo: DatabaseInfo): C
|
|||||||
left: {
|
left: {
|
||||||
exprType: 'column',
|
exprType: 'column',
|
||||||
columnName: column.columnName,
|
columnName: column.columnName,
|
||||||
source: { alias: 't1' },
|
source: { alias: 't0' },
|
||||||
},
|
},
|
||||||
right: {
|
right: {
|
||||||
exprType: 'column',
|
exprType: 'column',
|
||||||
columnName: column.columnName,
|
columnName: column.columnName,
|
||||||
source: {
|
source: {
|
||||||
name: {
|
name: fk,
|
||||||
pureName: fk.refTableName,
|
|
||||||
schemaName: fk.refSchemaName,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
@@ -90,28 +100,37 @@ export function getDeleteCascades(changeSet: ChangeSet, dbinfo: DatabaseInfo): C
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let resItem = res.find(x => x.title == fk.pureName);
|
let resItem = result.find(x => x.title == fk.pureName);
|
||||||
if (!resItem) {
|
if (!resItem) {
|
||||||
resItem = {
|
resItem = {
|
||||||
title: fk.pureName,
|
title: fk.pureName,
|
||||||
commands: [],
|
commands: [],
|
||||||
};
|
};
|
||||||
res.push(resItem);
|
result.push(resItem);
|
||||||
}
|
}
|
||||||
resItem.commands.push(refCmd);
|
resItem.commands.push(refCmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
let resItem = res.find(x => x.title == baseCmd.pureName);
|
|
||||||
if (!resItem) {
|
|
||||||
resItem = {
|
|
||||||
title: baseCmd.pureName,
|
|
||||||
commands: [],
|
|
||||||
};
|
|
||||||
res.push(resItem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resItem.commands.push(changeSetDeleteToSql(baseCmd));
|
export function getDeleteCascades(changeSet: ChangeSet, dbinfo: DatabaseInfo): ChangeSetDeleteCascade[] {
|
||||||
|
const result: 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);
|
||||||
|
if (!table.primaryKey) continue;
|
||||||
|
|
||||||
|
processDependencies(changeSet, result, allForeignKeys, [], table, baseCmd, dbinfo);
|
||||||
|
|
||||||
|
// let resItem = result.find(x => x.title == baseCmd.pureName);
|
||||||
|
// if (!resItem) {
|
||||||
|
// resItem = {
|
||||||
|
// title: baseCmd.pureName,
|
||||||
|
// commands: [],
|
||||||
|
// };
|
||||||
|
// result.push(resItem);
|
||||||
|
// }
|
||||||
|
// resItem.commands.push(changeSetDeleteToSql(baseCmd));
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,10 +32,12 @@
|
|||||||
<SqlEditor
|
<SqlEditor
|
||||||
{engine}
|
{engine}
|
||||||
value={values.deleteReferencesCascade
|
value={values.deleteReferencesCascade
|
||||||
? deleteCascadesScripts
|
? [
|
||||||
|
...deleteCascadesScripts
|
||||||
.filter(({ script, title }) => values[`deleteReferences_${title}`] !== false)
|
.filter(({ script, title }) => values[`deleteReferences_${title}`] !== false)
|
||||||
.map(({ script, title }) => script)
|
.map(({ script, title }) => script),
|
||||||
.join('\n')
|
sql,
|
||||||
|
].join('\n')
|
||||||
: sql}
|
: sql}
|
||||||
readOnly
|
readOnly
|
||||||
/>
|
/>
|
||||||
@@ -43,23 +45,32 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if !_.isEmpty(deleteCascadesScripts)}
|
{#if !_.isEmpty(deleteCascadesScripts)}
|
||||||
|
<div class="mt-2">
|
||||||
<FormCheckboxField
|
<FormCheckboxField
|
||||||
templateProps={{ noMargin: true }}
|
templateProps={{ noMargin: true }}
|
||||||
label="Delete references CASCADE"
|
label="Delete references CASCADE"
|
||||||
name="deleteReferencesCascade"
|
name="deleteReferencesCascade"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<FormValues let:values>
|
<FormValues let:values>
|
||||||
{#if values.deleteReferencesCascade}
|
{#if values.deleteReferencesCascade}
|
||||||
|
<!-- <div class="form-margin flex">
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
<div class="form-margin flex">
|
||||||
{#each _.sortBy(deleteCascadesScripts, 'title') as deleteTable}
|
{#each _.sortBy(deleteCascadesScripts, 'title') as deleteTable}
|
||||||
|
<div class="mr-1">
|
||||||
<FormCheckboxField
|
<FormCheckboxField
|
||||||
defaultValue={true}
|
defaultValue={true}
|
||||||
templateProps={{ noMargin: true }}
|
templateProps={{ noMargin: true }}
|
||||||
label={deleteTable.title}
|
label={deleteTable.title}
|
||||||
name={`deleteReferences_${deleteTable.title}`}
|
name={`deleteReferences_${deleteTable.title}`}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</FormValues>
|
</FormValues>
|
||||||
|
|
||||||
@@ -86,10 +97,12 @@
|
|||||||
closeCurrentModal();
|
closeCurrentModal();
|
||||||
onConfirm(
|
onConfirm(
|
||||||
e.detail.deleteReferencesCascade
|
e.detail.deleteReferencesCascade
|
||||||
? deleteCascadesScripts
|
? [
|
||||||
|
...deleteCascadesScripts
|
||||||
.filter(({ script, title }) => e.detail[`deleteReferences_${title}`] !== false)
|
.filter(({ script, title }) => e.detail[`deleteReferences_${title}`] !== false)
|
||||||
.map(({ script, title }) => script)
|
.map(({ script, title }) => script),
|
||||||
.join('\n')
|
sql,
|
||||||
|
].join('\n')
|
||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
|||||||
Reference in New Issue
Block a user