Deprecate object metadata maps in favor of flat entities (#16080)

## Context
Deprecating the old objectMetadataMap type in favour of split flat
entities to match with our new caching.
In the long run, trying to achieve:
- Better performance through caching
- Consistent data access patterns across the codebase
- Reduced database queries

Now that everything is based on flat entities, which are cached, we can
finish the refactoring of workspace context cache which should already
improve performances.
Then the last step will be to consume that new cache in the new global
datasource to get rid of the many workspace datasources stored in the
server
This commit is contained in:
Weiko
2025-11-27 13:43:34 +01:00
committed by GitHub
parent 978c0acb90
commit 1607aebcc6
281 changed files with 6510 additions and 6627 deletions
@@ -41,14 +41,15 @@ export class CreateManyResolverFactory
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.objectMetadataMaps,
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
);
return records.map((record: ObjectRecord) =>
typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName:
internalContext.objectMetadataItemWithFieldMaps.nameSingular,
objectName: internalContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
}),
@@ -40,13 +40,14 @@ export class CreateOneResolverFactory
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.objectMetadataMaps,
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
);
return typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName:
internalContext.objectMetadataItemWithFieldMaps.nameSingular,
objectName: internalContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
});
@@ -41,14 +41,15 @@ export class DeleteManyResolverFactory
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.objectMetadataMaps,
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
);
return records.map((record: ObjectRecord) =>
typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName:
internalContext.objectMetadataItemWithFieldMaps.nameSingular,
objectName: internalContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
}),
@@ -40,13 +40,14 @@ export class DeleteOneResolverFactory
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.objectMetadataMaps,
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
);
return typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName:
internalContext.objectMetadataItemWithFieldMaps.nameSingular,
objectName: internalContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
});
@@ -41,14 +41,15 @@ export class DestroyManyResolverFactory
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.objectMetadataMaps,
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
);
return records.map((record: ObjectRecord) =>
typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName:
internalContext.objectMetadataItemWithFieldMaps.nameSingular,
objectName: internalContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
}),
@@ -40,13 +40,14 @@ export class DestroyOneResolverFactory
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.objectMetadataMaps,
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
);
return typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName:
internalContext.objectMetadataItemWithFieldMaps.nameSingular,
objectName: internalContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
});
@@ -42,14 +42,15 @@ export class FindDuplicatesResolverFactory
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.objectMetadataMaps,
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
);
return paginatedDuplicates.map((duplicate) =>
typeORMObjectRecordsParser.createConnection({
objectRecords: duplicate.records,
objectName:
internalContext.objectMetadataItemWithFieldMaps.nameSingular,
objectName: internalContext.flatObjectMetadata.nameSingular,
take: duplicate.records.length,
totalCount: duplicate.totalCount,
order: [{ id: OrderByDirection.AscNullsFirst }],
@@ -47,15 +47,16 @@ export class FindManyResolverFactory
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.objectMetadataMaps,
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
);
return typeORMObjectRecordsParser.createConnection({
objectRecords: records,
objectRecordsAggregatedValues: aggregatedValues,
selectedAggregatedFields: selectedFieldsResult.aggregate,
objectName:
internalContext.objectMetadataItemWithFieldMaps.nameSingular,
objectName: internalContext.flatObjectMetadata.nameSingular,
take: args.first ?? args.last ?? QUERY_MAX_RECORDS,
totalCount,
order: args.orderBy,
@@ -40,13 +40,14 @@ export class FindOneResolverFactory
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.objectMetadataMaps,
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
);
return typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName:
internalContext.objectMetadataItemWithFieldMaps.nameSingular,
objectName: internalContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
});
@@ -40,7 +40,9 @@ export class GroupByResolverFactory
try {
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.objectMetadataMaps,
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
);
const results = await this.commonGroupByQueryRunnerService.execute(
@@ -51,8 +53,7 @@ export class GroupByResolverFactory
const formattedResults = results.map((group) => {
const formattedRecords = typeORMObjectRecordsParser.createConnection({
objectRecords: group.records ?? [],
objectName:
internalContext.objectMetadataItemWithFieldMaps.nameSingular,
objectName: internalContext.flatObjectMetadata.nameSingular,
objectRecordsAggregatedValues: {},
selectedAggregatedFields: {},
take: group.records?.length || 0,
@@ -40,13 +40,14 @@ export class MergeManyResolverFactory
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.objectMetadataMaps,
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
);
return typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName:
internalContext.objectMetadataItemWithFieldMaps.nameSingular,
objectName: internalContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
});
@@ -41,14 +41,15 @@ export class RestoreManyResolverFactory
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.objectMetadataMaps,
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
);
return records.map((record: ObjectRecord) =>
typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName:
internalContext.objectMetadataItemWithFieldMaps.nameSingular,
objectName: internalContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
}),
@@ -40,13 +40,14 @@ export class RestoreOneResolverFactory
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.objectMetadataMaps,
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
);
return typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName:
internalContext.objectMetadataItemWithFieldMaps.nameSingular,
objectName: internalContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
});
@@ -41,14 +41,15 @@ export class UpdateManyResolverFactory
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.objectMetadataMaps,
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
);
return records.map((record: ObjectRecord) =>
typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName:
internalContext.objectMetadataItemWithFieldMaps.nameSingular,
objectName: internalContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
}),
@@ -40,13 +40,14 @@ export class UpdateOneResolverFactory
const typeORMObjectRecordsParser =
new ObjectRecordsToGraphqlConnectionHelper(
internalContext.objectMetadataMaps,
internalContext.flatObjectMetadataMaps,
internalContext.flatFieldMetadataMaps,
internalContext.objectIdByNameSingular,
);
return typeORMObjectRecordsParser.processRecord({
objectRecord: record,
objectName:
internalContext.objectMetadataItemWithFieldMaps.nameSingular,
objectName: internalContext.flatObjectMetadata.nameSingular,
take: 1,
totalCount: 1,
});
@@ -17,11 +17,10 @@ import {
AuthExceptionCode,
} from 'src/engine/core-modules/auth/auth.exception';
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
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 { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { getResolverName } from 'src/engine/utils/get-resolver-name.util';
import { standardObjectMetadataDefinitions } from 'src/engine/workspace-manager/workspace-sync-metadata/standard-objects';
import { shouldExcludeFromWorkspaceApi } from 'src/engine/workspace-manager/workspace-sync-metadata/utils/should-exclude-from-workspace-api.util';
import { CreateManyResolverFactory } from './factories/create-many-resolver.factory';
import { CreateOneResolverFactory } from './factories/create-one-resolver.factory';
@@ -57,12 +56,13 @@ export class WorkspaceResolverFactory {
private readonly mergeManyResolverFactory: MergeManyResolverFactory,
private readonly groupByResolverFactory: GroupByResolverFactory,
private readonly workspaceResolverBuilderService: WorkspaceResolverBuilderService,
private readonly featureFlagService: FeatureFlagService,
) {}
async create(
authContext: AuthContext,
objectMetadataMaps: ObjectMetadataMaps,
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
objectIdByNameSingular: Record<string, string>,
workspaceResolverBuilderMethods: WorkspaceResolverBuilderMethods,
): Promise<IResolvers> {
const factories = new Map<
@@ -99,30 +99,17 @@ export class WorkspaceResolverFactory {
);
}
const workspaceFeatureFlagsMap =
await this.featureFlagService.getWorkspaceFeatureFlagsMap(workspaceId);
for (const objectMetadata of Object.values(objectMetadataMaps.byId).filter(
isDefined,
)) {
if (
shouldExcludeFromWorkspaceApi(
objectMetadata,
standardObjectMetadataDefinitions,
workspaceFeatureFlagsMap,
)
) {
continue;
}
for (const flatObjectMetadata of Object.values(
flatObjectMetadataMaps.byId,
).filter(isDefined)) {
// Generate query resolvers
for (const methodName of workspaceResolverBuilderMethods.queries) {
const resolverName = getResolverName(objectMetadata, methodName);
const resolverName = getResolverName(flatObjectMetadata, methodName);
const resolverFactory = factories.get(methodName);
if (!resolverFactory) {
this.logger.error(`Unknown query resolver type: ${methodName}`, {
objectMetadata,
flatObjectMetadata,
methodName,
resolverName,
});
@@ -132,27 +119,29 @@ export class WorkspaceResolverFactory {
if (
this.workspaceResolverBuilderService.shouldBuildResolver(
objectMetadata,
flatObjectMetadata,
methodName,
)
) {
// @ts-expect-error legacy noImplicitAny
resolvers.Query[resolverName] = resolverFactory.create({
authContext,
objectMetadataMaps,
objectMetadataItemWithFieldMaps: objectMetadata,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
objectIdByNameSingular,
});
}
}
// Generate mutation resolvers
for (const methodName of workspaceResolverBuilderMethods.mutations) {
const resolverName = getResolverName(objectMetadata, methodName);
const resolverName = getResolverName(flatObjectMetadata, methodName);
const resolverFactory = factories.get(methodName);
if (!resolverFactory) {
this.logger.error(`Unknown mutation resolver type: ${methodName}`, {
objectMetadata,
flatObjectMetadata,
methodName,
resolverName,
});
@@ -162,15 +151,17 @@ export class WorkspaceResolverFactory {
if (
this.workspaceResolverBuilderService.shouldBuildResolver(
objectMetadata,
flatObjectMetadata,
methodName,
)
) {
// @ts-expect-error legacy noImplicitAny
resolvers.Mutation[resolverName] = resolverFactory.create({
authContext,
objectMetadataMaps,
objectMetadataItemWithFieldMaps: objectMetadata,
flatObjectMetadata,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
objectIdByNameSingular,
});
}
}