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:
+13
-7
@@ -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: {},
|
||||
};
|
||||
|
||||
+19
-15
@@ -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(
|
||||
|
||||
+17
-5
@@ -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: {},
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
+5
-1
@@ -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
|
||||
|
||||
+69
-43
@@ -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) &&
|
||||
|
||||
+2
-2
@@ -42,8 +42,8 @@ const mockObjectMetadata: FlatObjectMetadata = {
|
||||
};
|
||||
|
||||
const mockFlatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata> = {
|
||||
byId: {},
|
||||
idByUniversalIdentifier: {},
|
||||
byUniversalIdentifier: {},
|
||||
universalIdentifierById: {},
|
||||
universalIdentifiersByApplicationId: {},
|
||||
};
|
||||
|
||||
|
||||
+7
-1
@@ -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];
|
||||
|
||||
+5
-1
@@ -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) =>
|
||||
|
||||
+36
-14
@@ -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;
|
||||
|
||||
+5
-1
@@ -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(
|
||||
|
||||
+5
-1
@@ -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;
|
||||
|
||||
+3
-1
@@ -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);
|
||||
|
||||
|
||||
+3
-1
@@ -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);
|
||||
|
||||
|
||||
+1
-1
@@ -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,
|
||||
|
||||
+3
-1
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user