Refactor flat entity maps to be universal oriented (#17665)

# Introduction
In preparation of the workspace agnostic builder, we're migrating
`FlatEntityMaps` to be universal identifier oriented and based
As in the builder context there're won't be any ids at all
Please also note that the FlatEntity is a UniversalFlatEntity superset

From
```ts
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';

export type FlatEntityMaps<T extends SyncableFlatEntity> = {
  byId: Partial<Record<string, T>>;
  idByUniversalIdentifier: Partial<Record<string, string>>;
  universalIdentifiersByApplicationId: Partial<Record<string, string[]>>;
};
```

To
```ts
export type FlatEntityMaps<
  T extends SyncableFlatEntity | UniversalSyncableFlatEntity,
> = {
  byUniversalIdentifier: Partial<Record<string, T>>;
  universalIdentifierById: Partial<Record<string, string>>;
  universalIdentifiersByApplicationId: Partial<Record<string, string[]>>; // this might make more sense to be migrated to universalIdentifiersByApplicationUniversalIdentifier but it's the main topic of this PR
};
```

## Low level maps tools
Had to refactor find | create | delete | replace | find-many | get-sub
tools ( through mutations and or throw equivalent )
This commit is contained in:
Paul Rastoin
2026-02-03 17:16:02 +01:00
committed by GitHub
parent 43042d55b2
commit 476bdf764c
202 changed files with 1853 additions and 909 deletions
@@ -3,8 +3,8 @@
exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect a created entity 1`] = `
{
"createdFlatEntityMaps": {
"byId": {
"field-id-1": {
"byUniversalIdentifier": {
"universal-identifier-1": {
"applicationId": "application-id-1",
"applicationUniversalIdentifier": "application-universal-identifier-1",
"calendarViewIds": [],
@@ -48,8 +48,8 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect a crea
"workspaceId": "workspace-id-1",
},
},
"idByUniversalIdentifier": {
"universal-identifier-1": "field-id-1",
"universalIdentifierById": {
"field-id-1": "universal-identifier-1",
},
"universalIdentifiersByApplicationId": {
"application-id-1": [
@@ -58,12 +58,12 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect a crea
},
},
"deletedFlatEntityMaps": {
"byId": {},
"idByUniversalIdentifier": {},
"byUniversalIdentifier": {},
"universalIdentifierById": {},
"universalIdentifiersByApplicationId": {},
},
"updatedFlatEntityMaps": {
"byId": {},
"byUniversalIdentifier": {},
},
}
`;
@@ -71,13 +71,13 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect a crea
exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect a deleted entity 1`] = `
{
"createdFlatEntityMaps": {
"byId": {},
"idByUniversalIdentifier": {},
"byUniversalIdentifier": {},
"universalIdentifierById": {},
"universalIdentifiersByApplicationId": {},
},
"deletedFlatEntityMaps": {
"byId": {
"field-id-1": {
"byUniversalIdentifier": {
"universal-identifier-1": {
"applicationId": "application-id-1",
"applicationUniversalIdentifier": "application-universal-identifier-1",
"calendarViewIds": [],
@@ -121,8 +121,8 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect a dele
"workspaceId": "workspace-id-1",
},
},
"idByUniversalIdentifier": {
"universal-identifier-1": "field-id-1",
"universalIdentifierById": {
"field-id-1": "universal-identifier-1",
},
"universalIdentifiersByApplicationId": {
"application-id-1": [
@@ -131,7 +131,7 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect a dele
},
},
"updatedFlatEntityMaps": {
"byId": {},
"byUniversalIdentifier": {},
},
}
`;
@@ -139,19 +139,19 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect a dele
exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect an updated entity 1`] = `
{
"createdFlatEntityMaps": {
"byId": {},
"idByUniversalIdentifier": {},
"byUniversalIdentifier": {},
"universalIdentifierById": {},
"universalIdentifiersByApplicationId": {},
},
"deletedFlatEntityMaps": {
"byId": {},
"idByUniversalIdentifier": {},
"byUniversalIdentifier": {},
"universalIdentifierById": {},
"universalIdentifiersByApplicationId": {},
},
"updatedFlatEntityMaps": {
"byId": {
"field-id-1": {
"universalIdentifier": "universal-identifier-1",
"byUniversalIdentifier": {
"universal-identifier-1": {
"id": "field-id-1",
"updates": [
{
"from": false,
@@ -168,8 +168,8 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect an upd
exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect created, deleted and updated entities 1`] = `
{
"createdFlatEntityMaps": {
"byId": {
"field-id-3": {
"byUniversalIdentifier": {
"universal-identifier-3": {
"applicationId": "application-id-1",
"applicationUniversalIdentifier": "application-universal-identifier-1",
"calendarViewIds": [],
@@ -213,8 +213,8 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect create
"workspaceId": "workspace-id-1",
},
},
"idByUniversalIdentifier": {
"universal-identifier-3": "field-id-3",
"universalIdentifierById": {
"field-id-3": "universal-identifier-3",
},
"universalIdentifiersByApplicationId": {
"application-id-1": [
@@ -223,8 +223,8 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect create
},
},
"deletedFlatEntityMaps": {
"byId": {
"field-id-2": {
"byUniversalIdentifier": {
"universal-identifier-2": {
"applicationId": "application-id-1",
"applicationUniversalIdentifier": "application-universal-identifier-1",
"calendarViewIds": [],
@@ -268,8 +268,8 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect create
"workspaceId": "workspace-id-1",
},
},
"idByUniversalIdentifier": {
"universal-identifier-2": "field-id-2",
"universalIdentifierById": {
"field-id-2": "universal-identifier-2",
},
"universalIdentifiersByApplicationId": {
"application-id-1": [
@@ -278,9 +278,9 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect create
},
},
"updatedFlatEntityMaps": {
"byId": {
"field-id-1": {
"universalIdentifier": "universal-identifier-1",
"byUniversalIdentifier": {
"universal-identifier-1": {
"id": "field-id-1",
"updates": [
{
"from": true,
@@ -297,17 +297,17 @@ exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should detect create
exports[`flatEntityDeletedCreatedUpdatedMatrixDispatcher It should not detect deleted entities when inferDeletionFromMissingEntities is false 1`] = `
{
"createdFlatEntityMaps": {
"byId": {},
"idByUniversalIdentifier": {},
"byUniversalIdentifier": {},
"universalIdentifierById": {},
"universalIdentifiersByApplicationId": {},
},
"deletedFlatEntityMaps": {
"byId": {},
"idByUniversalIdentifier": {},
"byUniversalIdentifier": {},
"universalIdentifierById": {},
"universalIdentifiersByApplicationId": {},
},
"updatedFlatEntityMaps": {
"byId": {},
"byUniversalIdentifier": {},
},
}
`;
@@ -14,9 +14,11 @@ type TestFlatEntity = SyncableFlatEntity & {
const createFlatEntityMaps = (
entities: TestFlatEntity[],
): FlatEntityMaps<TestFlatEntity> => ({
byId: Object.fromEntries(entities.map((entity) => [entity.id, entity])),
idByUniversalIdentifier: Object.fromEntries(
entities.map((entity) => [entity.universalIdentifier, entity.id]),
byUniversalIdentifier: Object.fromEntries(
entities.map((entity) => [entity.universalIdentifier, entity]),
),
universalIdentifierById: Object.fromEntries(
entities.map((entity) => [entity.id, entity.universalIdentifier]),
),
universalIdentifiersByApplicationId: {},
});
@@ -20,18 +20,24 @@ export const addFlatEntityToFlatEntityMapsThroughMutationOrThrow = <
flatEntity,
flatEntityMapsToMutate,
}: AddFlatEntityToFlatEntityMapsThroughMutationOrThrowArgs<T>): void => {
if (isDefined(flatEntityMapsToMutate.byId[flatEntity.id])) {
if (
isDefined(
flatEntityMapsToMutate.byUniversalIdentifier[
flatEntity.universalIdentifier
],
)
) {
throw new FlatEntityMapsException(
'addFlatEntityToFlatEntityMapsThroughMutationOrThrow: flat entity to add already exists',
FlatEntityMapsExceptionCode.ENTITY_ALREADY_EXISTS,
);
}
flatEntityMapsToMutate.byId[flatEntity.id] = flatEntity;
flatEntityMapsToMutate.byUniversalIdentifier[flatEntity.universalIdentifier] =
flatEntity;
flatEntityMapsToMutate.idByUniversalIdentifier[
flatEntity.universalIdentifier
] = flatEntity.id;
flatEntityMapsToMutate.universalIdentifierById[flatEntity.id] =
flatEntity.universalIdentifier;
if (isDefined(flatEntity.applicationId)) {
const existingUniversalIdentifiers =
@@ -20,31 +20,33 @@ export const deleteFlatEntityFromFlatEntityMapsThroughMutationOrThrow = <
flatEntityMapsToMutate,
entityToDeleteId,
}: DeleteFlatEntityFromFlatEntityMapsThroughMutationOrThrowArgs<T>): void => {
const entityToDelete = flatEntityMapsToMutate.byId[entityToDeleteId];
const universalIdentifierToDelete =
flatEntityMapsToMutate.universalIdentifierById[entityToDeleteId];
if (!isDefined(entityToDelete)) {
if (!isDefined(universalIdentifierToDelete)) {
throw new FlatEntityMapsException(
'deleteFlatEntityFromFlatEntityMapsThroughMutationOrThrow: entity to delete not found',
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
delete flatEntityMapsToMutate.byId[entityToDeleteId];
const entityToDelete =
flatEntityMapsToMutate.byUniversalIdentifier[universalIdentifierToDelete];
delete flatEntityMapsToMutate.idByUniversalIdentifier[
entityToDelete.universalIdentifier
delete flatEntityMapsToMutate.byUniversalIdentifier[
universalIdentifierToDelete
];
if (isDefined(entityToDelete.applicationId)) {
delete flatEntityMapsToMutate.universalIdentifierById[entityToDeleteId];
if (isDefined(entityToDelete?.applicationId)) {
const universalIdentifiers =
flatEntityMapsToMutate.universalIdentifiersByApplicationId[
entityToDelete.applicationId
];
if (isDefined(universalIdentifiers)) {
const index = universalIdentifiers.indexOf(
entityToDelete.universalIdentifier,
);
const index = universalIdentifiers.indexOf(universalIdentifierToDelete);
if (index !== -1) {
universalIdentifiers.splice(index, 1);
@@ -18,12 +18,12 @@ export type DeletedCreatedUpdatedMatrix<T extends AllMetadataName> = {
createdFlatEntityMaps: MetadataFlatEntityMaps<T>;
deletedFlatEntityMaps: MetadataFlatEntityMaps<T>;
updatedFlatEntityMaps: {
byId: Record<
byUniversalIdentifier: Record<
string,
{
updates: FlatEntityPropertiesUpdates<T>;
// TMP remove when maps is universal based
universalIdentifier: string;
id: string;
}
>;
};
@@ -51,7 +51,7 @@ export const flatEntityDeletedCreatedUpdatedMatrixDispatcher = <
const initialDispatcher: DeletedCreatedUpdatedMatrix<T> = {
createdFlatEntityMaps: createEmptyFlatEntityMaps(),
deletedFlatEntityMaps: createEmptyFlatEntityMaps(),
updatedFlatEntityMaps: { byId: {} },
updatedFlatEntityMaps: { byUniversalIdentifier: {} },
};
const fromMap = new Map(from.map((obj) => [obj.universalIdentifier, obj]));
@@ -105,8 +105,10 @@ export const flatEntityDeletedCreatedUpdatedMatrixDispatcher = <
continue;
}
initialDispatcher.updatedFlatEntityMaps.byId[toFlatEntity.id] = {
universalIdentifier: fromFlatEntity.universalIdentifier,
initialDispatcher.updatedFlatEntityMaps.byUniversalIdentifier[
fromFlatEntity.universalIdentifier
] = {
id: toFlatEntity.id,
updates,
};
}
@@ -1,5 +1,6 @@
import { isDefined } from 'twenty-shared/utils';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
@@ -76,7 +77,10 @@ export const validateFlatEntityCircularDependency = <
visited.add(currentParentId);
const parentEntity: T | undefined = flatEntityMaps.byId[currentParentId];
const parentEntity: T | undefined = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: currentParentId,
flatEntityMaps,
});
if (!isDefined(parentEntity)) {
break;