Migrate metadata cache (#16030)

## Context
Deprecating legacy ObjectMetadata from cache in favor of flat entities.
Introducing utils to build byName/byNameSingular/byNamePlural in
isolated cases

## Next
- I had to introduce a util to build from flat to legacy
objectMetadataMaps, we should instead use flat maps directly when needed
(datasource, schema generation, etc)
- Deprecate metadata version in the cache
- Use the new cache strategy for flat entities with permissions and
feature flags and inject in the global datasource context
This commit is contained in:
Weiko
2025-11-24 19:50:47 +01:00
committed by GitHub
parent 26e2fe349f
commit 04562b11fb
49 changed files with 764 additions and 598 deletions
@@ -0,0 +1,27 @@
import { isDefined } from 'twenty-shared/utils';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
export const buildObjectIdByNameMaps = (
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
): {
idByNameSingular: Record<string, string>;
idByNamePlural: Record<string, string>;
} => {
const idByNameSingular: Record<string, string> = {};
const idByNamePlural: Record<string, string> = {};
for (const [objectId, objectMetadata] of Object.entries(
flatObjectMetadataMaps.byId,
)) {
if (!isDefined(objectMetadata)) {
continue;
}
idByNameSingular[objectMetadata.nameSingular] = objectId;
idByNamePlural[objectMetadata.namePlural] = objectId;
}
return { idByNameSingular, idByNamePlural };
};
@@ -0,0 +1,45 @@
import { isDefined } from 'twenty-shared/utils';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { buildFieldMapsForObject } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-for-object.util';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type ObjectMetadataItemWithFieldMaps } from 'src/engine/metadata-modules/types/object-metadata-item-with-field-maps';
export const buildObjectMetadataItemWithFieldMaps = (
flatObjectMetadata: FlatObjectMetadata,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
flatIndexMaps: FlatEntityMaps<FlatIndexMetadata>,
): ObjectMetadataItemWithFieldMaps => {
const fieldsById: Record<string, FlatFieldMetadata> = {};
for (const fieldId of flatObjectMetadata.fieldMetadataIds) {
const field = flatFieldMetadataMaps.byId[fieldId];
if (isDefined(field)) {
fieldsById[fieldId] = field;
}
}
const { fieldIdByName, fieldIdByJoinColumnName } = buildFieldMapsForObject(
flatFieldMetadataMaps,
flatObjectMetadata.id,
);
const indexMetadatas = flatObjectMetadata.indexMetadataIds
.map((indexId) => flatIndexMaps.byId[indexId])
.filter(isDefined)
.map((flatIndex) => ({
...flatIndex,
indexFieldMetadatas: flatIndex.flatIndexFieldMetadatas,
}));
return {
...flatObjectMetadata,
fieldsById,
fieldIdByName,
fieldIdByJoinColumnName,
indexMetadatas,
} as unknown as ObjectMetadataItemWithFieldMaps;
};