Skip to content

Commit ec17bd5

Browse files
committed
feat: implement cascading deletion logic in AdminForthRestAPI
1 parent 81fce83 commit ec17bd5

File tree

2 files changed

+44
-24
lines changed

2 files changed

+44
-24
lines changed

adminforth/modules/configValidator.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import {
3030
import AdminForth from "adminforth";
3131
import { AdminForthConfigMenuItem } from "adminforth";
3232
import { afLogger } from "./logger.js";
33-
33+
import AdminForthRestAPI from './restApi.js';
3434

3535
export default class ConfigValidator implements IConfigValidator {
3636

@@ -282,8 +282,9 @@ export default class ConfigValidator implements IConfigValidator {
282282
return;
283283
}
284284

285-
await connector.deleteRecord({ resource: res as AdminForthResource, recordId });
286-
// call afterDelete hook
285+
const restApi = new AdminForthRestAPI (this.adminforth)
286+
restApi.deleteWithCascade(res as AdminForthResource, recordId, { adminUser, response, body: undefined, query: undefined, headers: undefined, cookies: undefined, requestUrl: undefined});
287+
287288
await Promise.all(
288289
(res.hooks.delete.afterSave).map(
289290
async (hook) => {

adminforth/modules/restApi.ts

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ export async function interpretResource(
126126
export default class AdminForthRestAPI implements IAdminForthRestAPI {
127127

128128
adminforth: IAdminForth;
129+
static deleteWithCascade: any;
129130

130131
constructor(adminforth: IAdminForth) {
131132
this.adminforth = adminforth;
@@ -152,6 +153,44 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {
152153
}
153154
}
154155
}
156+
async deleteWithCascade(resource: AdminForthResource, primaryKey: any, context: {body: any, adminUser: any, query: any, headers: any, cookies: any, requestUrl: any, response: any}) {
157+
const { adminUser, response } = context;
158+
159+
const record = await this.adminforth.connectors[resource.dataSource].getRecordByPrimaryKey(resource, primaryKey);
160+
161+
if (!record) return;
162+
163+
const childResources = this.adminforth.config.resources.filter(r =>r.columns.some(c => c.foreignResource?.resourceId === resource.resourceId));
164+
165+
for (const childRes of childResources) {
166+
const foreignColumn = childRes.columns.find(c => c.foreignResource?.resourceId === resource.resourceId);
167+
168+
if (!foreignColumn?.foreignResource?.onDelete) continue;
169+
170+
const strategy = foreignColumn.foreignResource.onDelete;
171+
172+
const childRecords = await this.adminforth.resource(childRes.resourceId).list(Filters.EQ(foreignColumn.name, primaryKey));
173+
174+
console.log("childRecords", childRecords)
175+
176+
const childPk = childRes.columns.find(c => c.primaryKey)?.name;
177+
if (!childPk) continue;
178+
179+
if (strategy === 'cascade') {
180+
for (const childRecord of childRecords) {
181+
await this.deleteWithCascade(childRes, childRecord[childPk], context);
182+
}
183+
}
184+
185+
if (strategy === 'setNull') {
186+
for (const childRecord of childRecords) {
187+
await this.adminforth.resource(childRes.resourceId).update(childRecord[childPk], {[foreignColumn.name]: null});
188+
}
189+
}
190+
}
191+
192+
await this.adminforth.deleteResourceRecord({resource, record, adminUser, recordId: primaryKey, response, extra: context});
193+
}
155194

156195
registerEndpoints(server: IHttpServer) {
157196
server.endpoint({
@@ -1481,27 +1520,7 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {
14811520
return { error };
14821521
}
14831522

1484-
const childResources = this.adminforth.config.resources.filter(r => r.columns.some(c => c.foreignResource?.resourceId === resource.resourceId));
1485-
if (childResources.length){
1486-
for (const childRes of childResources) {
1487-
const foreignResourceColumn = childRes.columns.find(c => c.foreignResource?.resourceId === resource.resourceId);
1488-
if (!foreignResourceColumn.foreignResource.onDelete) continue;
1489-
const onDeleteStrategy = foreignResourceColumn.foreignResource.onDelete;
1490-
const childRecords = await this.adminforth.resource(childRes.resourceId).list(Filters.EQ(foreignResourceColumn.name, body['primaryKey']))
1491-
const childPkColumn = childRes.columns.find(col => col.primaryKey);
1492-
if (!childPkColumn) continue;
1493-
const childPkFieldName = childPkColumn.name;
1494-
if (onDeleteStrategy === 'cascade') {
1495-
for (const childRecord of childRecords) {
1496-
await this.adminforth.resource(childRes.resourceId).delete(childRecord[childPkFieldName]);
1497-
}
1498-
} else if (onDeleteStrategy === 'setNull') {
1499-
for (const childRecord of childRecords) {
1500-
await this.adminforth.resource(childRes.resourceId).update(childRecord[childPkFieldName], {[foreignResourceColumn.name]: null});
1501-
}
1502-
}
1503-
}
1504-
}
1523+
await this.deleteWithCascade(resource, body.primaryKey, {body, adminUser, query, headers, cookies, requestUrl, response});
15051524

15061525
const { error: deleteError } = await this.adminforth.deleteResourceRecord({
15071526
resource, record, adminUser, recordId: body['primaryKey'], response,

0 commit comments

Comments
 (0)