Fix concurrent page layout edition bug (#15740)
This PR fixes a bug which could happen if two people were editing a page layout at the same time. If one person deletes a widget or a tab and saves first, and the second person saves after but doesn't delete this widget or tab, an error is raised. This is because, in the backend, a diff is computed to know which tab or widget to create, update or delete. But the logic was maid without considering soft deletion. So, when the second person saves, the diff tries to create the widget or tab which had been soft deleted by the first use. Since they have the same id, a duplicate primary key error is raised. Now we always consider that the last user to save has the truth. So we restore the tab/widget and update it.
This commit is contained in:
@@ -4,6 +4,7 @@ import deepEqual from 'deep-equal';
|
||||
type Diff<T extends { id: string }> = {
|
||||
toCreate: T[];
|
||||
toUpdate: T[];
|
||||
toRestoreAndUpdate: T[];
|
||||
idsToDelete: string[];
|
||||
};
|
||||
|
||||
@@ -29,7 +30,7 @@ type ComputeDiffBetweenObjectsParams<
|
||||
};
|
||||
|
||||
export const computeDiffBetweenObjects = <
|
||||
T extends { id: string },
|
||||
T extends { id: string; deletedAt: Date | null },
|
||||
K extends { id: string },
|
||||
>({
|
||||
existingObjects,
|
||||
@@ -38,6 +39,7 @@ export const computeDiffBetweenObjects = <
|
||||
}: ComputeDiffBetweenObjectsParams<T, K>): Diff<K> => {
|
||||
const toCreate: K[] = [];
|
||||
const toUpdate: K[] = [];
|
||||
const toRestoreAndUpdate: K[] = [];
|
||||
|
||||
const existingEntitiesMap = new Map(
|
||||
existingObjects.map((entity) => [entity.id, entity]),
|
||||
@@ -50,18 +52,22 @@ export const computeDiffBetweenObjects = <
|
||||
const existingEntity = existingEntitiesMap.get(receivedObject.id);
|
||||
|
||||
if (isDefined(existingEntity)) {
|
||||
const comparableExistingEntity = extractProperties(
|
||||
existingEntity,
|
||||
propertiesToCompare,
|
||||
);
|
||||
if (isDefined(existingEntity.deletedAt)) {
|
||||
toRestoreAndUpdate.push(receivedObject);
|
||||
} else {
|
||||
const comparableExistingEntity = extractProperties(
|
||||
existingEntity,
|
||||
propertiesToCompare,
|
||||
);
|
||||
|
||||
const comparableReceivedEntity = extractProperties(
|
||||
receivedObject,
|
||||
propertiesToCompare,
|
||||
);
|
||||
const comparableReceivedEntity = extractProperties(
|
||||
receivedObject,
|
||||
propertiesToCompare,
|
||||
);
|
||||
|
||||
if (!deepEqual(comparableExistingEntity, comparableReceivedEntity)) {
|
||||
toUpdate.push(receivedObject);
|
||||
if (!deepEqual(comparableExistingEntity, comparableReceivedEntity)) {
|
||||
toUpdate.push(receivedObject);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
toCreate.push(receivedObject);
|
||||
@@ -69,12 +75,14 @@ export const computeDiffBetweenObjects = <
|
||||
}
|
||||
|
||||
const idsToDelete = existingObjects
|
||||
.filter((existingEntity) => !isDefined(existingEntity.deletedAt))
|
||||
.filter((existingEntity) => !receivedEntitiesMap.has(existingEntity.id))
|
||||
.map((entity) => entity.id);
|
||||
|
||||
return {
|
||||
toCreate,
|
||||
toUpdate,
|
||||
toRestoreAndUpdate,
|
||||
idsToDelete,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user