optimize buildFieldMapsFromFlatObjectMetadata usages (#16132)
This newly introduced util can be a bit expensive especially when done recursively. This PR improves that File | Pattern Fixed | Impact -- | -- | -- format-result.util.ts | Recursive array/object processing | N array items → 1 call format-data.util.ts | Recursive array processing | N array items → 1 call process-nested-relations-v2.helper.ts | Duplicate call in call chain | 2 calls → 1 call common-result-getters.service.ts | Per-record processing in array | N records → 1 call compute-relation-connect-query-configs.util.ts | Nested loop (entities × connect fields) | N×M calls → 1 call
This commit is contained in:
+19
-5
@@ -18,7 +18,10 @@ import { FileService } from 'src/engine/core-modules/file/services/file.service'
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
|
||||
import {
|
||||
buildFieldMapsFromFlatObjectMetadata,
|
||||
type FieldMapsForObject,
|
||||
} from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
|
||||
import { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
|
||||
@@ -54,6 +57,11 @@ export class CommonResultGettersService {
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
|
||||
workspaceId: string,
|
||||
) {
|
||||
const fieldMaps = buildFieldMapsFromFlatObjectMetadata(
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadata,
|
||||
);
|
||||
|
||||
return await Promise.all(
|
||||
recordArray.map(
|
||||
async (record: ObjectRecord) =>
|
||||
@@ -63,6 +71,7 @@ export class CommonResultGettersService {
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
workspaceId,
|
||||
fieldMaps,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -74,13 +83,18 @@ export class CommonResultGettersService {
|
||||
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
|
||||
workspaceId: string,
|
||||
fieldMapsForObject?: FieldMapsForObject,
|
||||
): Promise<ObjectRecord> {
|
||||
const handler = this.getHandler(flatObjectMetadata.nameSingular);
|
||||
|
||||
const { fieldIdByName } = buildFieldMapsFromFlatObjectMetadata(
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadata,
|
||||
);
|
||||
const fieldMaps =
|
||||
fieldMapsForObject ??
|
||||
buildFieldMapsFromFlatObjectMetadata(
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadata,
|
||||
);
|
||||
|
||||
const { fieldIdByName } = fieldMaps;
|
||||
|
||||
const relationFields = Object.keys(record)
|
||||
.map(
|
||||
|
||||
+10
-9
@@ -17,7 +17,10 @@ import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-contex
|
||||
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
|
||||
import {
|
||||
buildFieldMapsFromFlatObjectMetadata,
|
||||
type FieldMapsForObject,
|
||||
} from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
|
||||
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { type WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace.datasource';
|
||||
import { type WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder';
|
||||
@@ -112,13 +115,13 @@ export class ProcessNestedRelationsV2Helper {
|
||||
rolePermissionConfig?: RolePermissionConfig;
|
||||
selectedFields: Record<string, unknown>;
|
||||
}): Promise<void> {
|
||||
const { fieldIdByName } = buildFieldMapsFromFlatObjectMetadata(
|
||||
const fieldMaps = buildFieldMapsFromFlatObjectMetadata(
|
||||
flatFieldMetadataMaps,
|
||||
parentObjectMetadataItem,
|
||||
);
|
||||
|
||||
const sourceFieldMetadata = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: fieldIdByName[sourceFieldName],
|
||||
flatEntityId: fieldMaps.fieldIdByName[sourceFieldName],
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
@@ -154,6 +157,7 @@ export class ProcessNestedRelationsV2Helper {
|
||||
flatFieldMetadataMaps,
|
||||
parentObjectMetadataItem,
|
||||
sourceFieldName,
|
||||
fieldMaps,
|
||||
});
|
||||
|
||||
const targetObjectRepository = workspaceDataSource.getRepository(
|
||||
@@ -250,19 +254,16 @@ export class ProcessNestedRelationsV2Helper {
|
||||
flatFieldMetadataMaps,
|
||||
parentObjectMetadataItem,
|
||||
sourceFieldName,
|
||||
fieldMaps,
|
||||
}: {
|
||||
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
|
||||
parentObjectMetadataItem: FlatObjectMetadata;
|
||||
sourceFieldName: string;
|
||||
fieldMaps: FieldMapsForObject;
|
||||
}) {
|
||||
const { fieldIdByName } = buildFieldMapsFromFlatObjectMetadata(
|
||||
flatFieldMetadataMaps,
|
||||
parentObjectMetadataItem,
|
||||
);
|
||||
|
||||
const targetFieldMetadata = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: fieldIdByName[sourceFieldName],
|
||||
flatEntityId: fieldMaps.fieldIdByName[sourceFieldName],
|
||||
flatEntityMaps: flatFieldMetadataMaps,
|
||||
});
|
||||
|
||||
|
||||
+6
-1
@@ -13,6 +13,7 @@ import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-m
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { type WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace.datasource';
|
||||
import { validateOperationIsPermittedOrThrow } from 'src/engine/twenty-orm/repository/permissions.utils';
|
||||
import { getObjectMetadataFromEntityTarget } from 'src/engine/twenty-orm/utils/get-object-metadata-from-entity-target.util';
|
||||
|
||||
import { WorkspaceEntityManager } from './workspace-entity-manager';
|
||||
|
||||
@@ -23,7 +24,7 @@ jest.mock('src/engine/twenty-orm/repository/permissions.utils', () => ({
|
||||
jest.mock(
|
||||
'src/engine/twenty-orm/utils/get-object-metadata-from-entity-target.util',
|
||||
() => ({
|
||||
getObjectMetadataFromEntityTarget: jest.fn().mockReturnValue({}),
|
||||
getObjectMetadataFromEntityTarget: jest.fn(),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -117,6 +118,10 @@ describe('WorkspaceEntityManager', () => {
|
||||
updatedAt: new Date(),
|
||||
};
|
||||
|
||||
(getObjectMetadataFromEntityTarget as jest.Mock).mockReturnValue(
|
||||
mockFlatObjectMetadata,
|
||||
);
|
||||
|
||||
const mockFlatFieldMetadata: FlatFieldMetadata = {
|
||||
id: 'field-id',
|
||||
type: 'TEXT' as FieldMetadataType,
|
||||
|
||||
+13
-7
@@ -9,7 +9,10 @@ import { getFlatFieldsFromFlatObjectMetadata } from 'src/engine/api/graphql/work
|
||||
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
|
||||
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 { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
|
||||
import {
|
||||
buildFieldMapsFromFlatObjectMetadata,
|
||||
type FieldMapsForObject,
|
||||
} from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.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 ConnectObject } from 'src/engine/twenty-orm/entity-manager/types/query-deep-partial-entity-with-nested-relation-fields.type';
|
||||
@@ -36,6 +39,11 @@ export const computeRelationConnectQueryConfigs = (
|
||||
) => {
|
||||
const allConnectQueryConfigs: Record<string, RelationConnectQueryConfig> = {};
|
||||
|
||||
const fieldMaps = buildFieldMapsFromFlatObjectMetadata(
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadata,
|
||||
);
|
||||
|
||||
for (const [entityIndex, entity] of entities.entries()) {
|
||||
const nestedRelationConnectFields =
|
||||
relationConnectQueryFieldsByEntityIndex[entityIndex];
|
||||
@@ -57,6 +65,7 @@ export const computeRelationConnectQueryConfigs = (
|
||||
flatFieldMetadataMaps,
|
||||
flatIndexMaps,
|
||||
entity,
|
||||
fieldMaps,
|
||||
);
|
||||
|
||||
const connectQueryConfig = allConnectQueryConfigs[connectFieldName];
|
||||
@@ -132,17 +141,14 @@ const computeRecordToConnectCondition = (
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
|
||||
flatIndexMaps: FlatEntityMaps<FlatIndexMetadata>,
|
||||
entity: Record<string, unknown>,
|
||||
fieldMaps: FieldMapsForObject,
|
||||
): {
|
||||
recordToConnectCondition: UniqueConstraintCondition;
|
||||
uniqueConstraintFields: FlatFieldMetadata<FieldMetadataType>[];
|
||||
targetObjectNameSingular: string;
|
||||
} => {
|
||||
const { fieldIdByName } = buildFieldMapsFromFlatObjectMetadata(
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadata,
|
||||
);
|
||||
|
||||
const field = flatFieldMetadataMaps.byId[fieldIdByName[connectFieldName]];
|
||||
const field =
|
||||
flatFieldMetadataMaps.byId[fieldMaps.fieldIdByName[connectFieldName]];
|
||||
|
||||
if (
|
||||
!isDefined(field) ||
|
||||
|
||||
@@ -7,7 +7,10 @@ import { capitalize } from 'twenty-shared/utils';
|
||||
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
|
||||
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 { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
|
||||
import {
|
||||
buildFieldMapsFromFlatObjectMetadata,
|
||||
type FieldMapsForObject,
|
||||
} from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { type CompositeFieldMetadataType } from 'src/engine/metadata-modules/workspace-migration/factories/composite-column-action.factory';
|
||||
|
||||
@@ -15,23 +18,27 @@ export function formatData<T>(
|
||||
data: T,
|
||||
flatObjectMetadata: FlatObjectMetadata,
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
|
||||
fieldMapsForObject?: FieldMapsForObject,
|
||||
): T {
|
||||
if (!data) {
|
||||
return data;
|
||||
}
|
||||
|
||||
if (Array.isArray(data)) {
|
||||
return data.map((item) =>
|
||||
formatData(item, flatObjectMetadata, flatFieldMetadataMaps),
|
||||
) as T;
|
||||
}
|
||||
|
||||
const { fieldIdByName, fieldIdByJoinColumnName } =
|
||||
const fieldMaps =
|
||||
fieldMapsForObject ??
|
||||
buildFieldMapsFromFlatObjectMetadata(
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadata,
|
||||
);
|
||||
|
||||
if (Array.isArray(data)) {
|
||||
return data.map((item) =>
|
||||
formatData(item, flatObjectMetadata, flatFieldMetadataMaps, fieldMaps),
|
||||
) as T;
|
||||
}
|
||||
|
||||
const { fieldIdByName, fieldIdByJoinColumnName } = fieldMaps;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const newData: Record<string, any> = {};
|
||||
|
||||
|
||||
@@ -16,7 +16,10 @@ import { getFlatFieldsFromFlatObjectMetadata } from 'src/engine/api/graphql/work
|
||||
import { computeCompositeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
|
||||
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 { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
|
||||
import {
|
||||
buildFieldMapsFromFlatObjectMetadata,
|
||||
type FieldMapsForObject,
|
||||
} from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { getCompositeFieldMetadataCollection } from 'src/engine/twenty-orm/utils/get-composite-field-metadata-collection';
|
||||
import { isFieldMetadataEntityOfType } from 'src/engine/utils/is-field-metadata-of-type.util';
|
||||
@@ -27,23 +30,25 @@ export function formatResult<T>(
|
||||
flatObjectMetadata: FlatObjectMetadata | undefined,
|
||||
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>,
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>,
|
||||
fieldMapsForObject?: FieldMapsForObject,
|
||||
): T {
|
||||
if (!isDefined(data)) {
|
||||
return data;
|
||||
}
|
||||
|
||||
if (Array.isArray(data)) {
|
||||
return data.map((item) =>
|
||||
formatResult(
|
||||
item,
|
||||
flatObjectMetadata,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
),
|
||||
) as T;
|
||||
}
|
||||
|
||||
if (!isPlainObject(data)) {
|
||||
if (Array.isArray(data)) {
|
||||
return data.map((item) =>
|
||||
formatResult(
|
||||
item,
|
||||
flatObjectMetadata,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
fieldMapsForObject,
|
||||
),
|
||||
) as T;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -51,10 +56,14 @@ export function formatResult<T>(
|
||||
throw new Error('Object metadata is missing');
|
||||
}
|
||||
|
||||
const { fieldIdByName } = buildFieldMapsFromFlatObjectMetadata(
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadata,
|
||||
);
|
||||
const fieldMaps =
|
||||
fieldMapsForObject ??
|
||||
buildFieldMapsFromFlatObjectMetadata(
|
||||
flatFieldMetadataMaps,
|
||||
flatObjectMetadata,
|
||||
);
|
||||
|
||||
const { fieldIdByName } = fieldMaps;
|
||||
|
||||
const compositeFieldMetadataMap = getCompositeFieldMetadataMap(
|
||||
flatObjectMetadata,
|
||||
@@ -86,6 +95,7 @@ export function formatResult<T>(
|
||||
flatObjectMetadata,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
fieldMaps,
|
||||
);
|
||||
} else if (fieldMetadata) {
|
||||
// @ts-expect-error legacy noImplicitAny
|
||||
|
||||
Reference in New Issue
Block a user