twenty / packages /twenty-shared /src /utils /compute-diff-between-objects.ts
Jules
Initial clean CRM deployment with prebuilt assets
d9494a5
Raw
History Blame Contribute Delete
2.31 kB
import { isDefined } from '@/utils/validation';
import { fastDeepEqual } from './json/fast-deep-equal';
type Diff<T extends { id: string }> = {
toCreate: T[];
toUpdate: T[];
toRestoreAndUpdate: T[];
idsToRemove: string[];
};
const extractProperties = <T extends { id: string }>(
object: T,
properties: (keyof T)[],
) => {
return properties.reduce((acc, property) => {
return {
...acc,
[property]: object[property],
};
}, {});
};
type ComputeDiffBetweenObjectsParams<
T extends { id: string },
K extends { id: string },
> = {
existingObjects: T[];
receivedObjects: K[];
propertiesToCompare: (keyof K & keyof T)[];
isEntityIncluded: (entity: NoInfer<T>) => boolean;
};
export const computeDiffBetweenObjects = <
T extends { id: string },
K extends { id: string },
>({
existingObjects,
receivedObjects,
propertiesToCompare,
isEntityIncluded,
}: ComputeDiffBetweenObjectsParams<T, K>): Diff<K> => {
const toCreate: K[] = [];
const toUpdate: K[] = [];
const toRestoreAndUpdate: K[] = [];
const existingEntitiesMap = new Map(
existingObjects.map((entity) => [entity.id, entity]),
);
const receivedEntitiesMap = new Map(
receivedObjects.map((entity) => [entity.id, entity]),
);
for (const receivedObject of receivedObjects) {
const existingEntity = existingEntitiesMap.get(receivedObject.id);
if (isDefined(existingEntity)) {
if (!isEntityIncluded(existingEntity)) {
toRestoreAndUpdate.push(receivedObject);
} else {
const comparableExistingEntity = extractProperties(
existingEntity,
propertiesToCompare,
);
const comparableReceivedEntity = extractProperties(
receivedObject,
propertiesToCompare,
);
if (
!fastDeepEqual(comparableExistingEntity, comparableReceivedEntity)
) {
toUpdate.push(receivedObject);
}
}
} else {
toCreate.push(receivedObject);
}
}
const idsToRemove = existingObjects
.filter((existingEntity) => isEntityIncluded(existingEntity))
.filter((existingEntity) => !receivedEntitiesMap.has(existingEntity.id))
.map((entity) => entity.id);
return {
toCreate,
toUpdate,
toRestoreAndUpdate,
idsToRemove,
};
};