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,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 ??
[]