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
@@ -87,8 +87,8 @@ export const mockFlatObjectMetadatas: FlatObjectMetadata[] = [
];
export const mockFlatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata> = {
byId: {
[personNameFieldId]: getFlatFieldMetadataMock({
byUniversalIdentifier: {
'person-name-field-universal-id': getFlatFieldMetadataMock({
id: personNameFieldId,
type: FieldMetadataType.FULL_NAME,
icon: 'test-field-icon',
@@ -102,7 +102,7 @@ export const mockFlatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata> = {
universalIdentifier: 'person-name-field-universal-id',
applicationId: workspaceId,
}),
[companyNameFieldId]: getFlatFieldMetadataMock({
'company-name-field-universal-id': getFlatFieldMetadataMock({
id: companyNameFieldId,
type: FieldMetadataType.TEXT,
icon: 'test-field-icon',
@@ -116,7 +116,7 @@ export const mockFlatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata> = {
universalIdentifier: 'company-name-field-universal-id',
applicationId: workspaceId,
}),
[companyDomainNameFieldId]: getFlatFieldMetadataMock({
'company-domain-name-field-universal-id': getFlatFieldMetadataMock({
id: companyDomainNameFieldId,
type: FieldMetadataType.LINKS,
icon: 'test-field-icon',
@@ -134,7 +134,7 @@ export const mockFlatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata> = {
universalIdentifier: 'company-domain-name-field-universal-id',
applicationId: workspaceId,
}),
[customObjectNameFieldId]: getFlatFieldMetadataMock({
'custom-object-name-field-universal-id': getFlatFieldMetadataMock({
id: customObjectNameFieldId,
type: FieldMetadataType.TEXT,
icon: 'test-field-icon',
@@ -148,7 +148,7 @@ export const mockFlatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata> = {
universalIdentifier: 'custom-object-name-field-universal-id',
applicationId: workspaceId,
}),
[customObjectImageFieldId]: getFlatFieldMetadataMock({
'custom-object-image-field-universal-id': getFlatFieldMetadataMock({
id: customObjectImageFieldId,
type: FieldMetadataType.TEXT,
icon: 'test-field-icon',
@@ -163,6 +163,12 @@ export const mockFlatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata> = {
applicationId: workspaceId,
}),
},
idByUniversalIdentifier: {},
universalIdentifierById: {
[personNameFieldId]: 'person-name-field-universal-id',
[companyNameFieldId]: 'company-name-field-universal-id',
[companyDomainNameFieldId]: 'company-domain-name-field-universal-id',
[customObjectNameFieldId]: 'custom-object-name-field-universal-id',
[customObjectImageFieldId]: 'custom-object-image-field-universal-id',
},
universalIdentifiersByApplicationId: {},
};
@@ -2,10 +2,11 @@ import { FieldMetadataType } from 'twenty-shared/types';
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
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 { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/get-flat-object-metadata.mock';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type ObjectMetadataInfo } from 'src/modules/workflow/common/workspace-services/workflow-common.workspace-service';
const workspaceId = '20202020-0000-0000-0000-000000000000';
@@ -219,13 +220,13 @@ export const mockFlatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata> =
ALL_FLAT_OBJECTS.reduce(
(acc, object) => ({
...acc,
byId: {
...acc.byId,
[object.id]: object,
byUniversalIdentifier: {
...acc.byUniversalIdentifier,
[object.universalIdentifier]: object,
},
idByUniversalIdentifier: {
...acc.idByUniversalIdentifier,
[object.universalIdentifier]: object.id,
universalIdentifierById: {
...acc.universalIdentifierById,
[object.id]: object.universalIdentifier,
},
}),
createEmptyFlatEntityMaps() as FlatEntityMaps<FlatObjectMetadata>,
@@ -235,13 +236,13 @@ export const mockFlatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata> =
ALL_FLAT_FIELDS.reduce(
(acc, field) => ({
...acc,
byId: {
...acc.byId,
[field.id]: field,
byUniversalIdentifier: {
...acc.byUniversalIdentifier,
[field.universalIdentifier]: field,
},
idByUniversalIdentifier: {
...acc.idByUniversalIdentifier,
[field.universalIdentifier]: field.id,
universalIdentifierById: {
...acc.universalIdentifierById,
[field.id]: field.universalIdentifier,
},
}),
createEmptyFlatEntityMaps() as FlatEntityMaps<FlatFieldMetadata>,
@@ -260,7 +261,10 @@ export const getMockObjectMetadataInfo = (
nameSingular: string,
): ObjectMetadataInfo => {
const objectId = mockObjectIdByNameSingular[nameSingular];
const flatObjectMetadata = mockFlatObjectMetadataMaps.byId[objectId];
const flatObjectMetadata = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: objectId,
flatEntityMaps: mockFlatObjectMetadataMaps,
});
if (!flatObjectMetadata) {
throw new Error(
@@ -67,25 +67,37 @@ describe('ActorFromAuthContextService', () => {
useValue: {
getOrRecomputeManyOrAllFlatEntityMaps: jest.fn().mockResolvedValue({
flatObjectMetadataMaps: {
byId: {
'person-id': {
byUniversalIdentifier: {
'person-universal-id': {
id: 'person-id',
nameSingular: 'person',
fieldIds: ['createdBy-id'],
universalIdentifier: 'person-universal-id',
},
},
universalIdentifierById: {
'person-id': 'person-universal-id',
},
universalIdentifiersByApplicationId: {},
},
flatFieldMetadataMaps: {
byId: {
'createdBy-id': {
byUniversalIdentifier: {
'createdBy-universal-id': {
id: 'createdBy-id',
name: 'createdBy',
objectMetadataId: 'person-id',
universalIdentifier: 'createdBy-universal-id',
},
},
universalIdentifierById: {
'createdBy-id': 'createdBy-universal-id',
},
universalIdentifiersByApplicationId: {},
},
flatIndexMaps: {
byId: {},
byUniversalIdentifier: {},
universalIdentifierById: {},
universalIdentifiersByApplicationId: {},
},
}),
},
@@ -10,6 +10,7 @@ import { buildCreatedByFromFullNameMetadata } from 'src/engine/core-modules/acto
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { WorkspaceNotFoundDefaultError } from 'src/engine/core-modules/workspace/workspace.exception';
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 { buildFieldMapsFromFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/build-field-maps-from-flat-object-metadata.util';
import { buildObjectIdByNameMaps } from 'src/engine/metadata-modules/flat-object-metadata/utils/build-object-id-by-name-maps.util';
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
@@ -103,7 +104,10 @@ export class ActorFromAuthContextService {
);
const objectId = idByNameSingular[objectMetadataNameSingular];
const objectMetadata = objectId
? flatObjectMetadataMaps.byId[objectId]
? findFlatEntityByIdInFlatEntityMaps({
flatEntityId: objectId,
flatEntityMaps: flatObjectMetadataMaps,
})
: undefined;
const fieldIdByName = objectMetadata
@@ -29,8 +29,11 @@ import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-
import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/services/field-metadata.service';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { findFlatEntitiesByApplicationId } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entities-by-application-id.util';
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
import { 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 { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service';
import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
@@ -286,13 +289,24 @@ export class ApplicationSyncService {
);
const formattedObjectPermissions = role.objectPermissions
?.map((perm) => ({
...perm,
objectMetadataId:
flatObjectMetadataMaps.idByUniversalIdentifier[
perm.objectUniversalIdentifier
],
}))
?.map((perm) => {
const flatObjectMetadata = findFlatEntityByUniversalIdentifier({
flatEntityMaps: flatObjectMetadataMaps,
universalIdentifier: perm.objectUniversalIdentifier,
});
if (!isDefined(flatObjectMetadata)) {
throw new ApplicationException(
`Failed to find object with universalIdentifier ${perm.objectUniversalIdentifier}`,
ApplicationExceptionCode.OBJECT_NOT_FOUND,
);
}
return {
...perm,
objectMetadataId: flatObjectMetadata.id,
};
})
.filter((perm): perm is typeof perm & { objectMetadataId: string } =>
isDefined(perm.objectMetadataId),
);
@@ -309,20 +323,34 @@ export class ApplicationSyncService {
const formattedFieldPermissions = role?.fieldPermissions
?.map((perm) => {
const objectMetadataId =
flatObjectMetadataMaps.idByUniversalIdentifier[
perm.objectUniversalIdentifier
];
const flatObjectMetadata = findFlatEntityByUniversalIdentifier({
flatEntityMaps: flatObjectMetadataMaps,
universalIdentifier: perm.objectUniversalIdentifier,
});
const fieldMetadataId =
flatFieldMetadataMaps.idByUniversalIdentifier[
perm.fieldUniversalIdentifier
];
if (!isDefined(flatObjectMetadata)) {
throw new ApplicationException(
`Failed to find object with universalIdentifier ${perm.objectUniversalIdentifier}`,
ApplicationExceptionCode.OBJECT_NOT_FOUND,
);
}
const flatFieldMetadata = findFlatEntityByUniversalIdentifier({
flatEntityMaps: flatFieldMetadataMaps,
universalIdentifier: perm.fieldUniversalIdentifier,
});
if (!isDefined(flatFieldMetadata)) {
throw new ApplicationException(
`Failed to find field with universalIdentifier ${perm.fieldUniversalIdentifier}`,
ApplicationExceptionCode.FIELD_NOT_FOUND,
);
}
return {
...perm,
objectMetadataId,
fieldMetadataId,
objectMetadataId: flatObjectMetadata.id,
fieldMetadataId: flatFieldMetadata.id,
};
})
.filter(
@@ -395,7 +423,7 @@ export class ApplicationSyncService {
);
const existingFields = Object.values(
existingFlatFieldMetadataMaps.byId,
existingFlatFieldMetadataMaps.byUniversalIdentifier,
).filter(
(field) =>
isDefined(field) &&
@@ -514,9 +542,7 @@ export class ApplicationSyncService {
fieldsToSync: ObjectFieldManifest[];
workspaceId: string;
ownerFlatApplication: FlatApplication;
flatObjectMetadataMaps: {
idByUniversalIdentifier: Partial<Record<string, string>>;
};
flatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
}) {
const relationFields = fieldsToSync.filter((field) =>
this.isRelationFieldManifest(field),
@@ -532,7 +558,7 @@ export class ApplicationSyncService {
for (const relation of relationFields) {
const existingRelationField = Object.values(
flatFieldMetadataMaps.byId,
flatFieldMetadataMaps.byUniversalIdentifier,
).find(
(field) =>
isDefined(field) &&
@@ -543,12 +569,12 @@ export class ApplicationSyncService {
continue;
}
const targetObjectId =
flatObjectMetadataMaps.idByUniversalIdentifier[
relation.targetObjectUniversalIdentifier
];
const targetObjectMetadata = findFlatEntityByUniversalIdentifier({
flatEntityMaps: flatObjectMetadataMaps,
universalIdentifier: relation.targetObjectUniversalIdentifier,
});
if (!isDefined(targetObjectId)) {
if (!isDefined(targetObjectMetadata)) {
throw new ApplicationException(
`Failed to find target object with universalIdentifier ${relation.targetObjectUniversalIdentifier}`,
ApplicationExceptionCode.OBJECT_NOT_FOUND,
@@ -568,7 +594,7 @@ export class ApplicationSyncService {
workspaceId,
relationCreationPayload: {
type: relation.relationType,
targetObjectMetadataId: targetObjectId,
targetObjectMetadataId: targetObjectMetadata.id,
targetFieldLabel: relation.targetFieldLabel,
targetFieldIcon: relation.targetFieldIcon ?? 'IconRelationOneToMany',
},
@@ -600,7 +626,7 @@ export class ApplicationSyncService {
);
const applicationObjects = Object.values(
existingFlatObjectMetadataMaps.byId,
existingFlatObjectMetadataMaps.byUniversalIdentifier,
).filter(
(obj) => isDefined(obj) && obj.applicationId === ownerFlatApplication.id,
// TODO handle when migrating to trinite usage
@@ -732,12 +758,12 @@ export class ApplicationSyncService {
);
for (const objectToSync of objectsToSync) {
const sourceObjectId =
flatObjectMetadataMaps.idByUniversalIdentifier[
objectToSync.universalIdentifier
];
const sourceObjectMetadata = findFlatEntityByUniversalIdentifier({
flatEntityMaps: flatObjectMetadataMaps,
universalIdentifier: objectToSync.universalIdentifier,
});
if (!isDefined(sourceObjectId)) {
if (!isDefined(sourceObjectMetadata)) {
throw new ApplicationException(
`Failed to find source object with universalIdentifier ${objectToSync.universalIdentifier}`,
ApplicationExceptionCode.OBJECT_NOT_FOUND,
@@ -745,7 +771,7 @@ export class ApplicationSyncService {
}
await this.syncObjectFieldsRelationOnly({
objectId: sourceObjectId,
objectId: sourceObjectMetadata.id,
fieldsToSync: objectToSync.fields,
workspaceId,
ownerFlatApplication,
@@ -772,12 +798,12 @@ export class ApplicationSyncService {
);
for (const fieldToSync of fieldsToSync) {
const targetObjectId =
flatObjectMetadataMaps.idByUniversalIdentifier[
fieldToSync.objectUniversalIdentifier
];
const targetObjectMetadata = findFlatEntityByUniversalIdentifier({
flatEntityMaps: flatObjectMetadataMaps,
universalIdentifier: fieldToSync.objectUniversalIdentifier,
});
if (!isDefined(targetObjectId)) {
if (!isDefined(targetObjectMetadata)) {
throw new ApplicationException(
'Object extension must specify either nameSingular or universalIdentifier in targetObject',
ApplicationExceptionCode.INVALID_INPUT,
@@ -785,14 +811,14 @@ export class ApplicationSyncService {
}
await this.syncObjectFieldsWithoutRelations({
objectId: targetObjectId,
objectId: targetObjectMetadata.id,
fieldsToSync: [fieldToSync],
workspaceId,
ownerFlatApplication,
});
await this.syncObjectFieldsRelationOnly({
objectId: targetObjectId,
objectId: targetObjectMetadata.id,
fieldsToSync: [fieldToSync],
workspaceId,
ownerFlatApplication,
@@ -823,7 +849,7 @@ export class ApplicationSyncService {
);
const applicationLogicFunctions = Object.values(
flatLogicFunctionMaps.byId,
flatLogicFunctionMaps.byUniversalIdentifier,
).filter(
(logicFunction) =>
isDefined(logicFunction) &&
@@ -42,8 +42,8 @@ const mockObjectMetadata: FlatObjectMetadata = {
};
const mockFlatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata> = {
byId: {},
idByUniversalIdentifier: {},
byUniversalIdentifier: {},
universalIdentifierById: {},
universalIdentifiersByApplicationId: {},
};
@@ -4,6 +4,7 @@ import { fastDeepEqual } from 'twenty-shared/utils';
import { STANDARD_OBJECTS } from 'twenty-shared/metadata';
import { type 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 { 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 { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
@@ -42,7 +43,12 @@ export const objectRecordChangedValues = (
return Object.keys(newRecord).reduce(
(acc, key) => {
const fieldId = fieldIdByName[key];
const field = fieldId ? flatFieldMetadataMaps.byId[fieldId] : undefined;
const field = fieldId
? findFlatEntityByIdInFlatEntityMaps({
flatEntityId: fieldId,
flatEntityMaps: flatFieldMetadataMaps,
})
: undefined;
const oldRecordValue = oldRecord[key];
const newRecordValue = newRecord[key];
@@ -15,6 +15,7 @@ import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decora
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.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 { buildObjectIdByNameMaps } from 'src/engine/metadata-modules/flat-object-metadata/utils/build-object-id-by-name-maps.util';
import { WorkspaceEventBatch } from 'src/engine/workspace-event-emitter/types/workspace-event-batch.type';
@@ -57,7 +58,10 @@ export class FilesFieldDeletionListener {
return;
}
const flatObjectMetadata = flatObjectMetadataMaps.byId[objectId];
const flatObjectMetadata = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: objectId,
flatEntityMaps: flatObjectMetadataMaps,
});
if (!isDefined(flatObjectMetadata)) {
return;
@@ -80,7 +80,7 @@ export class OpenApiService {
);
const flatObjectMetadataArray = Object.values(
flatObjectMetadataMaps.byId,
flatObjectMetadataMaps.byUniversalIdentifier,
).filter(isDefined);
flatObjectMetadataArray.sort((a, b) =>
@@ -17,10 +17,18 @@ describe('computeSchemaComponents', () => {
} as any;
const flatFieldMetadataMaps = {
byId: Object.fromEntries(
objectMetadataItemMock.fields.map((f) => [f.id, f as any]),
byUniversalIdentifier: Object.fromEntries(
objectMetadataItemMock.fields.map((f) => [
f.universalIdentifier || f.id,
f as any,
]),
),
universalIdentifierById: Object.fromEntries(
objectMetadataItemMock.fields.map((f) => [
f.id,
f.universalIdentifier || f.id,
]),
),
idByUniversalIdentifier: {},
universalIdentifiersByApplicationId: {},
};
@@ -33,11 +41,17 @@ describe('computeSchemaComponents', () => {
} as any;
const flatObjectMetadataMaps = {
byId: {
[flatObjectMetadata.id]: flatObjectMetadata,
[relationTargetObjectMetadata.id]: relationTargetObjectMetadata,
byUniversalIdentifier: {
[flatObjectMetadata.universalIdentifier as string]: flatObjectMetadata,
[relationTargetObjectMetadata.universalIdentifier as string]:
relationTargetObjectMetadata,
},
universalIdentifierById: {
[flatObjectMetadata.id]:
flatObjectMetadata.universalIdentifier as string,
[relationTargetObjectMetadata.id]:
relationTargetObjectMetadata.universalIdentifier as string,
},
idByUniversalIdentifier: {},
universalIdentifiersByApplicationId: {},
};
@@ -814,7 +828,7 @@ describe('computeSchemaComponents', () => {
Pick<
FieldMetadataEntity<FieldMetadataType.NUMBER>,
'id' | 'name' | 'type' | 'isNullable' | 'defaultValue' | 'settings'
>
> & { universalIdentifier: string }
>[] = [
{
title: 'Integer dataType with decimals',
@@ -825,6 +839,7 @@ describe('computeSchemaComponents', () => {
isNullable: false,
defaultValue: null,
settings: { type: 'number', decimals: 1, dataType: NumberDataType.INT },
universalIdentifier: 'number1',
},
},
{
@@ -836,6 +851,7 @@ describe('computeSchemaComponents', () => {
isNullable: false,
defaultValue: null,
settings: { type: 'number', dataType: NumberDataType.FLOAT },
universalIdentifier: 'number2',
},
},
{
@@ -847,6 +863,7 @@ describe('computeSchemaComponents', () => {
isNullable: false,
defaultValue: null,
settings: { type: 'number', decimals: 0, dataType: NumberDataType.INT },
universalIdentifier: 'number3',
},
},
];
@@ -862,18 +879,23 @@ describe('computeSchemaComponents', () => {
} as any;
const flatFieldMetadataMaps = {
byId: {
[field.id]: field as any,
byUniversalIdentifier: {
[field.universalIdentifier || field.id]: field as any,
},
universalIdentifierById: {
[field.id]: field.universalIdentifier || field.id,
},
idByUniversalIdentifier: {},
universalIdentifiersByApplicationId: {},
};
const flatObjectMetadataMaps = {
byId: {
[flatObjectMetadata.id]: flatObjectMetadata,
byUniversalIdentifier: {
[flatObjectMetadata.universalIdentifier as string]: flatObjectMetadata,
},
universalIdentifierById: {
[flatObjectMetadata.id]:
flatObjectMetadata.universalIdentifier as string,
},
idByUniversalIdentifier: {},
universalIdentifiersByApplicationId: {},
};
@@ -25,6 +25,7 @@ import {
computeViewIdParameters,
} from 'src/engine/core-modules/open-api/utils/parameters.utils';
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-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 { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-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 { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
@@ -105,8 +106,10 @@ const getSchemaComponentsRelationProperties = (
let itemProperty = {} as Property;
if (isFieldMetadataEntityOfType(field, FieldMetadataType.RELATION)) {
const targetObjectMetadata =
flatObjectMetadataMaps.byId[field.relationTargetObjectMetadataId];
const targetObjectMetadata = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: field.relationTargetObjectMetadataId,
flatEntityMaps: flatObjectMetadataMaps,
});
if (!targetObjectMetadata) {
return node;
@@ -16,6 +16,7 @@ import {
RecordCrudExceptionCode,
} from 'src/engine/core-modules/record-crud/exceptions/record-crud.exception';
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 { 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';
@@ -77,7 +78,10 @@ export class CommonApiContextBuilderService {
);
}
const flatObjectMetadata = flatObjectMetadataMaps.byId[objectId];
const flatObjectMetadata = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: objectId,
flatEntityMaps: flatObjectMetadataMaps,
});
if (!isDefined(flatObjectMetadata)) {
throw new RecordCrudException(
@@ -12,6 +12,7 @@ import { transformLinksValue } from 'src/engine/core-modules/record-transformer/
import { transformPhonesValue } from 'src/engine/core-modules/record-transformer/utils/transform-phones-value.util';
import { transformRichTextV2Value } from 'src/engine/core-modules/record-transformer/utils/transform-rich-text-v2.util';
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 { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
@@ -37,7 +38,10 @@ export class RecordInputTransformerService {
for (const [key, value] of Object.entries(recordInput)) {
const fieldMetadataId = fieldIdByName[key];
const fieldMetadata = fieldMetadataId
? flatFieldMetadataMaps.byId[fieldMetadataId]
? findFlatEntityByIdInFlatEntityMaps({
flatEntityId: fieldMetadataId,
flatEntityMaps: flatFieldMetadataMaps,
})
: undefined;
if (!fieldMetadata) {
@@ -57,7 +57,7 @@ export class SearchResolver {
);
const flatObjectMetadatas = Object.values(
flatObjectMetadataMaps.byId,
flatObjectMetadataMaps.byUniversalIdentifier,
).filter(isDefined);
const filteredObjectMetadataItems =
@@ -26,6 +26,7 @@ import {
} from 'src/engine/core-modules/search/exceptions/search.exception';
import { type RecordsWithObjectMetadataItem } from 'src/engine/core-modules/search/types/records-with-object-metadata-item';
import { formatSearchTerms } from 'src/engine/core-modules/search/utils/format-search-terms';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.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 { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
@@ -308,10 +309,10 @@ export class SearchService {
);
}
const labelIdentifierField =
flatFieldMetadataMaps.byId[
flatObjectMetadata.labelIdentifierFieldMetadataId
];
const labelIdentifierField = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: flatObjectMetadata.labelIdentifierFieldMetadataId,
flatEntityMaps: flatFieldMetadataMaps,
});
if (!isDefined(labelIdentifierField)) {
throw new SearchException(
@@ -355,10 +356,10 @@ export class SearchService {
return null;
}
const imageIdentifierField =
flatFieldMetadataMaps.byId[
flatObjectMetadata.imageIdentifierFieldMetadataId
];
const imageIdentifierField = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: flatObjectMetadata.imageIdentifierFieldMetadataId,
flatEntityMaps: flatFieldMetadataMaps,
});
if (!isDefined(imageIdentifierField)) {
return null;
@@ -90,7 +90,9 @@ export class PerObjectToolGeneratorService {
},
);
const allFlatObjects = Object.values(flatObjectMetadataMaps.byId)
const allFlatObjects = Object.values(
flatObjectMetadataMaps.byUniversalIdentifier,
)
.filter(isDefined)
.filter((obj) => obj.isActive && !obj.isSystem);
@@ -123,7 +123,9 @@ export class DatabaseToolProvider implements ToolProvider {
},
);
const allFlatObjects = Object.values(flatObjectMetadataMaps.byId)
const allFlatObjects = Object.values(
flatObjectMetadataMaps.byUniversalIdentifier,
)
.filter(isDefined)
.filter((obj) => obj.isActive && !obj.isSystem);
@@ -39,7 +39,7 @@ export class LogicFunctionToolProvider implements ToolProvider {
// Filter logic functions that are marked as tools
const logicFunctionsWithSchema = Object.values(
flatLogicFunctionMaps.byId,
flatLogicFunctionMaps.byUniversalIdentifier,
).filter(
(fn): fn is FlatLogicFunction =>
isDefined(fn) && fn.isTool === true && fn.deletedAt === null,
@@ -420,7 +420,9 @@ export class WorkspaceService extends TypeOrmQueryService<WorkspaceEntity> {
},
);
const fields = Object.values(flatFieldMetadataMaps.byId).filter(isDefined);
const fields = Object.values(
flatFieldMetadataMaps.byUniversalIdentifier,
).filter(isDefined);
if (fields.length === 0) {
return 0;