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:
+22
-98
@@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user