Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion apps/nestjs-backend/src/features/calculation/link.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1197,6 +1197,14 @@ export class LinkService {
}
}

// Lock affected foreign records to prevent concurrent modifications
const affectedForeignIds = uniq([
...toDelete.map(([, foreignId]) => foreignId),
...toAdd.map(([, foreignId]) => foreignId),
...toDeleteAndReinsert.flatMap(([, newKeys]) => newKeys),
]);
await this.lockForeignRecords(field.options.foreignTableId, affectedForeignIds);

// Handle order changes: delete all existing records for affected recordIds and re-insert
if (toDeleteAndReinsert.length) {
const recordIdsToDeleteAll = toDeleteAndReinsert.map(([recordId]) => recordId);
Expand Down Expand Up @@ -1429,10 +1437,20 @@ export class LinkService {
const { selfKeyName, foreignKeyName, fkHostTableName, isOneWay } = field.options;

if (isOneWay) {
this.saveForeignKeyForManyMany(field, fkMap);
await this.saveForeignKeyForManyMany(field, fkMap);
return;
}

// Lock affected foreign records to prevent concurrent modifications
const allForeignIds: string[] = [];
for (const recordId in fkMap) {
const fkItem = fkMap[recordId];
const oldKey = (fkItem.oldKey || []) as string[];
const newKey = (fkItem.newKey || []) as string[];
allForeignIds.push(...oldKey, ...newKey);
}
await this.lockForeignRecords(field.options.foreignTableId, uniq(allForeignIds));

// Process each record individually to maintain order
for (const recordId in fkMap) {
const fkItem = fkMap[recordId];
Expand Down Expand Up @@ -1589,6 +1607,12 @@ export class LinkService {
newKey && toAdd.push([recordId, newKey]);
}

// Lock affected foreign records to prevent concurrent modifications
const affectedForeignIds = uniq(
toDelete.map(([, foreignId]) => foreignId).concat(toAdd.map(([, foreignId]) => foreignId))
);
await this.lockForeignRecords(field.options.foreignTableId, affectedForeignIds);

if (toDelete.length) {
const updateFields: Record<string, null> = { [selfKeyName]: null };
// Also clear order column if field has order column
Expand Down
Loading