Factorize from entity to flat entity utils (#21972)

## What

Factorizes the two responsibilities that were copy‑pasted across every
`from-<entity>-entity-to-flat-<entity>` util into two reusable tools.

### `fromEntityToScalarEntity`
Projects a TypeORM entity into its scalar flat shape using an
**allow‑list** driven by
`ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME` (plus the base
columns `id`/`workspaceId`/`applicationId`/`universalIdentifier`). Only
registered scalar columns are forwarded, `Date`s are serialized to ISO
strings, and absent values are normalized to `null`. Replaces the
previous deny‑list (`removePropertiesFromRecord`) approach, so
unregistered/deprecated columns can no longer silently leak into the
flat entity.

### `resolveManyToOneRelationIdsToUniversalIdentifiers`
Resolves an entity's many‑to‑one foreign keys to their universal
identifiers, driven by `ALL_MANY_TO_ONE_METADATA_RELATIONS`. Handles the
always‑present `application`, nullable relations, and throws a
`FlatEntityMapsException` when a referenced id is missing from its
identifier map. Mirrors `resolveUniversalRelationIdentifiersToIds` in
the opposite direction.

Each `from-<entity>` util now reduces to: scalar spread + relation
spread (+ explicit one‑to‑many id/universalIdentifier arrays where
applicable).

### Note
The allow‑list drops `isUIReadOnly` (a `WasRemovedInUpgrade` column not
in the config) from `fieldMetadata`, which is the only
integration‑snapshot change.

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21972?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
This commit is contained in:
Paul Rastoin
2026-06-24 12:20:09 +02:00
committed by GitHub
parent 41d1b478b0
commit d2387430a1
34 changed files with 1106 additions and 1614 deletions
@@ -1,39 +1,26 @@
import { isDefined } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatApplicationVariable } from 'src/engine/metadata-modules/flat-application-variable/types/flat-application-variable.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromApplicationVariableEntityToFlatApplicationVariable = ({
entity: applicationVariableEntity,
applicationIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'applicationVariable'>): FlatApplicationVariable => {
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
applicationVariableEntity.applicationId,
);
export const fromApplicationVariableEntityToFlatApplicationVariable = (
args: FromEntityToFlatEntityArgs<'applicationVariable'>,
): FlatApplicationVariable => {
const { entity: applicationVariableEntity } = args;
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${applicationVariableEntity.applicationId} not found for applicationVariable ${applicationVariableEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const applicationVariableScalarEntity = fromEntityToScalarEntity({
metadataName: 'applicationVariable',
entity: applicationVariableEntity,
});
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'applicationVariable',
...args,
});
return {
id: applicationVariableEntity.id,
key: applicationVariableEntity.key,
value: applicationVariableEntity.value,
description: applicationVariableEntity.description,
isSecret: applicationVariableEntity.isSecret,
workspaceId: applicationVariableEntity.workspaceId,
universalIdentifier: applicationVariableEntity.universalIdentifier,
applicationId: applicationVariableEntity.applicationId,
createdAt: applicationVariableEntity.createdAt.toISOString(),
updatedAt: applicationVariableEntity.updatedAt.toISOString(),
applicationUniversalIdentifier,
...applicationVariableScalarEntity,
...relationUniversalIdentifiers,
};
};
@@ -1,79 +1,30 @@
import { isDefined } from 'twenty-shared/utils';
import { fromCommandMenuItemOverridesToUniversalOverrides } from 'src/engine/metadata-modules/flat-command-menu-item/utils/from-command-menu-item-overrides-to-universal-overrides.util';
import { type FlatCommandMenuItem } from 'src/engine/metadata-modules/flat-command-menu-item/types/flat-command-menu-item.type';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { fromCommandMenuItemOverridesToUniversalOverrides } from 'src/engine/metadata-modules/flat-command-menu-item/utils/from-command-menu-item-overrides-to-universal-overrides.util';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromCommandMenuItemEntityToFlatCommandMenuItem = ({
entity: commandMenuItemEntity,
applicationIdToUniversalIdentifierMap,
objectMetadataIdToUniversalIdentifierMap,
frontComponentIdToUniversalIdentifierMap,
pageLayoutIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'commandMenuItem'>): FlatCommandMenuItem => {
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
commandMenuItemEntity.applicationId,
);
export const fromCommandMenuItemEntityToFlatCommandMenuItem = (
args: FromEntityToFlatEntityArgs<'commandMenuItem'>,
): FlatCommandMenuItem => {
const {
entity: commandMenuItemEntity,
objectMetadataIdToUniversalIdentifierMap,
pageLayoutIdToUniversalIdentifierMap,
} = args;
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${commandMenuItemEntity.applicationId} not found for commandMenuItem ${commandMenuItemEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const commandMenuItemScalarEntity = fromEntityToScalarEntity({
metadataName: 'commandMenuItem',
entity: commandMenuItemEntity,
});
let availabilityObjectMetadataUniversalIdentifier: string | null = null;
if (isDefined(commandMenuItemEntity.availabilityObjectMetadataId)) {
availabilityObjectMetadataUniversalIdentifier =
objectMetadataIdToUniversalIdentifierMap.get(
commandMenuItemEntity.availabilityObjectMetadataId,
) ?? null;
if (!isDefined(availabilityObjectMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`ObjectMetadata with id ${commandMenuItemEntity.availabilityObjectMetadataId} not found for commandMenuItem ${commandMenuItemEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
let frontComponentUniversalIdentifier: string | null = null;
if (isDefined(commandMenuItemEntity.frontComponentId)) {
frontComponentUniversalIdentifier =
frontComponentIdToUniversalIdentifierMap.get(
commandMenuItemEntity.frontComponentId,
) ?? null;
if (!isDefined(frontComponentUniversalIdentifier)) {
throw new FlatEntityMapsException(
`FrontComponent with id ${commandMenuItemEntity.frontComponentId} not found for commandMenuItem ${commandMenuItemEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
let pageLayoutUniversalIdentifier: string | null = null;
if (isDefined(commandMenuItemEntity.pageLayoutId)) {
pageLayoutUniversalIdentifier =
pageLayoutIdToUniversalIdentifierMap.get(
commandMenuItemEntity.pageLayoutId,
) ?? null;
if (!isDefined(pageLayoutUniversalIdentifier)) {
throw new FlatEntityMapsException(
`PageLayout with id ${commandMenuItemEntity.pageLayoutId} not found for commandMenuItem ${commandMenuItemEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'commandMenuItem',
...args,
});
const universalOverrides = isDefined(commandMenuItemEntity.overrides)
? fromCommandMenuItemOverridesToUniversalOverrides({
@@ -89,35 +40,8 @@ export const fromCommandMenuItemEntityToFlatCommandMenuItem = ({
: null;
return {
id: commandMenuItemEntity.id,
workflowVersionId: commandMenuItemEntity.workflowVersionId,
frontComponentId: commandMenuItemEntity.frontComponentId,
engineComponentKey: commandMenuItemEntity.engineComponentKey,
label: commandMenuItemEntity.label,
icon: commandMenuItemEntity.icon,
shortLabel: commandMenuItemEntity.shortLabel,
position: commandMenuItemEntity.position,
isPinned: commandMenuItemEntity.isPinned,
payload: commandMenuItemEntity.payload,
hotKeys: commandMenuItemEntity.hotKeys,
availabilityType: commandMenuItemEntity.availabilityType,
availabilityObjectMetadataId:
commandMenuItemEntity.availabilityObjectMetadataId,
workspaceId: commandMenuItemEntity.workspaceId,
universalIdentifier: commandMenuItemEntity.universalIdentifier,
applicationId: commandMenuItemEntity.applicationId,
createdAt: commandMenuItemEntity.createdAt.toISOString(),
updatedAt: commandMenuItemEntity.updatedAt.toISOString(),
applicationUniversalIdentifier,
conditionalAvailabilityExpression:
commandMenuItemEntity.conditionalAvailabilityExpression,
availabilityObjectMetadataUniversalIdentifier,
frontComponentUniversalIdentifier,
pageLayoutId: commandMenuItemEntity.pageLayoutId,
pageLayoutUniversalIdentifier,
isActive: commandMenuItemEntity.isActive,
isSystemSideEffect: commandMenuItemEntity.isSystemSideEffect,
overrides: commandMenuItemEntity.overrides,
...commandMenuItemScalarEntity,
...relationUniversalIdentifiers,
universalOverrides,
};
};
@@ -1,39 +1,26 @@
import { isDefined } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatConnectionProvider } from 'src/engine/metadata-modules/flat-connection-provider/types/flat-connection-provider.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromConnectionProviderEntityToFlatConnectionProvider = ({
entity: connectionProviderEntity,
applicationIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'connectionProvider'>): FlatConnectionProvider => {
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
connectionProviderEntity.applicationId,
);
export const fromConnectionProviderEntityToFlatConnectionProvider = (
args: FromEntityToFlatEntityArgs<'connectionProvider'>,
): FlatConnectionProvider => {
const { entity: connectionProviderEntity } = args;
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${connectionProviderEntity.applicationId} not found for connection provider ${connectionProviderEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const connectionProviderScalarEntity = fromEntityToScalarEntity({
metadataName: 'connectionProvider',
entity: connectionProviderEntity,
});
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'connectionProvider',
...args,
});
return {
id: connectionProviderEntity.id,
universalIdentifier: connectionProviderEntity.universalIdentifier,
applicationId: connectionProviderEntity.applicationId,
workspaceId: connectionProviderEntity.workspaceId,
name: connectionProviderEntity.name,
displayName: connectionProviderEntity.displayName,
type: connectionProviderEntity.type,
oauthConfig: connectionProviderEntity.oauthConfig,
createdAt: connectionProviderEntity.createdAt.toISOString(),
updatedAt: connectionProviderEntity.updatedAt.toISOString(),
applicationUniversalIdentifier,
...connectionProviderScalarEntity,
...relationUniversalIdentifiers,
};
};
@@ -0,0 +1,183 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type MetadataEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-entity.type';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type EntityWithRegroupedOneToManyRelations } from 'src/engine/workspace-cache/types/entity-with-regrouped-one-to-many-relations.type';
const buildArgs = <T extends AllMetadataName>(
metadataName: T,
entity: Record<string, unknown>,
): {
metadataName: T;
entity: EntityWithRegroupedOneToManyRelations<MetadataEntity<T>>;
} => ({
metadataName,
entity: entity as unknown as EntityWithRegroupedOneToManyRelations<
MetadataEntity<T>
>,
});
describe('fromEntityToScalarEntity', () => {
it('should return the registered scalar properties along with the base columns', () => {
const result = fromEntityToScalarEntity(
buildArgs('permissionFlag', {
id: 'permission-flag-id-1',
workspaceId: 'workspace-id-1',
applicationId: 'app-id-1',
universalIdentifier: 'permission-flag-ui-1',
key: 'IMPERSONATE',
label: 'Impersonate',
description: 'Allows impersonation',
icon: 'IconUser',
permissionType: 'WORKSPACE',
createdAt: new Date('2024-01-01T00:00:00.000Z'),
updatedAt: new Date('2024-01-02T00:00:00.000Z'),
}),
);
expect(result).toEqual({
id: 'permission-flag-id-1',
workspaceId: 'workspace-id-1',
applicationId: 'app-id-1',
universalIdentifier: 'permission-flag-ui-1',
key: 'IMPERSONATE',
label: 'Impersonate',
description: 'Allows impersonation',
icon: 'IconUser',
permissionType: 'WORKSPACE',
createdAt: '2024-01-01T00:00:00.000Z',
updatedAt: '2024-01-02T00:00:00.000Z',
});
});
it('should drop relation objects, regrouped one-to-many arrays and any unregistered property', () => {
const result = fromEntityToScalarEntity(
buildArgs('permissionFlag', {
id: 'permission-flag-id-1',
workspaceId: 'workspace-id-1',
applicationId: 'app-id-1',
universalIdentifier: 'permission-flag-ui-1',
key: 'IMPERSONATE',
label: 'Impersonate',
description: 'Allows impersonation',
icon: 'IconUser',
permissionType: 'WORKSPACE',
createdAt: new Date('2024-01-01T00:00:00.000Z'),
updatedAt: new Date('2024-01-02T00:00:00.000Z'),
workspace: { id: 'workspace-id-1' },
application: { id: 'app-id-1' },
rolePermissionFlags: [{ id: 'role-permission-flag-id-1' }],
someTransientProperty: 'should-not-leak',
}),
);
expect(Object.keys(result).sort()).toEqual(
[
'id',
'workspaceId',
'applicationId',
'universalIdentifier',
'key',
'label',
'description',
'icon',
'permissionType',
'createdAt',
'updatedAt',
].sort(),
);
expect(result).not.toHaveProperty('workspace');
expect(result).not.toHaveProperty('application');
expect(result).not.toHaveProperty('rolePermissionFlags');
expect(result).not.toHaveProperty('someTransientProperty');
});
it('should keep many-to-one foreign key columns while dropping their relation objects', () => {
const result = fromEntityToScalarEntity(
buildArgs('viewSort', {
id: 'view-sort-id-1',
workspaceId: 'workspace-id-1',
applicationId: 'app-id-1',
universalIdentifier: 'view-sort-ui-1',
direction: 'ASC',
subFieldName: null,
fieldMetadataId: 'field-id-1',
viewId: 'view-id-1',
createdAt: new Date('2024-01-01T00:00:00.000Z'),
updatedAt: new Date('2024-01-02T00:00:00.000Z'),
deletedAt: null,
fieldMetadata: { id: 'field-id-1' },
view: { id: 'view-id-1' },
}),
);
expect(result.fieldMetadataId).toBe('field-id-1');
expect(result.viewId).toBe('view-id-1');
expect(result).not.toHaveProperty('fieldMetadata');
expect(result).not.toHaveProperty('view');
});
it('should serialize Date columns to ISO strings while leaving null dates untouched', () => {
const result = fromEntityToScalarEntity(
buildArgs('viewSort', {
id: 'view-sort-id-1',
workspaceId: 'workspace-id-1',
applicationId: 'app-id-1',
universalIdentifier: 'view-sort-ui-1',
direction: 'ASC',
subFieldName: null,
fieldMetadataId: 'field-id-1',
viewId: 'view-id-1',
createdAt: new Date('2024-01-01T00:00:00.000Z'),
updatedAt: new Date('2024-01-02T00:00:00.000Z'),
deletedAt: null,
}),
);
expect(result.createdAt).toBe('2024-01-01T00:00:00.000Z');
expect(result.updatedAt).toBe('2024-01-02T00:00:00.000Z');
expect(result.deletedAt).toBeNull();
});
it('should normalize absent properties to null instead of undefined', () => {
const result = fromEntityToScalarEntity(
buildArgs('permissionFlag', {
id: 'permission-flag-id-1',
key: 'IMPERSONATE',
label: 'Impersonate',
description: 'Allows impersonation',
icon: 'IconUser',
permissionType: 'WORKSPACE',
createdAt: new Date('2024-01-01T00:00:00.000Z'),
updatedAt: new Date('2024-01-02T00:00:00.000Z'),
}),
);
expect(result).toHaveProperty('workspaceId', null);
expect(result).toHaveProperty('applicationId', null);
expect(result).toHaveProperty('universalIdentifier', null);
expect(Object.values(result)).not.toContain(undefined);
});
it('should keep explicit null values and normalize undefined ones to null', () => {
const result = fromEntityToScalarEntity(
buildArgs('viewSort', {
id: 'view-sort-id-1',
workspaceId: 'workspace-id-1',
applicationId: null,
universalIdentifier: 'view-sort-ui-1',
direction: 'ASC',
subFieldName: null,
fieldMetadataId: 'field-id-1',
viewId: 'view-id-1',
createdAt: new Date('2024-01-01T00:00:00.000Z'),
updatedAt: new Date('2024-01-02T00:00:00.000Z'),
deletedAt: undefined,
}),
);
expect(result).toHaveProperty('applicationId', null);
expect(result).toHaveProperty('subFieldName', null);
expect(result).toHaveProperty('deletedAt', null);
});
});
@@ -0,0 +1,54 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME } from 'src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant';
import { type MetadataEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-entity.type';
import { type ScalarFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/scalar-flat-entity.type';
import { type EntityWithRegroupedOneToManyRelations } from 'src/engine/workspace-cache/types/entity-with-regrouped-one-to-many-relations.type';
const serializeScalarValue = (value: unknown): unknown => {
if (value instanceof Date) {
return value.toISOString();
}
return value ?? null;
};
const BASE_SCALAR_PROPERTY_NAMES = [
'id',
'workspaceId',
'applicationId',
'universalIdentifier',
] as const;
// Allow-list counterpart to removePropertiesFromRecord: rather than forwarding
// every entity property except the known relations (deny-list), this forwards only
// the scalar columns registered in
// ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME plus the always-present base
// columns, serialized into their flat (ScalarFlatEntity) shape. Anything unexpected
// on the entity instance is dropped, so a flat entity can never silently leak an
// unregistered property. Absent values are normalized to `null` so the output always
// has a stable key shape and never an `undefined` value.
export const fromEntityToScalarEntity = <T extends AllMetadataName>({
metadataName,
entity,
}: {
metadataName: T;
entity: EntityWithRegroupedOneToManyRelations<MetadataEntity<T>>;
}): ScalarFlatEntity<MetadataEntity<T>> => {
const propertiesConfiguration =
ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME[metadataName];
const entityRecord = entity as Record<string, unknown>;
const scalarProperties: Record<string, unknown> = {};
for (const propertyName of [
...BASE_SCALAR_PROPERTY_NAMES,
...Object.keys(propertiesConfiguration),
]) {
scalarProperties[propertyName] = serializeScalarValue(
entityRecord[propertyName],
);
}
return scalarProperties as ScalarFlatEntity<MetadataEntity<T>>;
};
@@ -1,80 +1,30 @@
import { FieldMetadataType } from 'twenty-shared/types';
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import { isDefined } from 'twenty-shared/utils';
import { isFieldMetadataSettingsOfType } from 'src/engine/metadata-modules/field-metadata/utils/is-field-metadata-settings-of-type.util';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromFieldMetadataEntityToFlatFieldMetadata = ({
entity: fieldMetadataEntity,
fieldMetadataIdToUniversalIdentifierMap,
objectMetadataIdToUniversalIdentifierMap,
applicationIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'fieldMetadata'>): FlatFieldMetadata => {
const fieldMetadataWithoutRelations = removePropertiesFromRecord(
fieldMetadataEntity,
getMetadataEntityRelationProperties('fieldMetadata'),
);
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
fieldMetadataEntity.applicationId,
);
export const fromFieldMetadataEntityToFlatFieldMetadata = (
args: FromEntityToFlatEntityArgs<'fieldMetadata'>,
): FlatFieldMetadata => {
const {
entity: fieldMetadataEntity,
fieldMetadataIdToUniversalIdentifierMap,
} = args;
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${fieldMetadataEntity.applicationId} not found when building flat field metadata for field ${fieldMetadataEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const fieldMetadataScalarEntity = fromEntityToScalarEntity({
metadataName: 'fieldMetadata',
entity: fieldMetadataEntity,
});
const objectMetadataUniversalIdentifier =
objectMetadataIdToUniversalIdentifierMap.get(
fieldMetadataEntity.objectMetadataId,
);
if (!isDefined(objectMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Object metadata with id ${fieldMetadataEntity.objectMetadataId} not found when building flat field metadata for field ${fieldMetadataEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
let relationTargetObjectMetadataUniversalIdentifier: string | null = null;
if (isDefined(fieldMetadataEntity.relationTargetObjectMetadataId)) {
relationTargetObjectMetadataUniversalIdentifier =
objectMetadataIdToUniversalIdentifierMap.get(
fieldMetadataEntity.relationTargetObjectMetadataId,
) ?? null;
if (!isDefined(relationTargetObjectMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Relation target object metadata with id ${fieldMetadataEntity.relationTargetObjectMetadataId} not found when building flat field metadata for field ${fieldMetadataEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
let relationTargetFieldMetadataUniversalIdentifier: string | null = null;
if (isDefined(fieldMetadataEntity.relationTargetFieldMetadataId)) {
relationTargetFieldMetadataUniversalIdentifier =
fieldMetadataIdToUniversalIdentifierMap.get(
fieldMetadataEntity.relationTargetFieldMetadataId,
) ?? null;
if (!isDefined(relationTargetFieldMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Relation target field metadata with id ${fieldMetadataEntity.relationTargetFieldMetadataId} not found when building flat field metadata for field ${fieldMetadataEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'fieldMetadata',
...args,
});
const settings = fieldMetadataEntity.settings;
const isRelationSettings =
@@ -94,10 +44,8 @@ export const fromFieldMetadataEntityToFlatFieldMetadata = ({
: settings;
return {
...fieldMetadataWithoutRelations,
universalIdentifier: fieldMetadataWithoutRelations.universalIdentifier,
createdAt: fieldMetadataWithoutRelations.createdAt.toISOString(),
updatedAt: fieldMetadataWithoutRelations.updatedAt.toISOString(),
...fieldMetadataScalarEntity,
...relationUniversalIdentifiers,
kanbanAggregateOperationViewIds:
fieldMetadataEntity.kanbanAggregateOperationViews.map(({ id }) => id),
calendarViewIds: fieldMetadataEntity.calendarViews.map(({ id }) => id),
@@ -108,10 +56,6 @@ export const fromFieldMetadataEntityToFlatFieldMetadata = ({
viewFilterIds: fieldMetadataEntity.viewFilters.map(({ id }) => id),
fieldPermissionIds:
fieldMetadataEntity.fieldPermissions?.map(({ id }) => id) ?? [],
applicationUniversalIdentifier,
objectMetadataUniversalIdentifier,
relationTargetObjectMetadataUniversalIdentifier,
relationTargetFieldMetadataUniversalIdentifier,
viewFieldUniversalIdentifiers: fieldMetadataEntity.viewFields.map(
({ universalIdentifier }) => universalIdentifier,
),
@@ -1,81 +1,26 @@
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatFieldPermission } from 'src/engine/metadata-modules/flat-field-permission/types/flat-field-permission.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromFieldPermissionEntityToFlatFieldPermission = ({
entity: fieldPermissionEntity,
applicationIdToUniversalIdentifierMap,
roleIdToUniversalIdentifierMap,
objectMetadataIdToUniversalIdentifierMap,
fieldMetadataIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'fieldPermission'>): FlatFieldPermission => {
const fieldPermissionEntityWithoutRelations = removePropertiesFromRecord(
fieldPermissionEntity,
getMetadataEntityRelationProperties('fieldPermission'),
);
export const fromFieldPermissionEntityToFlatFieldPermission = (
args: FromEntityToFlatEntityArgs<'fieldPermission'>,
): FlatFieldPermission => {
const { entity: fieldPermissionEntity } = args;
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
fieldPermissionEntity.applicationId,
);
const fieldPermissionScalarEntity = fromEntityToScalarEntity({
metadataName: 'fieldPermission',
entity: fieldPermissionEntity,
});
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${fieldPermissionEntity.applicationId} not found for fieldPermission ${fieldPermissionEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const roleUniversalIdentifier = roleIdToUniversalIdentifierMap.get(
fieldPermissionEntity.roleId,
);
if (!isDefined(roleUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Role with id ${fieldPermissionEntity.roleId} not found for fieldPermission ${fieldPermissionEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const objectMetadataUniversalIdentifier =
objectMetadataIdToUniversalIdentifierMap.get(
fieldPermissionEntity.objectMetadataId,
);
if (!isDefined(objectMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`ObjectMetadata with id ${fieldPermissionEntity.objectMetadataId} not found for fieldPermission ${fieldPermissionEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const fieldMetadataUniversalIdentifier =
fieldMetadataIdToUniversalIdentifierMap.get(
fieldPermissionEntity.fieldMetadataId,
);
if (!isDefined(fieldMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`FieldMetadata with id ${fieldPermissionEntity.fieldMetadataId} not found for fieldPermission ${fieldPermissionEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'fieldPermission',
...args,
});
return {
...fieldPermissionEntityWithoutRelations,
createdAt: fieldPermissionEntity.createdAt.toISOString(),
updatedAt: fieldPermissionEntity.updatedAt.toISOString(),
universalIdentifier:
fieldPermissionEntityWithoutRelations.universalIdentifier,
applicationUniversalIdentifier,
roleUniversalIdentifier,
objectMetadataUniversalIdentifier,
fieldMetadataUniversalIdentifier,
...fieldPermissionScalarEntity,
...relationUniversalIdentifiers,
};
};
@@ -1,43 +1,26 @@
import { isDefined } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatFrontComponent } from 'src/engine/metadata-modules/flat-front-component/types/flat-front-component.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromFrontComponentEntityToFlatFrontComponent = ({
entity: frontComponentEntity,
applicationIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'frontComponent'>): FlatFrontComponent => {
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
frontComponentEntity.applicationId,
);
export const fromFrontComponentEntityToFlatFrontComponent = (
args: FromEntityToFlatEntityArgs<'frontComponent'>,
): FlatFrontComponent => {
const { entity: frontComponentEntity } = args;
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${frontComponentEntity.applicationId} not found for frontComponent ${frontComponentEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const frontComponentScalarEntity = fromEntityToScalarEntity({
metadataName: 'frontComponent',
entity: frontComponentEntity,
});
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'frontComponent',
...args,
});
return {
id: frontComponentEntity.id,
name: frontComponentEntity.name,
description: frontComponentEntity.description,
sourceComponentPath: frontComponentEntity.sourceComponentPath,
builtComponentPath: frontComponentEntity.builtComponentPath,
componentName: frontComponentEntity.componentName,
builtComponentChecksum: frontComponentEntity.builtComponentChecksum,
isHeadless: frontComponentEntity.isHeadless,
usesSdkClient: frontComponentEntity.usesSdkClient,
workspaceId: frontComponentEntity.workspaceId,
universalIdentifier: frontComponentEntity.universalIdentifier,
applicationId: frontComponentEntity.applicationId,
createdAt: frontComponentEntity.createdAt.toISOString(),
updatedAt: frontComponentEntity.updatedAt.toISOString(),
applicationUniversalIdentifier,
...frontComponentScalarEntity,
...relationUniversalIdentifiers,
};
};
@@ -4,53 +4,38 @@ import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromIndexMetadataEntityToFlatIndexMetadata = ({
entity: indexMetadataEntity,
applicationIdToUniversalIdentifierMap,
objectMetadataIdToUniversalIdentifierMap,
fieldMetadataIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'index'> & {
fieldMetadataIdToUniversalIdentifierMap: Map<string, string>;
}): FlatIndexMetadata => {
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
indexMetadataEntity.applicationId,
);
type FromIndexMetadataEntityToFlatIndexMetadataArgs =
FromEntityToFlatEntityArgs<'index'> & {
fieldMetadataIdToUniversalIdentifierMap: Map<string, string>;
};
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${indexMetadataEntity.applicationId} not found for index ${indexMetadataEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
export const fromIndexMetadataEntityToFlatIndexMetadata = (
args: FromIndexMetadataEntityToFlatIndexMetadataArgs,
): FlatIndexMetadata => {
const {
entity: indexMetadataEntity,
fieldMetadataIdToUniversalIdentifierMap,
} = args;
const objectMetadataUniversalIdentifier =
objectMetadataIdToUniversalIdentifierMap.get(
indexMetadataEntity.objectMetadataId,
);
const indexMetadataScalarEntity = fromEntityToScalarEntity({
metadataName: 'index',
entity: indexMetadataEntity,
});
if (!isDefined(objectMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`ObjectMetadata with id ${indexMetadataEntity.objectMetadataId} not found for index ${indexMetadataEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const indexMetadataEntityWithoutRelations = removePropertiesFromRecord(
indexMetadataEntity,
getMetadataEntityRelationProperties('index'),
);
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'index',
...args,
});
return {
...indexMetadataEntityWithoutRelations,
createdAt: indexMetadataEntity.createdAt.toISOString(),
updatedAt: indexMetadataEntity.updatedAt.toISOString(),
universalIdentifier:
indexMetadataEntityWithoutRelations.universalIdentifier,
...indexMetadataScalarEntity,
...relationUniversalIdentifiers,
flatIndexFieldMetadatas: indexMetadataEntity.indexFieldMetadatas.map(
(indexFieldMetadata) => ({
...removePropertiesFromRecord(indexFieldMetadata, [
@@ -86,7 +71,5 @@ export const fromIndexMetadataEntityToFlatIndexMetadata = ({
fieldMetadataUniversalIdentifier,
};
}),
applicationUniversalIdentifier,
objectMetadataUniversalIdentifier,
};
};
@@ -1,118 +1,26 @@
import { isDefined } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatNavigationMenuItem } from 'src/engine/metadata-modules/flat-navigation-menu-item/types/flat-navigation-menu-item.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromNavigationMenuItemEntityToFlatNavigationMenuItem = ({
entity: navigationMenuItemEntity,
applicationIdToUniversalIdentifierMap,
objectMetadataIdToUniversalIdentifierMap,
navigationMenuItemIdToUniversalIdentifierMap,
viewIdToUniversalIdentifierMap,
pageLayoutIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'navigationMenuItem'>): FlatNavigationMenuItem => {
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
navigationMenuItemEntity.applicationId,
);
export const fromNavigationMenuItemEntityToFlatNavigationMenuItem = (
args: FromEntityToFlatEntityArgs<'navigationMenuItem'>,
): FlatNavigationMenuItem => {
const { entity: navigationMenuItemEntity } = args;
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${navigationMenuItemEntity.applicationId} not found for navigationMenuItem ${navigationMenuItemEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const navigationMenuItemScalarEntity = fromEntityToScalarEntity({
metadataName: 'navigationMenuItem',
entity: navigationMenuItemEntity,
});
let targetObjectMetadataUniversalIdentifier: string | null = null;
if (isDefined(navigationMenuItemEntity.targetObjectMetadataId)) {
targetObjectMetadataUniversalIdentifier =
objectMetadataIdToUniversalIdentifierMap.get(
navigationMenuItemEntity.targetObjectMetadataId,
) ?? null;
if (!isDefined(targetObjectMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`ObjectMetadata with id ${navigationMenuItemEntity.targetObjectMetadataId} not found for navigationMenuItem ${navigationMenuItemEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
let folderUniversalIdentifier: string | null = null;
if (isDefined(navigationMenuItemEntity.folderId)) {
folderUniversalIdentifier =
navigationMenuItemIdToUniversalIdentifierMap.get(
navigationMenuItemEntity.folderId,
) ?? null;
if (!isDefined(folderUniversalIdentifier)) {
throw new FlatEntityMapsException(
`NavigationMenuItem (folder) with id ${navigationMenuItemEntity.folderId} not found for navigationMenuItem ${navigationMenuItemEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
let viewUniversalIdentifier: string | null = null;
if (isDefined(navigationMenuItemEntity.viewId)) {
viewUniversalIdentifier =
viewIdToUniversalIdentifierMap.get(navigationMenuItemEntity.viewId) ??
null;
if (!isDefined(viewUniversalIdentifier)) {
throw new FlatEntityMapsException(
`View with id ${navigationMenuItemEntity.viewId} not found for navigationMenuItem ${navigationMenuItemEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
let pageLayoutUniversalIdentifier: string | null = null;
if (isDefined(navigationMenuItemEntity.pageLayoutId)) {
pageLayoutUniversalIdentifier =
pageLayoutIdToUniversalIdentifierMap.get(
navigationMenuItemEntity.pageLayoutId,
) ?? null;
if (!isDefined(pageLayoutUniversalIdentifier)) {
throw new FlatEntityMapsException(
`PageLayout with id ${navigationMenuItemEntity.pageLayoutId} not found for navigationMenuItem ${navigationMenuItemEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'navigationMenuItem',
...args,
});
return {
id: navigationMenuItemEntity.id,
type: navigationMenuItemEntity.type,
userWorkspaceId: navigationMenuItemEntity.userWorkspaceId,
targetRecordId: navigationMenuItemEntity.targetRecordId,
targetObjectMetadataId: navigationMenuItemEntity.targetObjectMetadataId,
viewId: navigationMenuItemEntity.viewId,
folderId: navigationMenuItemEntity.folderId,
name: navigationMenuItemEntity.name,
link: navigationMenuItemEntity.link,
icon: navigationMenuItemEntity.icon,
color: navigationMenuItemEntity.color,
pageLayoutId: navigationMenuItemEntity.pageLayoutId,
position: navigationMenuItemEntity.position,
workspaceId: navigationMenuItemEntity.workspaceId,
universalIdentifier: navigationMenuItemEntity.universalIdentifier,
applicationId: navigationMenuItemEntity.applicationId,
createdAt: navigationMenuItemEntity.createdAt.toISOString(),
updatedAt: navigationMenuItemEntity.updatedAt.toISOString(),
applicationUniversalIdentifier,
targetObjectMetadataUniversalIdentifier,
folderUniversalIdentifier,
viewUniversalIdentifier,
pageLayoutUniversalIdentifier,
...navigationMenuItemScalarEntity,
...relationUniversalIdentifiers,
};
};
@@ -1,40 +1,36 @@
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import { isDefined } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
type FromObjectMetadataEntityToFlatObjectMetadataArgs =
FromEntityToFlatEntityArgs<'objectMetadata'> & {
fieldMetadataIdToUniversalIdentifierMap: Map<string, string>;
};
export const fromObjectMetadataEntityToFlatObjectMetadata = ({
entity: objectMetadataEntity,
applicationIdToUniversalIdentifierMap,
fieldMetadataIdToUniversalIdentifierMap,
}: FromObjectMetadataEntityToFlatObjectMetadataArgs): FlatObjectMetadata => {
const objectMetadataEntityWithoutRelations = removePropertiesFromRecord(
objectMetadataEntity,
getMetadataEntityRelationProperties('objectMetadata'),
);
export const fromObjectMetadataEntityToFlatObjectMetadata = (
args: FromObjectMetadataEntityToFlatObjectMetadataArgs,
): FlatObjectMetadata => {
const {
entity: objectMetadataEntity,
fieldMetadataIdToUniversalIdentifierMap,
} = args;
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
objectMetadataEntity.applicationId,
);
const objectMetadataScalarEntity = fromEntityToScalarEntity({
metadataName: 'objectMetadata',
entity: objectMetadataEntity,
});
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${objectMetadataEntity.applicationId} not found when building flat object metadata for object ${objectMetadataEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'objectMetadata',
...args,
});
// labelIdentifier/imageIdentifier are soft field references (not modeled
// relations) resolved without throwing on missing identifiers
let labelIdentifierFieldMetadataUniversalIdentifier: string | null = null;
if (isDefined(objectMetadataEntity.labelIdentifierFieldMetadataId)) {
@@ -70,11 +66,10 @@ export const fromObjectMetadataEntityToFlatObjectMetadata = ({
}
return {
...objectMetadataEntityWithoutRelations,
universalIdentifier:
objectMetadataEntityWithoutRelations.universalIdentifier,
createdAt: objectMetadataEntity.createdAt.toISOString(),
updatedAt: objectMetadataEntity.updatedAt.toISOString(),
...objectMetadataScalarEntity,
...relationUniversalIdentifiers,
labelIdentifierFieldMetadataUniversalIdentifier,
imageIdentifierFieldMetadataUniversalIdentifier,
viewIds: objectMetadataEntity.views.map(({ id }) => id),
indexMetadataIds: objectMetadataEntity.indexMetadatas.map(({ id }) => id),
searchFieldMetadataIds: objectMetadataEntity.searchFieldMetadatas.map(
@@ -86,9 +81,6 @@ export const fromObjectMetadataEntityToFlatObjectMetadata = ({
),
fieldPermissionIds:
objectMetadataEntity.fieldPermissions?.map(({ id }) => id) ?? [],
applicationUniversalIdentifier,
labelIdentifierFieldMetadataUniversalIdentifier,
imageIdentifierFieldMetadataUniversalIdentifier,
fieldUniversalIdentifiers: objectMetadataEntity.fields.map(
({ universalIdentifier }) => universalIdentifier,
),
@@ -1,67 +1,26 @@
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatObjectPermission } from 'src/engine/metadata-modules/flat-object-permission/types/flat-object-permission.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromObjectPermissionEntityToFlatObjectPermission = ({
entity: objectPermissionEntity,
applicationIdToUniversalIdentifierMap,
roleIdToUniversalIdentifierMap,
objectMetadataIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'objectPermission'>): FlatObjectPermission => {
const objectPermissionEntityWithoutRelations = removePropertiesFromRecord(
objectPermissionEntity,
getMetadataEntityRelationProperties('objectPermission'),
);
export const fromObjectPermissionEntityToFlatObjectPermission = (
args: FromEntityToFlatEntityArgs<'objectPermission'>,
): FlatObjectPermission => {
const { entity: objectPermissionEntity } = args;
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
objectPermissionEntity.applicationId,
);
const objectPermissionScalarEntity = fromEntityToScalarEntity({
metadataName: 'objectPermission',
entity: objectPermissionEntity,
});
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${objectPermissionEntity.applicationId} not found for objectPermission ${objectPermissionEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const roleUniversalIdentifier = roleIdToUniversalIdentifierMap.get(
objectPermissionEntity.roleId,
);
if (!isDefined(roleUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Role with id ${objectPermissionEntity.roleId} not found for objectPermission ${objectPermissionEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const objectMetadataUniversalIdentifier =
objectMetadataIdToUniversalIdentifierMap.get(
objectPermissionEntity.objectMetadataId,
);
if (!isDefined(objectMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`ObjectMetadata with id ${objectPermissionEntity.objectMetadataId} not found for objectPermission ${objectPermissionEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'objectPermission',
...args,
});
return {
...objectPermissionEntityWithoutRelations,
createdAt: objectPermissionEntity.createdAt.toISOString(),
updatedAt: objectPermissionEntity.updatedAt.toISOString(),
universalIdentifier:
objectPermissionEntityWithoutRelations.universalIdentifier,
applicationUniversalIdentifier,
roleUniversalIdentifier,
objectMetadataUniversalIdentifier,
...objectPermissionScalarEntity,
...relationUniversalIdentifiers,
};
};
@@ -1,14 +1,11 @@
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import { isDefined } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget.type';
import { fromPageLayoutWidgetConfigurationToUniversalConfiguration } from 'src/engine/metadata-modules/flat-page-layout-widget/utils/from-page-layout-widget-configuration-to-universal-configuration.util';
import { fromPageLayoutWidgetOverridesToUniversalOverrides } from 'src/engine/metadata-modules/flat-page-layout-widget/utils/from-page-layout-widget-overrides-to-universal-overrides.util';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
type FromPageLayoutWidgetEntityToFlatPageLayoutWidgetArgs =
FromEntityToFlatEntityArgs<'pageLayoutWidget'> & {
@@ -18,64 +15,32 @@ type FromPageLayoutWidgetEntityToFlatPageLayoutWidgetArgs =
viewUniversalIdentifierById?: Partial<Record<string, string>>;
};
export const fromPageLayoutWidgetEntityToFlatPageLayoutWidget = ({
entity: pageLayoutWidgetEntity,
applicationIdToUniversalIdentifierMap,
pageLayoutTabIdToUniversalIdentifierMap,
objectMetadataIdToUniversalIdentifierMap,
fieldMetadataUniversalIdentifierById,
frontComponentUniversalIdentifierById,
viewFieldGroupUniversalIdentifierById,
viewUniversalIdentifierById,
}: FromPageLayoutWidgetEntityToFlatPageLayoutWidgetArgs): FlatPageLayoutWidget => {
const pageLayoutWidgetEntityWithoutRelations = removePropertiesFromRecord(
pageLayoutWidgetEntity,
getMetadataEntityRelationProperties('pageLayoutWidget'),
);
export const fromPageLayoutWidgetEntityToFlatPageLayoutWidget = (
args: FromPageLayoutWidgetEntityToFlatPageLayoutWidgetArgs,
): FlatPageLayoutWidget => {
const {
entity: pageLayoutWidgetEntity,
pageLayoutTabIdToUniversalIdentifierMap,
fieldMetadataUniversalIdentifierById,
frontComponentUniversalIdentifierById,
viewFieldGroupUniversalIdentifierById,
viewUniversalIdentifierById,
} = args;
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
pageLayoutWidgetEntity.applicationId,
);
const pageLayoutWidgetScalarEntity = fromEntityToScalarEntity({
metadataName: 'pageLayoutWidget',
entity: pageLayoutWidgetEntity,
});
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${pageLayoutWidgetEntity.applicationId} not found for pageLayoutWidget ${pageLayoutWidgetEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const pageLayoutTabUniversalIdentifier =
pageLayoutTabIdToUniversalIdentifierMap.get(
pageLayoutWidgetEntity.pageLayoutTabId,
);
if (!isDefined(pageLayoutTabUniversalIdentifier)) {
throw new FlatEntityMapsException(
`PageLayoutTab with id ${pageLayoutWidgetEntity.pageLayoutTabId} not found for pageLayoutWidget ${pageLayoutWidgetEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
let objectMetadataUniversalIdentifier: string | null = null;
if (isDefined(pageLayoutWidgetEntity.objectMetadataId)) {
objectMetadataUniversalIdentifier =
objectMetadataIdToUniversalIdentifierMap.get(
pageLayoutWidgetEntity.objectMetadataId,
) ?? null;
if (!isDefined(objectMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`ObjectMetadata with id ${pageLayoutWidgetEntity.objectMetadataId} not found for pageLayoutWidget ${pageLayoutWidgetEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'pageLayoutWidget',
...args,
});
const configurationWithUniversalIdentifiers =
fromPageLayoutWidgetConfigurationToUniversalConfiguration({
configuration: pageLayoutWidgetEntityWithoutRelations.configuration,
configuration: pageLayoutWidgetScalarEntity.configuration,
fieldMetadataUniversalIdentifierById,
frontComponentUniversalIdentifierById,
viewFieldGroupUniversalIdentifierById,
@@ -95,16 +60,8 @@ export const fromPageLayoutWidgetEntityToFlatPageLayoutWidget = ({
: null;
return {
...pageLayoutWidgetEntityWithoutRelations,
createdAt: pageLayoutWidgetEntity.createdAt.toISOString(),
updatedAt: pageLayoutWidgetEntity.updatedAt.toISOString(),
deletedAt: pageLayoutWidgetEntity.deletedAt?.toISOString() ?? null,
universalIdentifier:
pageLayoutWidgetEntityWithoutRelations.universalIdentifier,
applicationId: pageLayoutWidgetEntityWithoutRelations.applicationId,
applicationUniversalIdentifier,
pageLayoutTabUniversalIdentifier,
objectMetadataUniversalIdentifier,
...pageLayoutWidgetScalarEntity,
...relationUniversalIdentifiers,
universalConfiguration: configurationWithUniversalIdentifiers,
universalOverrides,
};
@@ -1,40 +1,27 @@
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatPermissionFlag } from 'src/engine/metadata-modules/flat-permission-flag/types/flat-permission-flag.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromPermissionFlagEntityToFlatPermissionFlag = ({
entity: permissionFlagEntity,
applicationIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'permissionFlag'>): FlatPermissionFlag => {
const entityWithoutRelations = removePropertiesFromRecord(
permissionFlagEntity,
getMetadataEntityRelationProperties('permissionFlag'),
);
export const fromPermissionFlagEntityToFlatPermissionFlag = (
args: FromEntityToFlatEntityArgs<'permissionFlag'>,
): FlatPermissionFlag => {
const { entity: permissionFlagEntity } = args;
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
permissionFlagEntity.applicationId,
);
const permissionFlagScalarEntity = fromEntityToScalarEntity({
metadataName: 'permissionFlag',
entity: permissionFlagEntity,
});
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${permissionFlagEntity.applicationId} not found for permissionFlag ${permissionFlagEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'permissionFlag',
...args,
});
return {
...entityWithoutRelations,
createdAt: permissionFlagEntity.createdAt.toISOString(),
updatedAt: permissionFlagEntity.updatedAt.toISOString(),
universalIdentifier: entityWithoutRelations.universalIdentifier,
applicationUniversalIdentifier,
...permissionFlagScalarEntity,
...relationUniversalIdentifiers,
rolePermissionFlagIds: permissionFlagEntity.rolePermissionFlags.map(
({ id }) => id,
),
@@ -1,67 +1,26 @@
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatRolePermissionFlag } from 'src/engine/metadata-modules/flat-role-permission-flag/types/flat-role-permission-flag.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromRolePermissionFlagEntityToFlatRolePermissionFlag = ({
entity: rolePermissionFlagEntity,
applicationIdToUniversalIdentifierMap,
permissionFlagIdToUniversalIdentifierMap,
roleIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'rolePermissionFlag'>): FlatRolePermissionFlag => {
const rolePermissionFlagEntityWithoutRelations = removePropertiesFromRecord(
rolePermissionFlagEntity,
getMetadataEntityRelationProperties('rolePermissionFlag'),
);
export const fromRolePermissionFlagEntityToFlatRolePermissionFlag = (
args: FromEntityToFlatEntityArgs<'rolePermissionFlag'>,
): FlatRolePermissionFlag => {
const { entity: rolePermissionFlagEntity } = args;
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
rolePermissionFlagEntity.applicationId,
);
const rolePermissionFlagScalarEntity = fromEntityToScalarEntity({
metadataName: 'rolePermissionFlag',
entity: rolePermissionFlagEntity,
});
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${rolePermissionFlagEntity.applicationId} not found for rolePermissionFlag ${rolePermissionFlagEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const roleUniversalIdentifier = roleIdToUniversalIdentifierMap.get(
rolePermissionFlagEntity.roleId,
);
if (!isDefined(roleUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Role with id ${rolePermissionFlagEntity.roleId} not found for rolePermissionFlag ${rolePermissionFlagEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const permissionFlagUniversalIdentifier =
permissionFlagIdToUniversalIdentifierMap.get(
rolePermissionFlagEntity.permissionFlagId,
);
if (!isDefined(permissionFlagUniversalIdentifier)) {
throw new FlatEntityMapsException(
`PermissionFlag with id ${rolePermissionFlagEntity.permissionFlagId} not found for rolePermissionFlag ${rolePermissionFlagEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'rolePermissionFlag',
...args,
});
return {
...rolePermissionFlagEntityWithoutRelations,
createdAt: rolePermissionFlagEntity.createdAt.toISOString(),
updatedAt: rolePermissionFlagEntity.updatedAt.toISOString(),
universalIdentifier:
rolePermissionFlagEntityWithoutRelations.universalIdentifier,
applicationUniversalIdentifier,
permissionFlagUniversalIdentifier,
roleUniversalIdentifier,
...rolePermissionFlagScalarEntity,
...relationUniversalIdentifiers,
};
};
@@ -1,50 +1,26 @@
import { isDefined } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatRoleTarget } from 'src/engine/metadata-modules/flat-role-target/types/flat-role-target.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromRoleTargetEntityToFlatRoleTarget = ({
entity: roleTargetEntity,
applicationIdToUniversalIdentifierMap,
roleIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'roleTarget'>): FlatRoleTarget => {
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(roleTargetEntity.applicationId);
export const fromRoleTargetEntityToFlatRoleTarget = (
args: FromEntityToFlatEntityArgs<'roleTarget'>,
): FlatRoleTarget => {
const { entity: roleTargetEntity } = args;
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${roleTargetEntity.applicationId} not found when building flat role target for role target ${roleTargetEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const roleTargetScalarEntity = fromEntityToScalarEntity({
metadataName: 'roleTarget',
entity: roleTargetEntity,
});
const roleUniversalIdentifier = roleIdToUniversalIdentifierMap.get(
roleTargetEntity.roleId,
);
if (!isDefined(roleUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Role with id ${roleTargetEntity.roleId} not found when building flat role target for role target ${roleTargetEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'roleTarget',
...args,
});
return {
id: roleTargetEntity.id,
workspaceId: roleTargetEntity.workspaceId,
roleId: roleTargetEntity.roleId,
userWorkspaceId: roleTargetEntity.userWorkspaceId,
agentId: roleTargetEntity.agentId,
apiKeyId: roleTargetEntity.apiKeyId,
applicationId: roleTargetEntity.applicationId,
universalIdentifier: roleTargetEntity.universalIdentifier,
createdAt: roleTargetEntity.createdAt.toISOString(),
updatedAt: roleTargetEntity.updatedAt.toISOString(),
applicationUniversalIdentifier,
roleUniversalIdentifier,
...roleTargetScalarEntity,
...relationUniversalIdentifiers,
};
};
@@ -1,14 +1,10 @@
import { isDefined } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { type MetadataEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-entity.type';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatRole } from 'src/engine/metadata-modules/flat-role/types/flat-role.type';
import { type EntityManyToOneIdByUniversalIdentifierMaps } from 'src/engine/workspace-cache/types/entity-many-to-one-id-by-universal-identifier-maps.type';
import { type EntityWithRegroupedOneToManyRelations } from 'src/engine/workspace-cache/types/entity-with-regrouped-one-to-many-relations.type';
import { type RegroupedEntity } from 'src/engine/workspace-cache/utils/regroup-entities-by-related-entity-id';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
type FromRoleEntityToFlatRoleArgs = {
entity: Omit<
@@ -21,40 +17,25 @@ type FromRoleEntityToFlatRoleArgs = {
};
} & EntityManyToOneIdByUniversalIdentifierMaps<'role'>;
export const fromRoleEntityToFlatRole = ({
entity: roleEntity,
applicationIdToUniversalIdentifierMap,
}: FromRoleEntityToFlatRoleArgs): FlatRole => {
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(roleEntity.applicationId);
export const fromRoleEntityToFlatRole = (
args: FromRoleEntityToFlatRoleArgs,
): FlatRole => {
const { entity: roleEntity } = args;
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${roleEntity.applicationId} not found for role ${roleEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const roleScalarEntity = fromEntityToScalarEntity({
metadataName: 'role',
entity: roleEntity,
});
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'role',
...args,
});
return {
id: roleEntity.id,
label: roleEntity.label,
description: roleEntity.description,
icon: roleEntity.icon,
isEditable: roleEntity.isEditable,
canUpdateAllSettings: roleEntity.canUpdateAllSettings,
canAccessAllTools: roleEntity.canAccessAllTools,
canReadAllObjectRecords: roleEntity.canReadAllObjectRecords,
canUpdateAllObjectRecords: roleEntity.canUpdateAllObjectRecords,
canSoftDeleteAllObjectRecords: roleEntity.canSoftDeleteAllObjectRecords,
canDestroyAllObjectRecords: roleEntity.canDestroyAllObjectRecords,
canBeAssignedToUsers: roleEntity.canBeAssignedToUsers,
canBeAssignedToAgents: roleEntity.canBeAssignedToAgents,
canBeAssignedToApiKeys: roleEntity.canBeAssignedToApiKeys,
workspaceId: roleEntity.workspaceId,
createdAt: roleEntity.createdAt.toISOString(),
updatedAt: roleEntity.updatedAt.toISOString(),
universalIdentifier: roleEntity.universalIdentifier,
applicationId: roleEntity.applicationId,
...roleScalarEntity,
...relationUniversalIdentifiers,
roleTargetIds: roleEntity.roleTargets.map(({ id }) => id),
objectPermissionIds: roleEntity.objectPermissions.map(({ id }) => id),
rolePermissionFlagIds: roleEntity.rolePermissionFlags.map(({ id }) => id),
@@ -64,7 +45,6 @@ export const fromRoleEntityToFlatRole = ({
),
rowLevelPermissionPredicateGroupIds:
roleEntity.rowLevelPermissionPredicateGroups.map(({ id }) => id),
applicationUniversalIdentifier,
roleTargetUniversalIdentifiers: roleEntity.roleTargets.map(
({ universalIdentifier }) => universalIdentifier,
),
@@ -1,11 +0,0 @@
/* @license Enterprise */
export const ROW_LEVEL_PERMISSION_PREDICATE_ENTITY_RELATION_PROPERTIES = [
'workspace',
'role',
'fieldMetadata',
'workspaceMemberFieldMetadata',
'objectMetadata',
'rowLevelPermissionPredicateGroup',
'application',
] as const;
@@ -1,10 +0,0 @@
/* @license Enterprise */
export const ROW_LEVEL_PERMISSION_PREDICATE_GROUP_ENTITY_RELATION_PROPERTIES = [
'workspace',
'role',
'parentRowLevelPermissionPredicateGroup',
'childRowLevelPermissionPredicateGroups',
'rowLevelPermissionPredicates',
'application',
] as const;
@@ -1,130 +1,29 @@
/* @license Enterprise */
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { ROW_LEVEL_PERMISSION_PREDICATE_ENTITY_RELATION_PROPERTIES } from 'src/engine/metadata-modules/flat-row-level-permission-predicate/constants/row-level-permission-predicate-entity-relation-properties.constant';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatRowLevelPermissionPredicate } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromRowLevelPermissionPredicateEntityToFlatRowLevelPermissionPredicate =
({
entity: rowLevelPermissionPredicateEntity,
applicationIdToUniversalIdentifierMap,
fieldMetadataIdToUniversalIdentifierMap,
objectMetadataIdToUniversalIdentifierMap,
roleIdToUniversalIdentifierMap,
rowLevelPermissionPredicateGroupIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'rowLevelPermissionPredicate'>): FlatRowLevelPermissionPredicate => {
const rowLevelPermissionPredicateEntityWithoutRelations =
removePropertiesFromRecord(rowLevelPermissionPredicateEntity, [
...ROW_LEVEL_PERMISSION_PREDICATE_ENTITY_RELATION_PROPERTIES,
] as (typeof ROW_LEVEL_PERMISSION_PREDICATE_ENTITY_RELATION_PROPERTIES)[number][]);
(
args: FromEntityToFlatEntityArgs<'rowLevelPermissionPredicate'>,
): FlatRowLevelPermissionPredicate => {
const { entity: rowLevelPermissionPredicateEntity } = args;
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
rowLevelPermissionPredicateEntity.applicationId,
);
const rowLevelPermissionPredicateScalarEntity = fromEntityToScalarEntity({
metadataName: 'rowLevelPermissionPredicate',
entity: rowLevelPermissionPredicateEntity,
});
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${rowLevelPermissionPredicateEntity.applicationId} not found for rowLevelPermissionPredicate ${rowLevelPermissionPredicateEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const fieldMetadataUniversalIdentifier =
fieldMetadataIdToUniversalIdentifierMap.get(
rowLevelPermissionPredicateEntity.fieldMetadataId,
);
if (!isDefined(fieldMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`FieldMetadata with id ${rowLevelPermissionPredicateEntity.fieldMetadataId} not found for rowLevelPermissionPredicate ${rowLevelPermissionPredicateEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const objectMetadataUniversalIdentifier =
objectMetadataIdToUniversalIdentifierMap.get(
rowLevelPermissionPredicateEntity.objectMetadataId,
);
if (!isDefined(objectMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`ObjectMetadata with id ${rowLevelPermissionPredicateEntity.objectMetadataId} not found for rowLevelPermissionPredicate ${rowLevelPermissionPredicateEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const roleUniversalIdentifier = roleIdToUniversalIdentifierMap.get(
rowLevelPermissionPredicateEntity.roleId,
);
if (!isDefined(roleUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Role with id ${rowLevelPermissionPredicateEntity.roleId} not found for rowLevelPermissionPredicate ${rowLevelPermissionPredicateEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
let workspaceMemberFieldMetadataUniversalIdentifier: string | null = null;
if (
isDefined(
rowLevelPermissionPredicateEntity.workspaceMemberFieldMetadataId,
)
) {
workspaceMemberFieldMetadataUniversalIdentifier =
fieldMetadataIdToUniversalIdentifierMap.get(
rowLevelPermissionPredicateEntity.workspaceMemberFieldMetadataId,
) ?? null;
if (!isDefined(workspaceMemberFieldMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`FieldMetadata with id ${rowLevelPermissionPredicateEntity.workspaceMemberFieldMetadataId} not found for rowLevelPermissionPredicate ${rowLevelPermissionPredicateEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
let rowLevelPermissionPredicateGroupUniversalIdentifier: string | null =
null;
if (
isDefined(
rowLevelPermissionPredicateEntity.rowLevelPermissionPredicateGroupId,
)
) {
rowLevelPermissionPredicateGroupUniversalIdentifier =
rowLevelPermissionPredicateGroupIdToUniversalIdentifierMap.get(
rowLevelPermissionPredicateEntity.rowLevelPermissionPredicateGroupId,
) ?? null;
if (!isDefined(rowLevelPermissionPredicateGroupUniversalIdentifier)) {
throw new FlatEntityMapsException(
`RowLevelPermissionPredicateGroup with id ${rowLevelPermissionPredicateEntity.rowLevelPermissionPredicateGroupId} not found for rowLevelPermissionPredicate ${rowLevelPermissionPredicateEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'rowLevelPermissionPredicate',
...args,
});
return {
...rowLevelPermissionPredicateEntityWithoutRelations,
createdAt: rowLevelPermissionPredicateEntity.createdAt.toISOString(),
updatedAt: rowLevelPermissionPredicateEntity.updatedAt.toISOString(),
deletedAt:
rowLevelPermissionPredicateEntity.deletedAt?.toISOString() ?? null,
universalIdentifier:
rowLevelPermissionPredicateEntityWithoutRelations.universalIdentifier,
applicationUniversalIdentifier,
fieldMetadataUniversalIdentifier,
objectMetadataUniversalIdentifier,
roleUniversalIdentifier,
workspaceMemberFieldMetadataUniversalIdentifier,
rowLevelPermissionPredicateGroupUniversalIdentifier,
...rowLevelPermissionPredicateScalarEntity,
...relationUniversalIdentifiers,
};
};
@@ -1,103 +1,31 @@
/* @license Enterprise */
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { ROW_LEVEL_PERMISSION_PREDICATE_GROUP_ENTITY_RELATION_PROPERTIES } from 'src/engine/metadata-modules/flat-row-level-permission-predicate/constants/row-level-permission-predicate-group-entity-relation-properties.constant';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatRowLevelPermissionPredicateGroup } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate-group.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
type FromRowLevelPermissionPredicateGroupEntityToFlatRowLevelPermissionPredicateGroupArgs =
FromEntityToFlatEntityArgs<'rowLevelPermissionPredicateGroup'> & {
rowLevelPermissionPredicateGroupIdToUniversalIdentifierMap: Map<
string,
string
>;
};
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromRowLevelPermissionPredicateGroupEntityToFlatRowLevelPermissionPredicateGroup =
({
entity: rowLevelPermissionPredicateGroupEntity,
applicationIdToUniversalIdentifierMap,
objectMetadataIdToUniversalIdentifierMap,
roleIdToUniversalIdentifierMap,
rowLevelPermissionPredicateGroupIdToUniversalIdentifierMap,
}: FromRowLevelPermissionPredicateGroupEntityToFlatRowLevelPermissionPredicateGroupArgs): FlatRowLevelPermissionPredicateGroup => {
const rowLevelPermissionPredicateGroupEntityWithoutRelations =
removePropertiesFromRecord(rowLevelPermissionPredicateGroupEntity, [
...ROW_LEVEL_PERMISSION_PREDICATE_GROUP_ENTITY_RELATION_PROPERTIES,
] as (typeof ROW_LEVEL_PERMISSION_PREDICATE_GROUP_ENTITY_RELATION_PROPERTIES)[number][]);
(
args: FromEntityToFlatEntityArgs<'rowLevelPermissionPredicateGroup'>,
): FlatRowLevelPermissionPredicateGroup => {
const { entity: rowLevelPermissionPredicateGroupEntity } = args;
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
rowLevelPermissionPredicateGroupEntity.applicationId,
);
const rowLevelPermissionPredicateGroupScalarEntity =
fromEntityToScalarEntity({
metadataName: 'rowLevelPermissionPredicateGroup',
entity: rowLevelPermissionPredicateGroupEntity,
});
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${rowLevelPermissionPredicateGroupEntity.applicationId} not found for rowLevelPermissionPredicateGroup ${rowLevelPermissionPredicateGroupEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const objectMetadataUniversalIdentifier =
objectMetadataIdToUniversalIdentifierMap.get(
rowLevelPermissionPredicateGroupEntity.objectMetadataId,
);
if (!isDefined(objectMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`ObjectMetadata with id ${rowLevelPermissionPredicateGroupEntity.objectMetadataId} not found for rowLevelPermissionPredicateGroup ${rowLevelPermissionPredicateGroupEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const roleUniversalIdentifier = roleIdToUniversalIdentifierMap.get(
rowLevelPermissionPredicateGroupEntity.roleId,
);
if (!isDefined(roleUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Role with id ${rowLevelPermissionPredicateGroupEntity.roleId} not found for rowLevelPermissionPredicateGroup ${rowLevelPermissionPredicateGroupEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
let parentRowLevelPermissionPredicateGroupUniversalIdentifier:
| string
| null = null;
if (
isDefined(
rowLevelPermissionPredicateGroupEntity.parentRowLevelPermissionPredicateGroupId,
)
) {
parentRowLevelPermissionPredicateGroupUniversalIdentifier =
rowLevelPermissionPredicateGroupIdToUniversalIdentifierMap.get(
rowLevelPermissionPredicateGroupEntity.parentRowLevelPermissionPredicateGroupId,
) ?? null;
if (
!isDefined(parentRowLevelPermissionPredicateGroupUniversalIdentifier)
) {
throw new FlatEntityMapsException(
`RowLevelPermissionPredicateGroup with id ${rowLevelPermissionPredicateGroupEntity.parentRowLevelPermissionPredicateGroupId} not found for rowLevelPermissionPredicateGroup ${rowLevelPermissionPredicateGroupEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'rowLevelPermissionPredicateGroup',
...args,
});
return {
...rowLevelPermissionPredicateGroupEntityWithoutRelations,
createdAt: rowLevelPermissionPredicateGroupEntity.createdAt.toISOString(),
updatedAt: rowLevelPermissionPredicateGroupEntity.updatedAt.toISOString(),
deletedAt:
rowLevelPermissionPredicateGroupEntity.deletedAt?.toISOString() ?? null,
universalIdentifier:
rowLevelPermissionPredicateGroupEntityWithoutRelations.universalIdentifier,
...rowLevelPermissionPredicateGroupScalarEntity,
...relationUniversalIdentifiers,
childRowLevelPermissionPredicateGroupIds: (
rowLevelPermissionPredicateGroupEntity.childRowLevelPermissionPredicateGroups ??
[]
@@ -106,10 +34,6 @@ export const fromRowLevelPermissionPredicateGroupEntityToFlatRowLevelPermissionP
rowLevelPermissionPredicateGroupEntity.rowLevelPermissionPredicates ??
[]
).map(({ id }) => id),
applicationUniversalIdentifier,
objectMetadataUniversalIdentifier,
roleUniversalIdentifier,
parentRowLevelPermissionPredicateGroupUniversalIdentifier,
childRowLevelPermissionPredicateGroupUniversalIdentifiers: (
rowLevelPermissionPredicateGroupEntity.childRowLevelPermissionPredicateGroups ??
[]
@@ -1,40 +1,26 @@
import { isDefined } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatSkill } from 'src/engine/metadata-modules/flat-skill/types/flat-skill.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromSkillEntityToFlatSkill = ({
entity: skillEntity,
applicationIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'skill'>): FlatSkill => {
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(skillEntity.applicationId);
export const fromSkillEntityToFlatSkill = (
args: FromEntityToFlatEntityArgs<'skill'>,
): FlatSkill => {
const { entity: skillEntity } = args;
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${skillEntity.applicationId} not found for skill ${skillEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const skillScalarEntity = fromEntityToScalarEntity({
metadataName: 'skill',
entity: skillEntity,
});
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'skill',
...args,
});
return {
createdAt: skillEntity.createdAt.toISOString(),
updatedAt: skillEntity.updatedAt.toISOString(),
id: skillEntity.id,
name: skillEntity.name,
label: skillEntity.label,
icon: skillEntity.icon,
description: skillEntity.description,
content: skillEntity.content,
workspaceId: skillEntity.workspaceId,
isCustom: skillEntity.isCustom,
isActive: skillEntity.isActive,
universalIdentifier: skillEntity.universalIdentifier,
applicationId: skillEntity.applicationId,
applicationUniversalIdentifier,
...skillScalarEntity,
...relationUniversalIdentifiers,
};
};
@@ -1,55 +1,27 @@
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatViewFieldGroup } from 'src/engine/metadata-modules/flat-view-field-group/types/flat-view-field-group.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromViewFieldGroupEntityToFlatViewFieldGroup = ({
entity: viewFieldGroupEntity,
applicationIdToUniversalIdentifierMap,
viewIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'viewFieldGroup'>): FlatViewFieldGroup => {
const viewFieldGroupEntityWithoutRelations = removePropertiesFromRecord(
viewFieldGroupEntity,
getMetadataEntityRelationProperties('viewFieldGroup'),
);
export const fromViewFieldGroupEntityToFlatViewFieldGroup = (
args: FromEntityToFlatEntityArgs<'viewFieldGroup'>,
): FlatViewFieldGroup => {
const { entity: viewFieldGroupEntity } = args;
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
viewFieldGroupEntity.applicationId,
);
const viewFieldGroupScalarEntity = fromEntityToScalarEntity({
metadataName: 'viewFieldGroup',
entity: viewFieldGroupEntity,
});
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${viewFieldGroupEntity.applicationId} not found for viewFieldGroup ${viewFieldGroupEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const viewUniversalIdentifier = viewIdToUniversalIdentifierMap.get(
viewFieldGroupEntity.viewId,
);
if (!isDefined(viewUniversalIdentifier)) {
throw new FlatEntityMapsException(
`View with id ${viewFieldGroupEntity.viewId} not found for viewFieldGroup ${viewFieldGroupEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'viewFieldGroup',
...args,
});
return {
...viewFieldGroupEntityWithoutRelations,
createdAt: viewFieldGroupEntity.createdAt.toISOString(),
updatedAt: viewFieldGroupEntity.updatedAt.toISOString(),
deletedAt: viewFieldGroupEntity.deletedAt?.toISOString() ?? null,
universalIdentifier:
viewFieldGroupEntityWithoutRelations.universalIdentifier,
applicationUniversalIdentifier,
viewUniversalIdentifier,
...viewFieldGroupScalarEntity,
...relationUniversalIdentifiers,
viewFieldIds:
viewFieldGroupEntity.viewFields?.map((viewField) => viewField.id) ?? [],
viewFieldUniversalIdentifiers:
@@ -1,74 +1,27 @@
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import { isDefined } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatViewField } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field.type';
import { fromViewFieldOverridesToUniversalOverrides } from 'src/engine/metadata-modules/flat-view-field/utils/from-view-field-overrides-to-universal-overrides.util';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromViewFieldEntityToFlatViewField = ({
entity: viewFieldEntity,
applicationIdToUniversalIdentifierMap,
fieldMetadataIdToUniversalIdentifierMap,
viewIdToUniversalIdentifierMap,
viewFieldGroupIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'viewField'>): FlatViewField => {
const viewFieldEntityWithoutRelations = removePropertiesFromRecord(
viewFieldEntity,
getMetadataEntityRelationProperties('viewField'),
);
export const fromViewFieldEntityToFlatViewField = (
args: FromEntityToFlatEntityArgs<'viewField'>,
): FlatViewField => {
const { entity: viewFieldEntity, viewFieldGroupIdToUniversalIdentifierMap } =
args;
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(viewFieldEntity.applicationId);
const viewFieldScalarEntity = fromEntityToScalarEntity({
metadataName: 'viewField',
entity: viewFieldEntity,
});
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${viewFieldEntity.applicationId} not found for viewField ${viewFieldEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const fieldMetadataUniversalIdentifier =
fieldMetadataIdToUniversalIdentifierMap.get(
viewFieldEntity.fieldMetadataId,
);
if (!isDefined(fieldMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`FieldMetadata with id ${viewFieldEntity.fieldMetadataId} not found for viewField ${viewFieldEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const viewUniversalIdentifier = viewIdToUniversalIdentifierMap.get(
viewFieldEntity.viewId,
);
if (!isDefined(viewUniversalIdentifier)) {
throw new FlatEntityMapsException(
`View with id ${viewFieldEntity.viewId} not found for viewField ${viewFieldEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
let viewFieldGroupUniversalIdentifier: string | null = null;
if (isDefined(viewFieldEntity.viewFieldGroupId)) {
viewFieldGroupUniversalIdentifier =
viewFieldGroupIdToUniversalIdentifierMap.get(
viewFieldEntity.viewFieldGroupId,
) ?? null;
if (!isDefined(viewFieldGroupUniversalIdentifier)) {
throw new FlatEntityMapsException(
`ViewFieldGroup with id ${viewFieldEntity.viewFieldGroupId} not found for viewField ${viewFieldEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'viewField',
...args,
});
const viewFieldGroupUniversalIdentifierById = Object.fromEntries(
viewFieldGroupIdToUniversalIdentifierMap.entries(),
@@ -83,15 +36,8 @@ export const fromViewFieldEntityToFlatViewField = ({
: null;
return {
...viewFieldEntityWithoutRelations,
createdAt: viewFieldEntity.createdAt.toISOString(),
updatedAt: viewFieldEntity.updatedAt.toISOString(),
deletedAt: viewFieldEntity.deletedAt?.toISOString() ?? null,
universalIdentifier: viewFieldEntityWithoutRelations.universalIdentifier,
applicationUniversalIdentifier,
fieldMetadataUniversalIdentifier,
viewUniversalIdentifier,
viewFieldGroupUniversalIdentifier,
...viewFieldScalarEntity,
...relationUniversalIdentifiers,
universalOverrides,
};
};
@@ -1,81 +1,30 @@
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatViewFilterGroup } from 'src/engine/metadata-modules/flat-view-filter-group/types/flat-view-filter-group.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
type FromViewFilterGroupEntityToFlatViewFilterGroupArgs =
FromEntityToFlatEntityArgs<'viewFilterGroup'> & {
viewFilterGroupIdToUniversalIdentifierMap: Map<string, string>;
};
export const fromViewFilterGroupEntityToFlatViewFilterGroup = (
args: FromEntityToFlatEntityArgs<'viewFilterGroup'>,
): FlatViewFilterGroup => {
const { entity: viewFilterGroupEntity } = args;
export const fromViewFilterGroupEntityToFlatViewFilterGroup = ({
entity: viewFilterGroupEntity,
applicationIdToUniversalIdentifierMap,
viewFilterGroupIdToUniversalIdentifierMap,
viewIdToUniversalIdentifierMap,
}: FromViewFilterGroupEntityToFlatViewFilterGroupArgs): FlatViewFilterGroup => {
const viewFilterGroupEntityWithoutRelations = removePropertiesFromRecord(
viewFilterGroupEntity,
getMetadataEntityRelationProperties('viewFilterGroup'),
);
const viewFilterGroupScalarEntity = fromEntityToScalarEntity({
metadataName: 'viewFilterGroup',
entity: viewFilterGroupEntity,
});
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
viewFilterGroupEntity.applicationId,
);
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${viewFilterGroupEntity.applicationId} not found for viewFilterGroup ${viewFilterGroupEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
let parentViewFilterGroupUniversalIdentifier: string | null = null;
if (isDefined(viewFilterGroupEntity.parentViewFilterGroupId)) {
parentViewFilterGroupUniversalIdentifier =
viewFilterGroupIdToUniversalIdentifierMap.get(
viewFilterGroupEntity.parentViewFilterGroupId,
) ?? null;
if (!isDefined(parentViewFilterGroupUniversalIdentifier)) {
throw new FlatEntityMapsException(
`ViewFilterGroup with id ${viewFilterGroupEntity.parentViewFilterGroupId} not found for viewFilterGroup ${viewFilterGroupEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
const viewUniversalIdentifier = viewIdToUniversalIdentifierMap.get(
viewFilterGroupEntity.viewId,
);
if (!isDefined(viewUniversalIdentifier)) {
throw new FlatEntityMapsException(
`View with id ${viewFilterGroupEntity.viewId} not found for viewFilterGroup ${viewFilterGroupEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'viewFilterGroup',
...args,
});
return {
...viewFilterGroupEntityWithoutRelations,
createdAt: viewFilterGroupEntity.createdAt.toISOString(),
updatedAt: viewFilterGroupEntity.updatedAt.toISOString(),
deletedAt: viewFilterGroupEntity.deletedAt?.toISOString() ?? null,
universalIdentifier:
viewFilterGroupEntityWithoutRelations.universalIdentifier,
...viewFilterGroupScalarEntity,
...relationUniversalIdentifiers,
viewFilterIds: viewFilterGroupEntity.viewFilters?.map(({ id }) => id) ?? [],
childViewFilterGroupIds:
viewFilterGroupEntity.childViewFilterGroups?.map(({ id }) => id) ?? [],
applicationUniversalIdentifier,
parentViewFilterGroupUniversalIdentifier,
viewUniversalIdentifier,
viewFilterUniversalIdentifiers:
viewFilterGroupEntity.viewFilters?.map(
({ universalIdentifier }) => universalIdentifier,
@@ -1,100 +1,26 @@
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatViewFilter } from 'src/engine/metadata-modules/flat-view-filter/types/flat-view-filter.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromViewFilterEntityToFlatViewFilter = ({
entity: viewFilterEntity,
applicationIdToUniversalIdentifierMap,
fieldMetadataIdToUniversalIdentifierMap,
viewFilterGroupIdToUniversalIdentifierMap,
viewIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'viewFilter'>): FlatViewFilter => {
const viewFilterEntityWithoutRelations = removePropertiesFromRecord(
viewFilterEntity,
getMetadataEntityRelationProperties('viewFilter'),
);
export const fromViewFilterEntityToFlatViewFilter = (
args: FromEntityToFlatEntityArgs<'viewFilter'>,
): FlatViewFilter => {
const { entity: viewFilterEntity } = args;
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(viewFilterEntity.applicationId);
const viewFilterScalarEntity = fromEntityToScalarEntity({
metadataName: 'viewFilter',
entity: viewFilterEntity,
});
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${viewFilterEntity.applicationId} not found for viewFilter ${viewFilterEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const fieldMetadataUniversalIdentifier =
fieldMetadataIdToUniversalIdentifierMap.get(
viewFilterEntity.fieldMetadataId,
);
if (!isDefined(fieldMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`FieldMetadata with id ${viewFilterEntity.fieldMetadataId} not found for viewFilter ${viewFilterEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
let viewFilterGroupUniversalIdentifier: string | null = null;
if (isDefined(viewFilterEntity.viewFilterGroupId)) {
viewFilterGroupUniversalIdentifier =
viewFilterGroupIdToUniversalIdentifierMap.get(
viewFilterEntity.viewFilterGroupId,
) ?? null;
if (!isDefined(viewFilterGroupUniversalIdentifier)) {
throw new FlatEntityMapsException(
`ViewFilterGroup with id ${viewFilterEntity.viewFilterGroupId} not found for viewFilter ${viewFilterEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
const viewUniversalIdentifier = viewIdToUniversalIdentifierMap.get(
viewFilterEntity.viewId,
);
if (!isDefined(viewUniversalIdentifier)) {
throw new FlatEntityMapsException(
`View with id ${viewFilterEntity.viewId} not found for viewFilter ${viewFilterEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
let relationTargetFieldMetadataUniversalIdentifier: string | null = null;
if (isDefined(viewFilterEntity.relationTargetFieldMetadataId)) {
relationTargetFieldMetadataUniversalIdentifier =
fieldMetadataIdToUniversalIdentifierMap.get(
viewFilterEntity.relationTargetFieldMetadataId,
) ?? null;
if (!isDefined(relationTargetFieldMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`FieldMetadata with id ${viewFilterEntity.relationTargetFieldMetadataId} not found for viewFilter ${viewFilterEntity.id} (relation target)`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'viewFilter',
...args,
});
return {
...viewFilterEntityWithoutRelations,
createdAt: viewFilterEntity.createdAt.toISOString(),
updatedAt: viewFilterEntity.updatedAt.toISOString(),
deletedAt: viewFilterEntity.deletedAt?.toISOString() ?? null,
universalIdentifier: viewFilterEntityWithoutRelations.universalIdentifier,
applicationUniversalIdentifier,
fieldMetadataUniversalIdentifier,
relationTargetFieldMetadataUniversalIdentifier,
viewFilterGroupUniversalIdentifier,
viewUniversalIdentifier,
...viewFilterScalarEntity,
...relationUniversalIdentifiers,
};
};
@@ -1,51 +1,26 @@
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatViewGroup } from 'src/engine/metadata-modules/flat-view-group/types/flat-view-group.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromViewGroupEntityToFlatViewGroup = ({
entity: viewGroupEntity,
applicationIdToUniversalIdentifierMap,
viewIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'viewGroup'>): FlatViewGroup => {
const viewGroupEntityWithoutRelations = removePropertiesFromRecord(
viewGroupEntity,
getMetadataEntityRelationProperties('viewGroup'),
);
export const fromViewGroupEntityToFlatViewGroup = (
args: FromEntityToFlatEntityArgs<'viewGroup'>,
): FlatViewGroup => {
const { entity: viewGroupEntity } = args;
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(viewGroupEntity.applicationId);
const viewGroupScalarEntity = fromEntityToScalarEntity({
metadataName: 'viewGroup',
entity: viewGroupEntity,
});
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${viewGroupEntity.applicationId} not found for viewGroup ${viewGroupEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const viewUniversalIdentifier = viewIdToUniversalIdentifierMap.get(
viewGroupEntity.viewId,
);
if (!isDefined(viewUniversalIdentifier)) {
throw new FlatEntityMapsException(
`View with id ${viewGroupEntity.viewId} not found for viewGroup ${viewGroupEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'viewGroup',
...args,
});
return {
...viewGroupEntityWithoutRelations,
createdAt: viewGroupEntity.createdAt.toISOString(),
updatedAt: viewGroupEntity.updatedAt.toISOString(),
deletedAt: viewGroupEntity.deletedAt?.toISOString() ?? null,
universalIdentifier: viewGroupEntityWithoutRelations.universalIdentifier,
applicationUniversalIdentifier,
viewUniversalIdentifier,
...viewGroupScalarEntity,
...relationUniversalIdentifiers,
};
};
@@ -1,63 +1,26 @@
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import type { FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatViewSort } from 'src/engine/metadata-modules/flat-view-sort/types/flat-view-sort.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromViewSortEntityToFlatViewSort = ({
entity: viewSortEntity,
applicationIdToUniversalIdentifierMap,
viewIdToUniversalIdentifierMap,
fieldMetadataIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'viewSort'>): FlatViewSort => {
const viewSortEntityWithoutRelations = removePropertiesFromRecord(
viewSortEntity,
getMetadataEntityRelationProperties('viewSort'),
);
export const fromViewSortEntityToFlatViewSort = (
args: FromEntityToFlatEntityArgs<'viewSort'>,
): FlatViewSort => {
const { entity: viewSortEntity } = args;
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(viewSortEntity.applicationId);
const viewSortScalarEntity = fromEntityToScalarEntity({
metadataName: 'viewSort',
entity: viewSortEntity,
});
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${viewSortEntity.applicationId} not found for viewSort ${viewSortEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const viewUniversalIdentifier = viewIdToUniversalIdentifierMap.get(
viewSortEntity.viewId,
);
if (!isDefined(viewUniversalIdentifier)) {
throw new FlatEntityMapsException(
`View with id ${viewSortEntity.viewId} not found for viewSort ${viewSortEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const fieldMetadataUniversalIdentifier =
fieldMetadataIdToUniversalIdentifierMap.get(viewSortEntity.fieldMetadataId);
if (!isDefined(fieldMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Field metadata with id ${viewSortEntity.fieldMetadataId} not found for viewSort ${viewSortEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'viewSort',
...args,
});
return {
...viewSortEntityWithoutRelations,
createdAt: viewSortEntity.createdAt.toISOString(),
updatedAt: viewSortEntity.updatedAt.toISOString(),
deletedAt: viewSortEntity.deletedAt?.toISOString() ?? null,
universalIdentifier: viewSortEntityWithoutRelations.universalIdentifier,
applicationUniversalIdentifier,
viewUniversalIdentifier,
fieldMetadataUniversalIdentifier,
...viewSortScalarEntity,
...relationUniversalIdentifiers,
};
};
@@ -1,93 +1,26 @@
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import { isDefined } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
import { fromViewOverridesToUniversalOverrides } from 'src/engine/metadata-modules/flat-view/utils/from-view-overrides-to-universal-overrides.util';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromViewEntityToFlatView = ({
entity: viewEntity,
applicationIdToUniversalIdentifierMap,
objectMetadataIdToUniversalIdentifierMap,
fieldMetadataIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'view'>): FlatView => {
const viewEntityWithoutRelations = removePropertiesFromRecord(
viewEntity,
getMetadataEntityRelationProperties('view'),
);
export const fromViewEntityToFlatView = (
args: FromEntityToFlatEntityArgs<'view'>,
): FlatView => {
const { entity: viewEntity, fieldMetadataIdToUniversalIdentifierMap } = args;
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(viewEntity.applicationId);
const viewScalarEntity = fromEntityToScalarEntity({
metadataName: 'view',
entity: viewEntity,
});
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${viewEntity.applicationId} not found for view ${viewEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const objectMetadataUniversalIdentifier =
objectMetadataIdToUniversalIdentifierMap.get(viewEntity.objectMetadataId);
if (!isDefined(objectMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`ObjectMetadata with id ${viewEntity.objectMetadataId} not found for view ${viewEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
let kanbanAggregateOperationFieldMetadataUniversalIdentifier: string | null =
null;
if (isDefined(viewEntity.kanbanAggregateOperationFieldMetadataId)) {
kanbanAggregateOperationFieldMetadataUniversalIdentifier =
fieldMetadataIdToUniversalIdentifierMap.get(
viewEntity.kanbanAggregateOperationFieldMetadataId,
) ?? null;
if (!isDefined(kanbanAggregateOperationFieldMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`FieldMetadata with id ${viewEntity.kanbanAggregateOperationFieldMetadataId} not found for view ${viewEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
let calendarFieldMetadataUniversalIdentifier: string | null = null;
if (isDefined(viewEntity.calendarFieldMetadataId)) {
calendarFieldMetadataUniversalIdentifier =
fieldMetadataIdToUniversalIdentifierMap.get(
viewEntity.calendarFieldMetadataId,
) ?? null;
if (!isDefined(calendarFieldMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`FieldMetadata with id ${viewEntity.calendarFieldMetadataId} not found for view ${viewEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
let mainGroupByFieldMetadataUniversalIdentifier: string | null = null;
if (isDefined(viewEntity.mainGroupByFieldMetadataId)) {
mainGroupByFieldMetadataUniversalIdentifier =
fieldMetadataIdToUniversalIdentifierMap.get(
viewEntity.mainGroupByFieldMetadataId,
) ?? null;
if (!isDefined(mainGroupByFieldMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`FieldMetadata with id ${viewEntity.mainGroupByFieldMetadataId} not found for view ${viewEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
}
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'view',
...args,
});
const universalOverrides = isDefined(viewEntity.overrides)
? fromViewOverridesToUniversalOverrides({
@@ -100,22 +33,14 @@ export const fromViewEntityToFlatView = ({
: null;
return {
...viewEntityWithoutRelations,
createdAt: viewEntity.createdAt.toISOString(),
updatedAt: viewEntity.updatedAt.toISOString(),
deletedAt: viewEntity.deletedAt?.toISOString() ?? null,
universalIdentifier: viewEntityWithoutRelations.universalIdentifier,
...viewScalarEntity,
...relationUniversalIdentifiers,
universalOverrides,
viewFieldIds: viewEntity.viewFields.map(({ id }) => id),
viewFieldGroupIds: viewEntity.viewFieldGroups?.map(({ id }) => id) ?? [],
viewFilterIds: viewEntity.viewFilters.map(({ id }) => id),
viewGroupIds: viewEntity.viewGroups.map(({ id }) => id),
viewFilterGroupIds: viewEntity.viewFilterGroups?.map(({ id }) => id) ?? [],
applicationUniversalIdentifier,
objectMetadataUniversalIdentifier,
kanbanAggregateOperationFieldMetadataUniversalIdentifier,
calendarFieldMetadataUniversalIdentifier,
mainGroupByFieldMetadataUniversalIdentifier,
viewFieldUniversalIdentifiers: viewEntity.viewFields.map(
({ universalIdentifier }) => universalIdentifier,
),
@@ -1,38 +1,26 @@
import { isDefined } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatWebhook } from 'src/engine/metadata-modules/flat-webhook/types/flat-webhook.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromWebhookEntityToFlatWebhook = ({
entity: webhookEntity,
applicationIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'webhook'>): FlatWebhook => {
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(webhookEntity.applicationId);
export const fromWebhookEntityToFlatWebhook = (
args: FromEntityToFlatEntityArgs<'webhook'>,
): FlatWebhook => {
const { entity: webhookEntity } = args;
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${webhookEntity.applicationId} not found for webhook ${webhookEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const webhookScalarEntity = fromEntityToScalarEntity({
metadataName: 'webhook',
entity: webhookEntity,
});
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'webhook',
...args,
});
return {
id: webhookEntity.id,
targetUrl: webhookEntity.targetUrl,
operations: webhookEntity.operations,
description: webhookEntity.description,
secret: webhookEntity.secret,
workspaceId: webhookEntity.workspaceId,
universalIdentifier: webhookEntity.universalIdentifier,
applicationId: webhookEntity.applicationId,
createdAt: webhookEntity.createdAt.toISOString(),
updatedAt: webhookEntity.updatedAt.toISOString(),
deletedAt: webhookEntity.deletedAt?.toISOString() ?? null,
applicationUniversalIdentifier,
...webhookScalarEntity,
...relationUniversalIdentifiers,
};
};
@@ -1,39 +1,26 @@
import { isDefined, removePropertiesFromRecord } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { getMetadataEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-entity-relation-properties.util';
import { fromEntityToScalarEntity } from 'src/engine/metadata-modules/flat-entity/utils/from-entity-to-scalar-entity.util';
import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
export const fromLogicFunctionEntityToFlatLogicFunction = ({
entity: logicFunctionEntity,
applicationIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'logicFunction'>): FlatLogicFunction => {
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
logicFunctionEntity.applicationId,
);
export const fromLogicFunctionEntityToFlatLogicFunction = (
args: FromEntityToFlatEntityArgs<'logicFunction'>,
): FlatLogicFunction => {
const { entity: logicFunctionEntity } = args;
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${logicFunctionEntity.applicationId} not found for logicFunction ${logicFunctionEntity.id}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const logicFunctionScalarEntity = fromEntityToScalarEntity({
metadataName: 'logicFunction',
entity: logicFunctionEntity,
});
const logicFunctionWithoutRelations = removePropertiesFromRecord(
logicFunctionEntity,
getMetadataEntityRelationProperties('logicFunction'),
);
const relationUniversalIdentifiers =
resolveManyToOneRelationIdsToUniversalIdentifiers({
metadataName: 'logicFunction',
...args,
});
return {
...logicFunctionWithoutRelations,
createdAt: logicFunctionEntity.createdAt.toISOString(),
updatedAt: logicFunctionEntity.updatedAt.toISOString(),
deletedAt: logicFunctionEntity.deletedAt?.toISOString() ?? null,
applicationUniversalIdentifier,
...logicFunctionScalarEntity,
...relationUniversalIdentifiers,
};
};
@@ -0,0 +1,236 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { FlatEntityMapsExceptionCode } from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { type EntityManyToOneIdByUniversalIdentifierMaps } from 'src/engine/workspace-cache/types/entity-many-to-one-id-by-universal-identifier-maps.type';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
import { resolveManyToOneRelationIdsToUniversalIdentifiers } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/resolve-many-to-one-relation-ids-to-universal-identifiers.util';
const buildArgs = <T extends AllMetadataName>(
args: {
metadataName: T;
entity: Record<string, string | null | undefined>;
} & EntityManyToOneIdByUniversalIdentifierMaps<T>,
): { metadataName: T } & FromEntityToFlatEntityArgs<T> => ({
...args,
entity: args.entity as unknown as FromEntityToFlatEntityArgs<T>['entity'],
});
describe('resolveManyToOneRelationIdsToUniversalIdentifiers', () => {
describe('application resolution', () => {
it('should resolve only the application universal identifier when the entity has no other many-to-one relations', () => {
const result = resolveManyToOneRelationIdsToUniversalIdentifiers(
buildArgs({
metadataName: 'permissionFlag',
entity: {
id: 'permission-flag-id-1',
applicationId: 'app-id-1',
},
applicationIdToUniversalIdentifierMap: new Map([
['app-id-1', 'app-ui-1'],
]),
}),
);
expect(result).toEqual({
applicationUniversalIdentifier: 'app-ui-1',
});
});
it('should throw when the applicationId is not present in the map', () => {
expect(() =>
resolveManyToOneRelationIdsToUniversalIdentifiers(
buildArgs({
metadataName: 'permissionFlag',
entity: {
id: 'permission-flag-id-1',
applicationId: 'app-id-1',
},
applicationIdToUniversalIdentifierMap: new Map(),
}),
),
).toThrow(
expect.objectContaining({
code: FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
}),
);
});
it('should throw when the entity has no applicationId', () => {
expect(() =>
resolveManyToOneRelationIdsToUniversalIdentifiers(
buildArgs({
metadataName: 'permissionFlag',
entity: {
id: 'permission-flag-id-1',
applicationId: null,
},
applicationIdToUniversalIdentifierMap: new Map([
['app-id-1', 'app-ui-1'],
]),
}),
),
).toThrow(
expect.objectContaining({
code: FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
}),
);
});
});
describe('non-nullable relations', () => {
it('should resolve universal identifiers for application and non-nullable foreign keys', () => {
const result = resolveManyToOneRelationIdsToUniversalIdentifiers(
buildArgs({
metadataName: 'viewField',
entity: {
id: 'view-field-id-1',
applicationId: 'app-id-1',
fieldMetadataId: 'field-id-1',
viewId: 'view-id-1',
viewFieldGroupId: 'view-field-group-id-1',
},
applicationIdToUniversalIdentifierMap: new Map([
['app-id-1', 'app-ui-1'],
]),
fieldMetadataIdToUniversalIdentifierMap: new Map([
['field-id-1', 'field-ui-1'],
]),
viewIdToUniversalIdentifierMap: new Map([['view-id-1', 'view-ui-1']]),
viewFieldGroupIdToUniversalIdentifierMap: new Map([
['view-field-group-id-1', 'view-field-group-ui-1'],
]),
}),
);
expect(result).toEqual({
applicationUniversalIdentifier: 'app-ui-1',
fieldMetadataUniversalIdentifier: 'field-ui-1',
viewUniversalIdentifier: 'view-ui-1',
viewFieldGroupUniversalIdentifier: 'view-field-group-ui-1',
});
});
it('should throw when a non-nullable foreign key id is missing from the map', () => {
expect(() =>
resolveManyToOneRelationIdsToUniversalIdentifiers(
buildArgs({
metadataName: 'viewField',
entity: {
id: 'view-field-id-1',
applicationId: 'app-id-1',
fieldMetadataId: 'non-existent-field-id',
viewId: 'view-id-1',
viewFieldGroupId: null,
},
applicationIdToUniversalIdentifierMap: new Map([
['app-id-1', 'app-ui-1'],
]),
fieldMetadataIdToUniversalIdentifierMap: new Map(),
viewIdToUniversalIdentifierMap: new Map([
['view-id-1', 'view-ui-1'],
]),
viewFieldGroupIdToUniversalIdentifierMap: new Map(),
}),
),
).toThrow(
expect.objectContaining({
code: FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
}),
);
});
it('should throw a malformed-entity error when a non-nullable foreign key is itself missing', () => {
expect(() =>
resolveManyToOneRelationIdsToUniversalIdentifiers(
buildArgs({
metadataName: 'viewField',
entity: {
id: 'view-field-id-1',
applicationId: 'app-id-1',
fieldMetadataId: null,
viewId: 'view-id-1',
viewFieldGroupId: null,
},
applicationIdToUniversalIdentifierMap: new Map([
['app-id-1', 'app-ui-1'],
]),
fieldMetadataIdToUniversalIdentifierMap: new Map([
['field-id-1', 'field-ui-1'],
]),
viewIdToUniversalIdentifierMap: new Map([
['view-id-1', 'view-ui-1'],
]),
viewFieldGroupIdToUniversalIdentifierMap: new Map(),
}),
),
).toThrow(
expect.objectContaining({
code: FlatEntityMapsExceptionCode.ENTITY_MALFORMED,
}),
);
});
});
describe('nullable relations', () => {
it('should resolve a nullable foreign key to null when its id is not defined', () => {
const result = resolveManyToOneRelationIdsToUniversalIdentifiers(
buildArgs({
metadataName: 'viewField',
entity: {
id: 'view-field-id-1',
applicationId: 'app-id-1',
fieldMetadataId: 'field-id-1',
viewId: 'view-id-1',
viewFieldGroupId: null,
},
applicationIdToUniversalIdentifierMap: new Map([
['app-id-1', 'app-ui-1'],
]),
fieldMetadataIdToUniversalIdentifierMap: new Map([
['field-id-1', 'field-ui-1'],
]),
viewIdToUniversalIdentifierMap: new Map([['view-id-1', 'view-ui-1']]),
viewFieldGroupIdToUniversalIdentifierMap: new Map(),
}),
);
expect(result).toEqual({
applicationUniversalIdentifier: 'app-ui-1',
fieldMetadataUniversalIdentifier: 'field-ui-1',
viewUniversalIdentifier: 'view-ui-1',
viewFieldGroupUniversalIdentifier: null,
});
});
it('should throw when a nullable foreign key has an id that is missing from the map', () => {
expect(() =>
resolveManyToOneRelationIdsToUniversalIdentifiers(
buildArgs({
metadataName: 'viewField',
entity: {
id: 'view-field-id-1',
applicationId: 'app-id-1',
fieldMetadataId: 'field-id-1',
viewId: 'view-id-1',
viewFieldGroupId: 'non-existent-view-field-group-id',
},
applicationIdToUniversalIdentifierMap: new Map([
['app-id-1', 'app-ui-1'],
]),
fieldMetadataIdToUniversalIdentifierMap: new Map([
['field-id-1', 'field-ui-1'],
]),
viewIdToUniversalIdentifierMap: new Map([
['view-id-1', 'view-ui-1'],
]),
viewFieldGroupIdToUniversalIdentifierMap: new Map(),
}),
),
).toThrow(
expect.objectContaining({
code: FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
}),
);
});
});
});
@@ -0,0 +1,130 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { capitalize, isDefined } from 'twenty-shared/utils';
import { ALL_MANY_TO_ONE_METADATA_RELATIONS } from 'src/engine/metadata-modules/flat-entity/constant/all-many-to-one-metadata-relations.constant';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { type FromEntityToFlatEntityArgs } from 'src/engine/workspace-cache/types/from-entity-to-flat-entity-args.type';
type ManyToOneRelationsConfig<T extends AllMetadataName> =
(typeof ALL_MANY_TO_ONE_METADATA_RELATIONS)[T];
// Mirrors ResolvedForeignKeyIds from resolveUniversalRelationIdentifiersToIds but
// keyed on universalForeignKey, so the resolved record is the many-to-one part of a
// flat entity (plus the always-present applicationUniversalIdentifier).
export type ResolvedManyToOneRelationUniversalIdentifiers<
T extends AllMetadataName,
> = {
[K in keyof ManyToOneRelationsConfig<T> as ManyToOneRelationsConfig<T>[K] extends {
universalForeignKey: infer UniversalForeignKey extends string;
}
? UniversalForeignKey
: never]: ManyToOneRelationsConfig<T>[K] extends { isNullable: true }
? string | null
: string;
} & {
applicationUniversalIdentifier: string;
};
export const resolveManyToOneRelationIdsToUniversalIdentifiers = <
T extends AllMetadataName,
>({
metadataName,
entity,
...idToUniversalIdentifierMaps
}: {
metadataName: T;
} & FromEntityToFlatEntityArgs<T>): ResolvedManyToOneRelationUniversalIdentifiers<T> => {
const readEntityForeignKey = (
propertyName: string,
): string | null | undefined =>
entity[propertyName as keyof typeof entity] as string | null | undefined;
const entityId = readEntityForeignKey('id');
const resolvedUniversalIdentifierByForeignKey: Record<string, string | null> =
{};
const applicationId = readEntityForeignKey('applicationId');
const applicationUniversalIdentifier = isDefined(applicationId)
? idToUniversalIdentifierMaps.applicationIdToUniversalIdentifierMap.get(
applicationId,
)
: undefined;
if (!isDefined(applicationUniversalIdentifier)) {
throw new FlatEntityMapsException(
`Application with id ${applicationId} not found for ${metadataName} ${entityId}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
resolvedUniversalIdentifierByForeignKey.applicationUniversalIdentifier =
applicationUniversalIdentifier;
const relationEntries = ALL_MANY_TO_ONE_METADATA_RELATIONS[metadataName];
for (const relationPropertyName of Object.keys(relationEntries)) {
const relationEntry = relationEntries[
relationPropertyName as keyof typeof relationEntries
] as {
foreignKey: string;
metadataName: AllMetadataName;
isNullable: boolean;
universalForeignKey: string;
} | null;
if (!isDefined(relationEntry)) {
continue;
}
const {
foreignKey,
metadataName: targetMetadataName,
universalForeignKey,
isNullable,
} = relationEntry;
const foreignKeyId = readEntityForeignKey(foreignKey);
if (!isDefined(foreignKeyId)) {
if (isNullable) {
resolvedUniversalIdentifierByForeignKey[universalForeignKey] = null;
continue;
}
throw new FlatEntityMapsException(
`Missing non-nullable foreign key ${foreignKey} on ${metadataName} ${entityId} (relation to ${targetMetadataName})`,
FlatEntityMapsExceptionCode.ENTITY_MALFORMED,
);
}
const mapKey = `${targetMetadataName}IdToUniversalIdentifierMap`;
const targetIdToUniversalIdentifierMap = idToUniversalIdentifierMaps[
mapKey as keyof typeof idToUniversalIdentifierMaps
] as unknown as Map<string, string> | undefined;
if (!isDefined(targetIdToUniversalIdentifierMap)) {
throw new FlatEntityMapsException(
`Missing ${mapKey} when resolving ${metadataName} ${entityId}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
const universalIdentifier =
targetIdToUniversalIdentifierMap.get(foreignKeyId);
if (!isDefined(universalIdentifier)) {
throw new FlatEntityMapsException(
`${capitalize(targetMetadataName)} with id ${foreignKeyId} not found for ${metadataName} ${entityId}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
resolvedUniversalIdentifierByForeignKey[universalForeignKey] =
universalIdentifier;
}
return resolvedUniversalIdentifierByForeignKey as ResolvedManyToOneRelationUniversalIdentifiers<T>;
};
@@ -400,7 +400,6 @@ exports[`syncApplication should delete old field and create equivalent one when
"isSystem": false,
"isSystemSideEffect": false,
"isUIEditable": true,
"isUIReadOnly": false,
"isUnique": false,
"kanbanAggregateOperationViewIds": [],
"kanbanAggregateOperationViewUniversalIdentifiers": [],