mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-05-01 12:03:58 +00:00
delete cascade refactor WIP
This commit is contained in:
@@ -11,11 +11,6 @@ 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[];
|
||||||
@@ -222,7 +217,7 @@ function extractFields(item: ChangeSetItem, allowNulls = true): UpdateField[] {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertToSql(
|
function changeSetInsertToSql(
|
||||||
item: ChangeSetItem,
|
item: ChangeSetItem,
|
||||||
dbinfo: DatabaseInfo = null
|
dbinfo: DatabaseInfo = null
|
||||||
): [AllowIdentityInsert, Insert, AllowIdentityInsert] {
|
): [AllowIdentityInsert, Insert, AllowIdentityInsert] {
|
||||||
@@ -266,7 +261,7 @@ function insertToSql(
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractCondition(item: ChangeSetItem, alias?: string): Condition {
|
export function extractChangeSetCondition(item: ChangeSetItem, alias?: string): Condition {
|
||||||
return {
|
return {
|
||||||
conditionType: 'and',
|
conditionType: 'and',
|
||||||
conditions: _.keys(item.condition).map(columnName => ({
|
conditions: _.keys(item.condition).map(columnName => ({
|
||||||
@@ -291,7 +286,7 @@ function extractCondition(item: ChangeSetItem, alias?: string): Condition {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateToSql(item: ChangeSetItem): Update {
|
function changeSetUpdateToSql(item: ChangeSetItem): Update {
|
||||||
return {
|
return {
|
||||||
from: {
|
from: {
|
||||||
name: {
|
name: {
|
||||||
@@ -301,11 +296,11 @@ function updateToSql(item: ChangeSetItem): Update {
|
|||||||
},
|
},
|
||||||
commandType: 'update',
|
commandType: 'update',
|
||||||
fields: extractFields(item),
|
fields: extractFields(item),
|
||||||
where: extractCondition(item),
|
where: extractChangeSetCondition(item),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteToSql(item: ChangeSetItem): Delete {
|
export function changeSetDeleteToSql(item: ChangeSetItem): Delete {
|
||||||
return {
|
return {
|
||||||
from: {
|
from: {
|
||||||
name: {
|
name: {
|
||||||
@@ -314,128 +309,20 @@ function deleteToSql(item: ChangeSetItem): Delete {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
commandType: 'delete',
|
commandType: 'delete',
|
||||||
where: extractCondition(item),
|
where: extractChangeSetCondition(item),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function changeSetToSql(changeSet: ChangeSet, dbinfo: DatabaseInfo): Command[] {
|
export function changeSetToSql(changeSet: ChangeSet, dbinfo: DatabaseInfo): Command[] {
|
||||||
return _.compact(
|
return _.compact(
|
||||||
_.flatten([
|
_.flatten([
|
||||||
...(changeSet.inserts.map(item => insertToSql(item, dbinfo)) as any),
|
...(changeSet.inserts.map(item => changeSetInsertToSql(item, dbinfo)) as any),
|
||||||
...changeSet.updates.map(updateToSql),
|
...changeSet.updates.map(changeSetUpdateToSql),
|
||||||
...changeSet.deletes.map(deleteToSql),
|
...changeSet.deletes.map(changeSetDeleteToSql),
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
if (!table.primaryKey) continue;
|
|
||||||
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
|
|
||||||
...table.primaryKey.columns.map(column => ({
|
|
||||||
conditionType: 'binary',
|
|
||||||
operator: '=',
|
|
||||||
left: {
|
|
||||||
exprType: 'column',
|
|
||||||
columnName: column.columnName,
|
|
||||||
source: { alias: 't1' },
|
|
||||||
},
|
|
||||||
right: {
|
|
||||||
exprType: 'column',
|
|
||||||
columnName: column.columnName,
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
let resItem = res.find(x => x.title == baseCmd.pureName);
|
|
||||||
if (!resItem) {
|
|
||||||
resItem = {
|
|
||||||
title: baseCmd.pureName,
|
|
||||||
commands: [],
|
|
||||||
};
|
|
||||||
res.push(resItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
resItem.commands.push(deleteToSql(baseCmd));
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
117
packages/datalib/src/deleteCascade.ts
Normal file
117
packages/datalib/src/deleteCascade.ts
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
import _ from 'lodash';
|
||||||
|
import { Command, Insert, Update, Delete, UpdateField, Condition, AllowIdentityInsert } from 'dbgate-sqltree';
|
||||||
|
import { NamedObjectInfo, DatabaseInfo } from 'dbgate-types';
|
||||||
|
import { ChangeSet, extractChangeSetCondition, changeSetDeleteToSql } from './ChangeSet';
|
||||||
|
|
||||||
|
export interface ChangeSetDeleteCascade {
|
||||||
|
title: string;
|
||||||
|
commands: Command[];
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (!table.primaryKey) continue;
|
||||||
|
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: [
|
||||||
|
extractChangeSetCondition(baseCmd, 't2'),
|
||||||
|
// @ts-ignore
|
||||||
|
...table.primaryKey.columns.map(column => ({
|
||||||
|
conditionType: 'binary',
|
||||||
|
operator: '=',
|
||||||
|
left: {
|
||||||
|
exprType: 'column',
|
||||||
|
columnName: column.columnName,
|
||||||
|
source: { alias: 't1' },
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
exprType: 'column',
|
||||||
|
columnName: column.columnName,
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
let resItem = res.find(x => x.title == baseCmd.pureName);
|
||||||
|
if (!resItem) {
|
||||||
|
resItem = {
|
||||||
|
title: baseCmd.pureName,
|
||||||
|
commands: [],
|
||||||
|
};
|
||||||
|
res.push(resItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
resItem.commands.push(changeSetDeleteToSql(baseCmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
@@ -11,3 +11,4 @@ export * from './runMacro';
|
|||||||
export * from './FormViewDisplay';
|
export * from './FormViewDisplay';
|
||||||
export * from './TableFormViewDisplay';
|
export * from './TableFormViewDisplay';
|
||||||
export * from './CollectionGridDisplay';
|
export * from './CollectionGridDisplay';
|
||||||
|
export * from './deleteCascade';
|
||||||
|
|||||||
Reference in New Issue
Block a user