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
@@ -5,6 +5,7 @@ import { isDefined } from 'twenty-shared/utils';
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { type FlatPageLayoutTabMaps } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab-maps.type';
import { type FlatPageLayoutTab } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab.type';
import { fromCreatePageLayoutTabInputToFlatPageLayoutTabToCreate } from 'src/engine/metadata-modules/flat-page-layout-tab/utils/from-create-page-layout-tab-input-to-flat-page-layout-tab-to-create.util';
@@ -166,7 +167,10 @@ export class PageLayoutDuplicationService {
pageLayoutId: string,
flatPageLayoutMaps: FlatPageLayoutMaps,
): FlatPageLayout {
const flatLayout = flatPageLayoutMaps.byId[pageLayoutId];
const flatLayout = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: pageLayoutId,
flatEntityMaps: flatPageLayoutMaps,
});
if (!isDefined(flatLayout) || isDefined(flatLayout.deletedAt)) {
throw new PageLayoutException(
@@ -188,7 +192,9 @@ export class PageLayoutDuplicationService {
): { tab: FlatPageLayoutTab; widgets: FlatPageLayoutWidget[] }[] {
const widgetsByTabId = new Map<string, FlatPageLayoutWidget[]>();
for (const widget of Object.values(flatPageLayoutWidgetMaps.byId)) {
for (const widget of Object.values(
flatPageLayoutWidgetMaps.byUniversalIdentifier,
)) {
if (!isDefined(widget) || isDefined(widget.deletedAt)) {
continue;
}
@@ -199,7 +205,7 @@ export class PageLayoutDuplicationService {
widgetsByTabId.set(widget.pageLayoutTabId, existingWidgets);
}
const tabs = Object.values(flatPageLayoutTabMaps.byId)
const tabs = Object.values(flatPageLayoutTabMaps.byUniversalIdentifier)
.filter(
(tab): tab is FlatPageLayoutTab =>
isDefined(tab) &&
@@ -7,6 +7,7 @@ import { v4 } from 'uuid';
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { FLAT_PAGE_LAYOUT_TAB_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-page-layout-tab/constants/flat-page-layout-tab-editable-properties.constant';
import { type FlatPageLayoutTabMaps } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab-maps.type';
import { type FlatPageLayoutTab } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab.type';
@@ -66,7 +67,10 @@ export class PageLayoutUpdateService {
},
);
const existingPageLayout = flatPageLayoutMaps.byId[id];
const existingPageLayout = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: id,
flatEntityMaps: flatPageLayoutMaps,
});
// TODO move in validator
if (
@@ -203,7 +207,9 @@ export class PageLayoutUpdateService {
tabsToUpdate: FlatPageLayoutTab[];
tabsToDelete: FlatPageLayoutTab[];
} {
const existingTabs = Object.values(flatPageLayoutTabMaps.byId)
const existingTabs = Object.values(
flatPageLayoutTabMaps.byUniversalIdentifier,
)
.filter(isDefined)
.filter((tab) => tab.pageLayoutId === existingPageLayout.id);
@@ -279,7 +285,10 @@ export class PageLayoutUpdateService {
const tabsToDelete: FlatPageLayoutTab[] = idsToDelete
.map((tabId) => {
const existingTab = flatPageLayoutTabMaps.byId[tabId];
const existingTab = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: tabId,
flatEntityMaps: flatPageLayoutTabMaps,
});
if (!isDefined(existingTab)) {
return null;
@@ -359,7 +368,9 @@ export class PageLayoutUpdateService {
widgetsToCreate: FlatPageLayoutWidget[];
widgetsToUpdate: FlatPageLayoutWidget[];
} {
const existingWidgets = Object.values(flatPageLayoutWidgetMaps.byId)
const existingWidgets = Object.values(
flatPageLayoutWidgetMaps.byUniversalIdentifier,
)
.filter(isDefined)
.filter((widget) => widget.pageLayoutTabId === tabId);
@@ -447,7 +458,10 @@ export class PageLayoutUpdateService {
const widgetsToDelete: FlatPageLayoutWidget[] = idsToDelete
.map((widgetId) => {
const existingWidget = flatPageLayoutWidgetMaps.byId[widgetId];
const existingWidget = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: widgetId,
flatEntityMaps: flatPageLayoutWidgetMaps,
});
if (!isDefined(existingWidget)) {
return null;
@@ -5,6 +5,7 @@ import { isDefined } from 'twenty-shared/utils';
import { ApplicationService } from 'src/engine/core-modules/application/services/application.service';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { type FlatPageLayoutTabMaps } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab-maps.type';
import { type FlatPageLayoutWidgetMaps } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget-maps.type';
@@ -51,7 +52,9 @@ export class PageLayoutService {
flatPageLayoutWidgetMaps,
} = await this.getPageLayoutFlatEntityMaps(workspaceId);
const activeLayouts = Object.values(flatPageLayoutMaps.byId)
const activeLayouts = Object.values(
flatPageLayoutMaps.byUniversalIdentifier,
)
.filter(isDefined)
.filter((layout) => !isDefined(layout.deletedAt));
@@ -79,7 +82,9 @@ export class PageLayoutService {
flatPageLayoutWidgetMaps,
} = await this.getPageLayoutFlatEntityMaps(workspaceId);
const activeLayouts = Object.values(flatPageLayoutMaps.byId)
const activeLayouts = Object.values(
flatPageLayoutMaps.byUniversalIdentifier,
)
.filter(isDefined)
.filter(
(layout) =>
@@ -111,7 +116,10 @@ export class PageLayoutService {
flatPageLayoutWidgetMaps,
} = await this.getPageLayoutFlatEntityMaps(workspaceId);
const flatLayout = flatPageLayoutMaps.byId[id];
const flatLayout = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: id,
flatEntityMaps: flatPageLayoutMaps,
});
const isLayoutNotFound =
!isDefined(flatLayout) || isDefined(flatLayout.deletedAt);