diff --git a/packages/datalib/src/ChangeSet.ts b/packages/datalib/src/ChangeSet.ts index 97c7aef12..4b6a2ddbe 100644 --- a/packages/datalib/src/ChangeSet.ts +++ b/packages/datalib/src/ChangeSet.ts @@ -11,6 +11,11 @@ export interface ChangeSetItem { fields?: { [column: string]: string }; } +export interface ChangeSetDeleteCascade { + title: string; + commands: Command[]; +} + export interface ChangeSet { inserts: 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; let [fieldName, existingItem] = findExistingChangeSetItem(changeSet, definition); if (fieldName == 'deletes') { @@ -257,7 +266,7 @@ function insertToSql( ]; } -function extractCondition(item: ChangeSetItem): Condition { +function extractCondition(item: ChangeSetItem, alias?: string): Condition { return { conditionType: 'and', conditions: _.keys(item.condition).map(columnName => ({ @@ -271,6 +280,7 @@ function extractCondition(item: ChangeSetItem): Condition { pureName: item.pureName, schemaName: item.schemaName, }, + alias, }, }, 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 { // console.log('definition', definition); const [field, item] = findExistingChangeSetItem(changeSet, definition); diff --git a/packages/web/src/modals/ConfirmSqlModal.svelte b/packages/web/src/modals/ConfirmSqlModal.svelte index 6b3a0c20a..fcdbbddbc 100644 --- a/packages/web/src/modals/ConfirmSqlModal.svelte +++ b/packages/web/src/modals/ConfirmSqlModal.svelte @@ -1,5 +1,6 @@