Migrate Views-xxx Index Field Object Skill to be fully universal ( all actions and metadata runner and builder ) + all metadata update actions runner (#17687)

# What this PR does
Overall naming `universal` versus `flat` is not always the most updated
and so on
Will make a big cleaning tour after I've finished the whole migration
Migrating all `view` and ( filter fields etc ) `field` `object` `index`
to the universal pattern on all `services`, `builder` and `runner`
levels

## Universal and flat optimistic tooling

`addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow`
and its delete counterpart maintain the consistency of
`UniversalFlatEntityMaps` when an entity is created or removed. Beyond
inserting/removing the entity from its own maps, they walk through
`ALL_UNIVERSAL_METADATA_RELATIONS` to update the **aggregator arrays**
on related parent entities — the add appends the new entity's
`universalIdentifier` to the parent's aggregator (e.g. a new viewField's
identifier gets appended to its parent view's
`viewFieldUniversalIdentifiers`), and the delete filters it out. This
keeps the maps in sync so that diff computations and relation lookups
remain accurate throughout the migration building process.

## ALL_UNIVERSAL_METADATA_RELATIONS
`ALL_UNIVERSAL_METADATA_RELATIONS` is the universal counterpart of
`ALL_METADATA_RELATIONS`. It maps each metadata entity to its
many-to-one and one-to-many relations using universal foreign keys
(`*UniversalIdentifier`) instead of database IDs (`*Id`). This allows
migration actions to reference related entities in a workspace-agnostic
way. Relations that are workspace-specific (e.g. `workspace`,
`dataSource`, `userWorkspace`) are set to `null` and skipped during
resolution.

## `workspaceMigrationCreateIdEnrichment`
Reserved to API metadata ( will be able to validate at app installation
lvl )
- Workspace migration `create` actions now carry an optional `id` (and
`fieldIdByUniversalIdentifier` for object/field actions) so that
caller-provided IDs flow through the entire build-validate-run pipeline.
- New `enrichCreateWorkspaceMigrationActionsWithIds` utility resolves
`universalIdentifier → id` mappings after the builder runs and injects
them into the migration actions before the runner persists entities.
- Runner action handlers use the provided IDs instead of generating new
UUIDs, enabling deterministic entity creation for synchronization
workflows.


## `resolveUniversalUpdateRelationIdentifiersToIds`
`resolveUniversalUpdateRelationIdentifiersToIds` converts universal
identifiers (workspace-agnostic, stable keys) in a migration update
payload into concrete database UUIDs, so the update can be applied to a
specific workspace.

It iterates over the many-to-one relations defined in
`ALL_UNIVERSAL_METADATA_RELATIONS` for the given entity type, replaces
each `*UniversalIdentifier` property with its corresponding `*Id` by
looking up the target entity in `allFlatEntityMaps`, and throws if a
non-null identifier can't be resolved.

Used by all `update` action handlers in
`transpileUniversalActionToFlatAction`, avoiding duplicated resolution
logic across handlers.

## What this PR does not
- Migrating twenty-standard declaration to universal
- Migrating all the inputs transpilers to universal
- Migrating all metadata to be fully universal ( we still need to
de-scope the type of all of them and refactor their validator very close
)

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Paul Rastoin
2026-02-09 19:02:38 +01:00
committed by GitHub
parent 2a76e1791e
commit 8c951d3623
366 changed files with 10036 additions and 6606 deletions
-1
View File
@@ -18,7 +18,6 @@ IS_IMAP_SMTP_CALDAV_ENABLED=true
CALENDAR_PROVIDER_GOOGLE_ENABLED=false
MESSAGING_PROVIDER_MICROSOFT_ENABLED=false
CALENDAR_PROVIDER_MICROSOFT_ENABLED=false
TELEMETRY_ENABLED=false
AUTH_GOOGLE_CALLBACK_URL=http://localhost:3000/auth/google/redirect
AUTH_GOOGLE_APIS_CALLBACK_URL=http://localhost:3000/auth/google-apis/get-access-token
@@ -1,7 +1,7 @@
import { type FlatEntityPropertiesToCompare } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-to-compare.type';
import { type MetadataUniversalFlatEntityPropertiesToCompare } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/metadata-universal-flat-entity-properties-to-compare.type';
export const FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES = [
'label',
'description',
'icon',
] as const satisfies FlatEntityPropertiesToCompare<'fieldMetadata'>[];
] as const satisfies MetadataUniversalFlatEntityPropertiesToCompare<'fieldMetadata'>[];
@@ -17,7 +17,8 @@ import {
} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { findFlatEntityByUniversalIdentifierOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier-or-throw.util';
import { findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-universal-identifier-in-universal-flat-entity-maps-or-throw.util';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { fromCreateFieldInputToFlatFieldMetadatasToCreate } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-create-field-input-to-flat-field-metadatas-to-create.util';
import { fromDeleteFieldInputToFlatFieldMetadatasToDelete } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-delete-field-input-to-flat-field-metadatas-to-delete.util';
@@ -111,6 +112,13 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
});
const deletedFlatFieldMetadata = findFlatEntityByUniversalIdentifierOrThrow(
{
universalIdentifier: flatFieldMetadatasToDelete[0].universalIdentifier,
flatEntityMaps: existingFlatFieldMetadataMaps,
},
);
const validateAndBuildResult =
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
{
@@ -140,7 +148,7 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
);
}
return flatFieldMetadatasToDelete[0];
return deletedFlatFieldMetadata;
}
async updateOneField({
@@ -340,7 +348,6 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
createFieldInput,
workspaceId,
flatApplication: resolvedOwnerFlatApplication,
}),
);
@@ -402,12 +409,15 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
},
);
return findManyFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityIds: allTranspiledTranspilationInputs.map(
({ result: { flatFieldMetadatas } }) => flatFieldMetadatas[0].id,
),
flatEntityMaps: recomputedFlatFieldMetadataMaps,
});
return findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrow(
{
universalIdentifiers: allTranspiledTranspilationInputs.map(
({ result: { flatFieldMetadatas } }) =>
flatFieldMetadatas[0].universalIdentifier,
),
flatEntityMaps: recomputedFlatFieldMetadataMaps,
},
);
}
public async findOneWithinWorkspace(
@@ -1,4 +1,4 @@
import { type FlatAgent } from 'src/engine/metadata-modules/flat-agent/types/flat-agent.type';
import { type MetadataEntityPropertyName } from 'src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant';
export const FLAT_AGENT_EDITABLE_PROPERTIES = [
'name',
@@ -10,4 +10,4 @@ export const FLAT_AGENT_EDITABLE_PROPERTIES = [
'responseFormat',
'modelConfiguration',
'evaluationInputs',
] as const satisfies (keyof FlatAgent)[];
] as const satisfies MetadataEntityPropertyName<'agent'>[];
@@ -1,4 +1,4 @@
import { type FlatCommandMenuItem } from 'src/engine/metadata-modules/flat-command-menu-item/types/flat-command-menu-item.type';
import { type MetadataEntityPropertyName } from 'src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant';
export const FLAT_COMMAND_MENU_ITEM_EDITABLE_PROPERTIES = [
'label',
@@ -6,4 +6,4 @@ export const FLAT_COMMAND_MENU_ITEM_EDITABLE_PROPERTIES = [
'isPinned',
'availabilityType',
'availabilityObjectMetadataId',
] as const satisfies (keyof FlatCommandMenuItem)[];
] as const satisfies MetadataEntityPropertyName<'commandMenuItem'>[];
@@ -0,0 +1,297 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ALL_UNIVERSAL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY should match snapshot 1`] = `
{
"agent": {
"propertiesToCompare": [
"name",
"label",
"icon",
"description",
"prompt",
"modelId",
"responseFormat",
"modelConfiguration",
"evaluationInputs",
],
"propertiesToStringify": [
"responseFormat",
"modelConfiguration",
"evaluationInputs",
],
},
"commandMenuItem": {
"propertiesToCompare": [
"label",
"icon",
"isPinned",
"availabilityType",
"availabilityObjectMetadataUniversalIdentifier",
],
"propertiesToStringify": [],
},
"fieldMetadata": {
"propertiesToCompare": [
"defaultValue",
"description",
"icon",
"isActive",
"isLabelSyncedWithName",
"isUnique",
"label",
"name",
"options",
"standardOverrides",
"universalSettings",
],
"propertiesToStringify": [
"defaultValue",
"options",
"standardOverrides",
"universalSettings",
],
},
"frontComponent": {
"propertiesToCompare": [
"name",
"description",
"builtComponentChecksum",
"sourceComponentPath",
"builtComponentPath",
"componentName",
],
"propertiesToStringify": [],
},
"index": {
"propertiesToCompare": [
"indexType",
"indexWhereClause",
"flatIndexFieldMetadatas",
"isUnique",
"name",
],
"propertiesToStringify": [
"flatIndexFieldMetadatas",
],
},
"logicFunction": {
"propertiesToCompare": [
"name",
"description",
"timeoutSeconds",
"checksum",
"sourceHandlerPath",
"handlerName",
"toolInputSchema",
"isTool",
"deletedAt",
"cronTriggerSettings",
"databaseEventTriggerSettings",
"httpRouteTriggerSettings",
],
"propertiesToStringify": [
"toolInputSchema",
"cronTriggerSettings",
"databaseEventTriggerSettings",
"httpRouteTriggerSettings",
],
},
"navigationMenuItem": {
"propertiesToCompare": [
"position",
"folderUniversalIdentifier",
"name",
],
"propertiesToStringify": [],
},
"objectMetadata": {
"propertiesToCompare": [
"description",
"icon",
"isActive",
"isLabelSyncedWithName",
"labelPlural",
"labelSingular",
"namePlural",
"nameSingular",
"labelIdentifierFieldMetadataUniversalIdentifier",
"standardOverrides",
],
"propertiesToStringify": [
"standardOverrides",
],
},
"pageLayout": {
"propertiesToCompare": [
"name",
"type",
"objectMetadataUniversalIdentifier",
"deletedAt",
],
"propertiesToStringify": [],
},
"pageLayoutTab": {
"propertiesToCompare": [
"title",
"position",
"deletedAt",
],
"propertiesToStringify": [],
},
"pageLayoutWidget": {
"propertiesToCompare": [
"title",
"type",
"objectMetadataUniversalIdentifier",
"gridPosition",
"position",
"universalConfiguration",
"deletedAt",
],
"propertiesToStringify": [
"gridPosition",
"position",
"universalConfiguration",
],
},
"role": {
"propertiesToCompare": [
"label",
"description",
"icon",
"canUpdateAllSettings",
"canAccessAllTools",
"canReadAllObjectRecords",
"canUpdateAllObjectRecords",
"canSoftDeleteAllObjectRecords",
"canDestroyAllObjectRecords",
"canBeAssignedToUsers",
"canBeAssignedToAgents",
"canBeAssignedToApiKeys",
],
"propertiesToStringify": [],
},
"roleTarget": {
"propertiesToCompare": [
"roleUniversalIdentifier",
"userWorkspaceId",
"apiKeyId",
"agentId",
],
"propertiesToStringify": [],
},
"rowLevelPermissionPredicate": {
"propertiesToCompare": [
"fieldMetadataUniversalIdentifier",
"operand",
"value",
"rowLevelPermissionPredicateGroupUniversalIdentifier",
"positionInRowLevelPermissionPredicateGroup",
"subFieldName",
"workspaceMemberFieldMetadataUniversalIdentifier",
"workspaceMemberSubFieldName",
"deletedAt",
],
"propertiesToStringify": [
"value",
],
},
"rowLevelPermissionPredicateGroup": {
"propertiesToCompare": [
"logicalOperator",
"positionInRowLevelPermissionPredicateGroup",
"parentRowLevelPermissionPredicateGroupUniversalIdentifier",
"deletedAt",
],
"propertiesToStringify": [],
},
"skill": {
"propertiesToCompare": [
"name",
"label",
"icon",
"description",
"content",
"isActive",
],
"propertiesToStringify": [],
},
"view": {
"propertiesToCompare": [
"key",
"deletedAt",
"createdByUserWorkspaceId",
"name",
"type",
"icon",
"position",
"isCompact",
"openRecordIn",
"kanbanAggregateOperation",
"kanbanAggregateOperationFieldMetadataUniversalIdentifier",
"anyFieldFilterValue",
"calendarLayout",
"calendarFieldMetadataUniversalIdentifier",
"visibility",
"mainGroupByFieldMetadataUniversalIdentifier",
"shouldHideEmptyGroups",
],
"propertiesToStringify": [],
},
"viewField": {
"propertiesToCompare": [
"isVisible",
"size",
"position",
"aggregateOperation",
"deletedAt",
],
"propertiesToStringify": [],
},
"viewFilter": {
"propertiesToCompare": [
"viewUniversalIdentifier",
"deletedAt",
"fieldMetadataUniversalIdentifier",
"operand",
"value",
"viewFilterGroupUniversalIdentifier",
"positionInViewFilterGroup",
"subFieldName",
],
"propertiesToStringify": [
"value",
],
},
"viewFilterGroup": {
"propertiesToCompare": [
"viewUniversalIdentifier",
"deletedAt",
"parentViewFilterGroupUniversalIdentifier",
"logicalOperator",
"positionInViewFilterGroup",
],
"propertiesToStringify": [],
},
"viewGroup": {
"propertiesToCompare": [
"isVisible",
"fieldValue",
"position",
"deletedAt",
],
"propertiesToStringify": [],
},
"webhook": {
"propertiesToCompare": [
"targetUrl",
"operations",
"description",
"secret",
],
"propertiesToStringify": [
"operations",
],
},
}
`;
@@ -0,0 +1,16 @@
import { ALL_METADATA_NAME } from 'twenty-shared/metadata';
import { ALL_UNIVERSAL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY } from 'src/engine/metadata-modules/flat-entity/constant/all-universal-flat-entity-properties-to-compare-and-stringify.constant';
describe('ALL_UNIVERSAL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY', () => {
it('should match snapshot', () => {
expect(
Object.keys(
ALL_UNIVERSAL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY,
),
).toMatchObject(Object.values(ALL_METADATA_NAME));
expect(
ALL_UNIVERSAL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY,
).toMatchSnapshot();
});
});
@@ -0,0 +1,356 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type MetadataEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-entity.type';
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
import { type MetadataManyToOneJoinColumn } from 'src/engine/metadata-modules/flat-entity/types/metadata-many-to-one-join-column.type';
import { type AllJsonbPropertiesWithSerializedPropertiesForMetadataName } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/constants/all-jsonb-properties-with-serialized-relation-by-metadata-name.constant';
import { type ToUniversalForeignKey } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/constants/all-universal-metadata-relations.constant';
import { type ExtractJsonbProperties } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/extract-jsonb-properties.type';
import { type UniversalFlatEntityExtraProperties } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-from.type';
type HasObjectInUnion<T> = T extends unknown
? T extends object
? true
: false
: never;
type MetadataEntityPropertyConfiguration<
TMetadataName extends AllMetadataName,
> = {
[K in keyof Omit<
MetadataFlatEntity<TMetadataName>,
| Extract<
keyof MetadataFlatEntity<TMetadataName>,
keyof UniversalFlatEntityExtraProperties<
MetadataEntity<TMetadataName>,
TMetadataName
>
>
| '__universal'
>]?: {
universalProperty: K extends AllJsonbPropertiesWithSerializedPropertiesForMetadataName<TMetadataName> &
string
? `universal${Capitalize<K>}`
: K extends MetadataManyToOneJoinColumn<TMetadataName> & string
? ToUniversalForeignKey<K>
: undefined;
toStringify: K extends ExtractJsonbProperties<MetadataEntity<TMetadataName>>
? true
: K extends keyof MetadataEntity<TMetadataName>
? HasObjectInUnion<MetadataEntity<TMetadataName>[K]>
: boolean;
};
};
export const ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME = {
fieldMetadata: {
defaultValue: { toStringify: true, universalProperty: undefined },
description: { toStringify: false, universalProperty: undefined },
icon: { toStringify: false, universalProperty: undefined },
isActive: { toStringify: false, universalProperty: undefined },
isLabelSyncedWithName: { toStringify: false, universalProperty: undefined },
isUnique: { toStringify: false, universalProperty: undefined },
label: { toStringify: false, universalProperty: undefined },
name: { toStringify: false, universalProperty: undefined },
options: { toStringify: true, universalProperty: undefined },
standardOverrides: { toStringify: true, universalProperty: undefined },
settings: { toStringify: true, universalProperty: 'universalSettings' },
},
objectMetadata: {
description: { toStringify: false, universalProperty: undefined },
icon: { toStringify: false, universalProperty: undefined },
isActive: { toStringify: false, universalProperty: undefined },
isLabelSyncedWithName: { toStringify: false, universalProperty: undefined },
labelPlural: { toStringify: false, universalProperty: undefined },
labelSingular: { toStringify: false, universalProperty: undefined },
namePlural: { toStringify: false, universalProperty: undefined },
nameSingular: { toStringify: false, universalProperty: undefined },
labelIdentifierFieldMetadataId: {
toStringify: false,
// @ts-expect-error remove once https://github.com/twentyhq/core-team-issues/issues/2172 has been resolved
universalProperty: 'labelIdentifierFieldMetadataUniversalIdentifier',
},
standardOverrides: { toStringify: true, universalProperty: undefined },
},
view: {
key: { toStringify: false, universalProperty: undefined },
deletedAt: { toStringify: false, universalProperty: undefined },
createdByUserWorkspaceId: {
toStringify: false,
universalProperty: undefined,
},
name: { toStringify: false, universalProperty: undefined },
type: { toStringify: false, universalProperty: undefined },
icon: { toStringify: false, universalProperty: undefined },
position: { toStringify: false, universalProperty: undefined },
isCompact: { toStringify: false, universalProperty: undefined },
openRecordIn: { toStringify: false, universalProperty: undefined },
kanbanAggregateOperation: {
toStringify: false,
universalProperty: undefined,
},
kanbanAggregateOperationFieldMetadataId: {
toStringify: false,
universalProperty:
'kanbanAggregateOperationFieldMetadataUniversalIdentifier',
},
anyFieldFilterValue: { toStringify: false, universalProperty: undefined },
calendarLayout: { toStringify: false, universalProperty: undefined },
calendarFieldMetadataId: {
toStringify: false,
universalProperty: 'calendarFieldMetadataUniversalIdentifier',
},
visibility: { toStringify: false, universalProperty: undefined },
mainGroupByFieldMetadataId: {
toStringify: false,
universalProperty: 'mainGroupByFieldMetadataUniversalIdentifier',
},
shouldHideEmptyGroups: { toStringify: false, universalProperty: undefined },
},
viewField: {
isVisible: { toStringify: false, universalProperty: undefined },
size: { toStringify: false, universalProperty: undefined },
position: { toStringify: false, universalProperty: undefined },
aggregateOperation: { toStringify: false, universalProperty: undefined },
deletedAt: { toStringify: false, universalProperty: undefined },
},
viewGroup: {
isVisible: { toStringify: false, universalProperty: undefined },
fieldValue: { toStringify: false, universalProperty: undefined },
position: { toStringify: false, universalProperty: undefined },
deletedAt: { toStringify: false, universalProperty: undefined },
},
index: {
indexType: { toStringify: false, universalProperty: undefined },
indexWhereClause: { toStringify: false, universalProperty: undefined },
flatIndexFieldMetadatas: {
toStringify: true,
universalProperty: undefined,
},
isUnique: { toStringify: false, universalProperty: undefined },
name: { toStringify: false, universalProperty: undefined },
},
logicFunction: {
name: { toStringify: false, universalProperty: undefined },
description: { toStringify: false, universalProperty: undefined },
timeoutSeconds: { toStringify: false, universalProperty: undefined },
checksum: { toStringify: false, universalProperty: undefined },
sourceHandlerPath: { toStringify: false, universalProperty: undefined },
handlerName: { toStringify: false, universalProperty: undefined },
toolInputSchema: { toStringify: true, universalProperty: undefined },
isTool: { toStringify: false, universalProperty: undefined },
deletedAt: { toStringify: false, universalProperty: undefined },
cronTriggerSettings: { toStringify: true, universalProperty: undefined },
databaseEventTriggerSettings: {
toStringify: true,
universalProperty: undefined,
},
httpRouteTriggerSettings: {
toStringify: true,
universalProperty: undefined,
},
},
viewFilter: {
viewId: {
toStringify: false,
universalProperty: 'viewUniversalIdentifier',
},
deletedAt: { toStringify: false, universalProperty: undefined },
fieldMetadataId: {
toStringify: false,
universalProperty: 'fieldMetadataUniversalIdentifier',
},
operand: { toStringify: false, universalProperty: undefined },
value: { toStringify: true, universalProperty: undefined },
viewFilterGroupId: {
toStringify: false,
universalProperty: 'viewFilterGroupUniversalIdentifier',
},
positionInViewFilterGroup: {
toStringify: false,
universalProperty: undefined,
},
subFieldName: { toStringify: false, universalProperty: undefined },
},
role: {
label: { toStringify: false, universalProperty: undefined },
description: { toStringify: false, universalProperty: undefined },
icon: { toStringify: false, universalProperty: undefined },
canUpdateAllSettings: { toStringify: false, universalProperty: undefined },
canAccessAllTools: { toStringify: false, universalProperty: undefined },
canReadAllObjectRecords: {
toStringify: false,
universalProperty: undefined,
},
canUpdateAllObjectRecords: {
toStringify: false,
universalProperty: undefined,
},
canSoftDeleteAllObjectRecords: {
toStringify: false,
universalProperty: undefined,
},
canDestroyAllObjectRecords: {
toStringify: false,
universalProperty: undefined,
},
canBeAssignedToUsers: { toStringify: false, universalProperty: undefined },
canBeAssignedToAgents: { toStringify: false, universalProperty: undefined },
canBeAssignedToApiKeys: {
toStringify: false,
universalProperty: undefined,
},
},
roleTarget: {
roleId: {
toStringify: false,
universalProperty: 'roleUniversalIdentifier',
},
userWorkspaceId: { toStringify: false, universalProperty: undefined },
apiKeyId: { toStringify: false, universalProperty: undefined },
agentId: { toStringify: false, universalProperty: undefined },
},
agent: {
name: { toStringify: false, universalProperty: undefined },
label: { toStringify: false, universalProperty: undefined },
icon: { toStringify: false, universalProperty: undefined },
description: { toStringify: false, universalProperty: undefined },
prompt: { toStringify: false, universalProperty: undefined },
modelId: { toStringify: false, universalProperty: undefined },
responseFormat: { toStringify: true, universalProperty: undefined },
modelConfiguration: { toStringify: true, universalProperty: undefined },
evaluationInputs: { toStringify: true, universalProperty: undefined },
},
pageLayout: {
name: { toStringify: false, universalProperty: undefined },
type: { toStringify: false, universalProperty: undefined },
objectMetadataId: {
toStringify: false,
universalProperty: 'objectMetadataUniversalIdentifier',
},
deletedAt: { toStringify: false, universalProperty: undefined },
},
pageLayoutWidget: {
title: { toStringify: false, universalProperty: undefined },
type: { toStringify: false, universalProperty: undefined },
objectMetadataId: {
toStringify: false,
universalProperty: 'objectMetadataUniversalIdentifier',
},
gridPosition: { toStringify: true, universalProperty: undefined },
position: { toStringify: true, universalProperty: undefined },
configuration: {
toStringify: true,
universalProperty: 'universalConfiguration',
},
deletedAt: { toStringify: false, universalProperty: undefined },
},
pageLayoutTab: {
title: { toStringify: false, universalProperty: undefined },
position: { toStringify: false, universalProperty: undefined },
deletedAt: { toStringify: false, universalProperty: undefined },
},
skill: {
name: { toStringify: false, universalProperty: undefined },
label: { toStringify: false, universalProperty: undefined },
icon: { toStringify: false, universalProperty: undefined },
description: { toStringify: false, universalProperty: undefined },
content: { toStringify: false, universalProperty: undefined },
isActive: { toStringify: false, universalProperty: undefined },
},
commandMenuItem: {
label: { toStringify: false, universalProperty: undefined },
icon: { toStringify: false, universalProperty: undefined },
isPinned: { toStringify: false, universalProperty: undefined },
availabilityType: { toStringify: false, universalProperty: undefined },
availabilityObjectMetadataId: {
toStringify: false,
universalProperty: 'availabilityObjectMetadataUniversalIdentifier',
},
},
navigationMenuItem: {
position: { toStringify: false, universalProperty: undefined },
folderId: {
toStringify: false,
universalProperty: 'folderUniversalIdentifier',
},
name: { toStringify: false, universalProperty: undefined },
},
rowLevelPermissionPredicate: {
fieldMetadataId: {
toStringify: false,
universalProperty: 'fieldMetadataUniversalIdentifier',
},
operand: { toStringify: false, universalProperty: undefined },
value: { toStringify: true, universalProperty: undefined },
rowLevelPermissionPredicateGroupId: {
toStringify: false,
universalProperty: 'rowLevelPermissionPredicateGroupUniversalIdentifier',
},
positionInRowLevelPermissionPredicateGroup: {
toStringify: false,
universalProperty: undefined,
},
subFieldName: { toStringify: false, universalProperty: undefined },
workspaceMemberFieldMetadataId: {
toStringify: false,
universalProperty: 'workspaceMemberFieldMetadataUniversalIdentifier',
},
workspaceMemberSubFieldName: {
toStringify: false,
universalProperty: undefined,
},
deletedAt: { toStringify: false, universalProperty: undefined },
},
rowLevelPermissionPredicateGroup: {
logicalOperator: { toStringify: false, universalProperty: undefined },
positionInRowLevelPermissionPredicateGroup: {
toStringify: false,
universalProperty: undefined,
},
parentRowLevelPermissionPredicateGroupId: {
toStringify: false,
universalProperty:
'parentRowLevelPermissionPredicateGroupUniversalIdentifier',
},
deletedAt: { toStringify: false, universalProperty: undefined },
},
viewFilterGroup: {
viewId: {
toStringify: false,
universalProperty: 'viewUniversalIdentifier',
},
deletedAt: { toStringify: false, universalProperty: undefined },
parentViewFilterGroupId: {
toStringify: false,
universalProperty: 'parentViewFilterGroupUniversalIdentifier',
},
logicalOperator: { toStringify: false, universalProperty: undefined },
positionInViewFilterGroup: {
toStringify: false,
universalProperty: undefined,
},
},
frontComponent: {
name: { toStringify: false, universalProperty: undefined },
description: { toStringify: false, universalProperty: undefined },
builtComponentChecksum: {
toStringify: false,
universalProperty: undefined,
},
sourceComponentPath: { toStringify: false, universalProperty: undefined },
builtComponentPath: { toStringify: false, universalProperty: undefined },
componentName: { toStringify: false, universalProperty: undefined },
},
webhook: {
targetUrl: { toStringify: false, universalProperty: undefined },
operations: { toStringify: true, universalProperty: undefined },
description: { toStringify: false, universalProperty: undefined },
secret: { toStringify: false, universalProperty: undefined },
},
} as const satisfies {
[P in AllMetadataName]: MetadataEntityPropertyConfiguration<P>;
};
export type MetadataEntityPropertyName<T extends AllMetadataName> =
keyof (typeof ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME)[T];
@@ -1,169 +0,0 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { FLAT_AGENT_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-agent/constants/flat-agent-editable-properties.constant';
import { FLAT_COMMAND_MENU_ITEM_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-command-menu-item/constants/flat-command-menu-item-editable-properties.constant';
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
import { FLAT_FIELD_METADATA_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-editable-properties.constant';
import { FLAT_FRONT_COMPONENT_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-front-component/constants/flat-front-component-editable-properties.constant';
import { FLAT_NAVIGATION_MENU_ITEM_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-navigation-menu-item/constants/flat-navigation-menu-item-editable-properties.constant';
import { FLAT_OBJECT_METADATA_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-object-metadata/constants/flat-object-metadata-editable-properties.constant';
import { FLAT_PAGE_LAYOUT_TAB_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-page-layout-tab/constants/flat-page-layout-tab-editable-properties.constant';
import { FLAT_PAGE_LAYOUT_WIDGET_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-page-layout-widget/constants/flat-page-layout-widget-editable-properties.constant';
import { FLAT_PAGE_LAYOUT_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-page-layout/constants/flat-page-layout-editable-properties.constant';
import { FLAT_ROLE_TARGET_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-role-target/constants/flat-role-target-editable-properties.constant';
import { FLAT_ROLE_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-role/constants/flat-role-editable-properties.constant';
import { FLAT_ROW_LEVEL_PERMISSION_PREDICATE_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-row-level-permission-predicate/constants/flat-row-level-permission-predicate-editable-properties.constant';
import { FLAT_ROW_LEVEL_PERMISSION_PREDICATE_GROUP_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-row-level-permission-predicate/constants/flat-row-level-permission-predicate-group-editable-properties.constant';
import { FLAT_SKILL_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-skill/constants/flat-skill-editable-properties.constant';
import { FLAT_VIEW_FIELD_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-view-field/constants/flat-view-field-editable-properties.constant';
import { FLAT_VIEW_FILTER_GROUP_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-view-filter-group/constants/flat-view-filter-group-editable-properties.constant';
import { FLAT_VIEW_FILTER_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-view-filter/constants/flat-view-filter-editable-properties.constant';
import { FLAT_VIEW_GROUP_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-view-group/constants/flat-view-group-editable-properties.constant';
import { FLAT_VIEW_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-view/constants/flat-view-editable-properties.constant';
import { FLAT_LOGIC_FUNCTION_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/logic-function/constants/flat-logic-function-editable-properties.constant';
type OneFlatEntityConfiguration<T extends AllMetadataName> = {
propertiesToCompare: (keyof MetadataFlatEntity<T>)[];
propertiesToStringify: (keyof MetadataFlatEntity<T>)[];
};
export const ALL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY = {
fieldMetadata: {
propertiesToCompare: [
...FLAT_FIELD_METADATA_EDITABLE_PROPERTIES.custom,
'standardOverrides',
],
propertiesToStringify: [
'options',
'settings',
'standardOverrides',
'defaultValue',
],
},
objectMetadata: {
propertiesToCompare: [
...FLAT_OBJECT_METADATA_EDITABLE_PROPERTIES.custom,
'standardOverrides',
],
propertiesToStringify: ['standardOverrides'],
},
view: {
propertiesToCompare: [
'key',
'deletedAt',
'createdByUserWorkspaceId',
...FLAT_VIEW_EDITABLE_PROPERTIES,
],
propertiesToStringify: [],
},
viewField: {
propertiesToCompare: [...FLAT_VIEW_FIELD_EDITABLE_PROPERTIES, 'deletedAt'],
propertiesToStringify: [],
},
viewGroup: {
propertiesToCompare: [...FLAT_VIEW_GROUP_EDITABLE_PROPERTIES, 'deletedAt'],
propertiesToStringify: [],
},
index: {
propertiesToCompare: [
'indexType',
'indexWhereClause',
'flatIndexFieldMetadatas',
'isUnique',
'name',
],
propertiesToStringify: ['flatIndexFieldMetadatas'],
},
logicFunction: {
propertiesToCompare: [
...FLAT_LOGIC_FUNCTION_EDITABLE_PROPERTIES,
'deletedAt',
],
propertiesToStringify: ['toolInputSchema'],
},
viewFilter: {
propertiesToCompare: [
'viewId',
'deletedAt',
...FLAT_VIEW_FILTER_EDITABLE_PROPERTIES,
],
propertiesToStringify: ['value'],
},
role: {
propertiesToCompare: [...FLAT_ROLE_EDITABLE_PROPERTIES],
propertiesToStringify: [],
},
roleTarget: {
propertiesToCompare: [...FLAT_ROLE_TARGET_EDITABLE_PROPERTIES],
propertiesToStringify: [],
},
agent: {
propertiesToCompare: [...FLAT_AGENT_EDITABLE_PROPERTIES],
propertiesToStringify: [
'responseFormat',
'modelConfiguration',
'evaluationInputs',
],
},
pageLayout: {
propertiesToCompare: [...FLAT_PAGE_LAYOUT_EDITABLE_PROPERTIES, 'deletedAt'],
propertiesToStringify: [],
},
pageLayoutWidget: {
propertiesToCompare: [
...FLAT_PAGE_LAYOUT_WIDGET_EDITABLE_PROPERTIES,
'deletedAt',
],
propertiesToStringify: ['gridPosition', 'configuration'],
},
pageLayoutTab: {
propertiesToCompare: [
...FLAT_PAGE_LAYOUT_TAB_EDITABLE_PROPERTIES,
'deletedAt',
],
propertiesToStringify: [],
},
skill: {
propertiesToCompare: [...FLAT_SKILL_EDITABLE_PROPERTIES],
propertiesToStringify: [],
},
commandMenuItem: {
propertiesToCompare: [...FLAT_COMMAND_MENU_ITEM_EDITABLE_PROPERTIES],
propertiesToStringify: [],
},
navigationMenuItem: {
propertiesToCompare: [...FLAT_NAVIGATION_MENU_ITEM_EDITABLE_PROPERTIES],
propertiesToStringify: [],
},
rowLevelPermissionPredicate: {
propertiesToCompare: [
...FLAT_ROW_LEVEL_PERMISSION_PREDICATE_EDITABLE_PROPERTIES,
'deletedAt',
],
propertiesToStringify: ['value'],
},
rowLevelPermissionPredicateGroup: {
propertiesToCompare: [
...FLAT_ROW_LEVEL_PERMISSION_PREDICATE_GROUP_EDITABLE_PROPERTIES,
'deletedAt',
],
propertiesToStringify: [],
},
viewFilterGroup: {
propertiesToCompare: [
'viewId',
'deletedAt',
...FLAT_VIEW_FILTER_GROUP_EDITABLE_PROPERTIES,
],
propertiesToStringify: [],
},
frontComponent: {
propertiesToCompare: [...FLAT_FRONT_COMPONENT_EDITABLE_PROPERTIES],
propertiesToStringify: [],
},
webhook: {
propertiesToCompare: ['targetUrl', 'operations', 'description', 'secret'],
propertiesToStringify: ['operations'],
},
} as const satisfies {
[P in AllMetadataName]: OneFlatEntityConfiguration<P>;
};
@@ -9,8 +9,9 @@ import { type ExtractEntityOneToManyEntityRelationProperties } from 'src/engine/
import { type FromMetadataEntityToMetadataName } from 'src/engine/metadata-modules/flat-entity/types/from-metadata-entity-to-metadata-name.type';
import { type MetadataEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-entity.type';
import { type SyncableEntity } from 'src/engine/workspace-manager/types/syncable-entity.interface';
import { type AllJsonbPropertiesWithSerializedPropertiesForMetadataName } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/constants/all-jsonb-properties-with-serialized-relation-by-metadata-name.constant';
export type ManyToOneRelationValue<
export type MetadataManyToOneRelationConfiguration<
TSourceMetadataName extends AllMetadataName,
TRelationProperty extends ExtractEntityManyToOneEntityRelationProperties<
MetadataEntity<TSourceMetadataName>
@@ -24,7 +25,6 @@ export type ManyToOneRelationValue<
flatEntityForeignKeyAggregator:
| keyof AddSuffixToEntityOneToManyProperties<TTargetEntity, 'ids'>
| null;
// Note: In the best of the world should not be nullable, entities should always declare inverside keys
foreignKey: ExtractPropertiesThatEndsWithId<
MetadataEntity<TSourceMetadataName>,
'id' | 'workspaceId'
@@ -33,35 +33,44 @@ export type ManyToOneRelationValue<
? true
: false;
}
: null;
: // Note: In the best of the world should not be nullable, entities should always declare inverside keys
null;
type OneToManyRelationValue<
TSourceMetadataName extends AllMetadataName,
TRelationProperty extends ExtractEntityOneToManyEntityRelationProperties<
MetadataEntity<TSourceMetadataName>
>,
> =
MetadataEntity<TSourceMetadataName>[TRelationProperty] extends Relation<
(infer TTargetEntity extends SyncableEntity)[]
>
? {
metadataName: FromMetadataEntityToMetadataName<TTargetEntity>;
}
: null;
> = MetadataEntity<TSourceMetadataName>[TRelationProperty] extends (infer TTargetEntity extends
SyncableEntity)[]
? {
metadataName: FromMetadataEntityToMetadataName<TTargetEntity>;
}
: null;
type MetadataRelationsProperties = {
[TSourceMetadataName in AllMetadataName]: {
manyToOne: {
[TRelationProperty in ExtractEntityManyToOneEntityRelationProperties<
MetadataEntity<TSourceMetadataName>
>]: ManyToOneRelationValue<TSourceMetadataName, TRelationProperty>;
>]: MetadataManyToOneRelationConfiguration<
TSourceMetadataName,
TRelationProperty
>;
};
oneToMany: {
[TRelationProperty in ExtractEntityOneToManyEntityRelationProperties<
MetadataEntity<TSourceMetadataName>
>]: OneToManyRelationValue<TSourceMetadataName, TRelationProperty>;
};
};
} & ([
AllJsonbPropertiesWithSerializedPropertiesForMetadataName<TSourceMetadataName>,
] extends [never]
? // eslint-disable-next-line @typescript-eslint/no-empty-object-type
{}
: {
serializedRelations: Partial<Record<AllMetadataName, true>>;
});
};
export const ALL_METADATA_RELATIONS = {
@@ -156,6 +165,9 @@ export const ALL_METADATA_RELATIONS = {
calendarViews: { metadataName: 'view' },
mainGroupByFieldMetadataViews: { metadataName: 'view' },
},
serializedRelations: {
fieldMetadata: true,
},
},
objectMetadata: {
manyToOne: {
@@ -378,6 +390,9 @@ export const ALL_METADATA_RELATIONS = {
application: null,
},
oneToMany: {},
serializedRelations: {
fieldMetadata: true,
},
},
rowLevelPermissionPredicate: {
manyToOne: {
@@ -11,6 +11,7 @@ type MetadataRequiredForValidation = {
};
};
// TODO deprecate in favor of ALL_METADATA_RELATIONS
export const ALL_METADATA_REQUIRED_METADATA_FOR_VALIDATION = {
fieldMetadata: {
objectMetadata: true,
@@ -0,0 +1,58 @@
import {
ALL_METADATA_NAME,
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 MetadataUniversalFlatEntityPropertiesToCompare } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/metadata-universal-flat-entity-properties-to-compare.type';
import { type MetadataUniversalFlatEntityPropertiesToStringify } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/metadata-universal-flat-entity-properties-to-stringify.type';
type UniversalFlatEntityPropertiesToCompareAndStringify<
T extends AllMetadataName,
> = {
propertiesToCompare: MetadataUniversalFlatEntityPropertiesToCompare<T>[];
propertiesToStringify: MetadataUniversalFlatEntityPropertiesToStringify<T>[];
};
const computeUniversalFlatEntityPropertiesToCompareAndStringify = <
T extends AllMetadataName,
>(
metadataName: T,
): UniversalFlatEntityPropertiesToCompareAndStringify<T> => {
const entries = Object.entries(
ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME[metadataName],
) as [
string,
{ universalProperty: string | undefined; toStringify: boolean },
][];
const accumulator: UniversalFlatEntityPropertiesToCompareAndStringify<T> = {
propertiesToCompare: [],
propertiesToStringify: [],
};
for (const [property, configuration] of entries) {
const comparedProperty = configuration.universalProperty ?? property;
accumulator.propertiesToCompare.push(
comparedProperty as MetadataUniversalFlatEntityPropertiesToCompare<T>,
);
if (configuration.toStringify === true) {
accumulator.propertiesToStringify.push(
comparedProperty as MetadataUniversalFlatEntityPropertiesToStringify<T>,
);
}
}
return accumulator;
};
export const ALL_UNIVERSAL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY =
Object.values(ALL_METADATA_NAME).reduce(
(acc, metadataName) => ({
...acc,
[metadataName]:
computeUniversalFlatEntityPropertiesToCompareAndStringify(metadataName),
}),
{} as {
[P in AllMetadataName]: UniversalFlatEntityPropertiesToCompareAndStringify<P>;
},
);
@@ -18,7 +18,8 @@ type ExpectedGenericFlatEntityInformation = {
[P in WorkspaceMigrationActionType]: unknown;
};
flatEntity: SyncableFlatEntity;
universalFlatEntity: UniversalSyncableFlatEntity;
// TODO remove SyncableFlatEntity once every metadata has been universal migrated
universalFlatEntity: UniversalSyncableFlatEntity | SyncableFlatEntity;
entity: unknown;
};
@@ -0,0 +1,62 @@
import {
type HasAllProperties,
type Equal,
type Expect,
} from 'twenty-shared/testing';
import { type FlatEntityUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-update.type';
// eslint-disable-next-line unused-imports/no-unused-vars
type Assertions = [
Expect<
Equal<
keyof FlatEntityUpdate<'fieldMetadata'>,
| 'name'
| 'label'
| 'icon'
| 'description'
| 'isActive'
| 'defaultValue'
| 'standardOverrides'
| 'options'
| 'settings'
| 'isUnique'
| 'isLabelSyncedWithName'
| 'universalSettings'
>
>,
Expect<
HasAllProperties<
FlatEntityUpdate<'fieldMetadata'>,
{
universalSettings?: never;
}
>
>,
Expect<
Equal<
keyof FlatEntityUpdate<'objectMetadata'>,
| 'icon'
| 'description'
| 'isActive'
| 'standardOverrides'
| 'isLabelSyncedWithName'
| 'nameSingular'
| 'namePlural'
| 'labelSingular'
| 'labelPlural'
| 'labelIdentifierFieldMetadataId'
| 'labelIdentifierFieldMetadataUniversalIdentifier'
>
>,
Expect<
HasAllProperties<
FlatEntityUpdate<'objectMetadata'>,
{
labelIdentifierFieldMetadataUniversalIdentifier?: never;
}
>
>,
];
@@ -1,5 +1,3 @@
import { type AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity';
import { type CommandMenuItemEntity } from 'src/engine/metadata-modules/command-menu-item/entities/command-menu-item.entity';
import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { type FlatAgentMaps } from 'src/engine/metadata-modules/flat-agent/types/flat-agent-maps.type';
import { type FlatAgent } from 'src/engine/metadata-modules/flat-agent/types/flat-agent.type';
@@ -37,42 +35,34 @@ import { type FlatViewMaps } from 'src/engine/metadata-modules/flat-view/types/f
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
import { type FlatWebhookMaps } from 'src/engine/metadata-modules/flat-webhook/types/flat-webhook-maps.type';
import { type FlatWebhook } from 'src/engine/metadata-modules/flat-webhook/types/flat-webhook.type';
import { type FrontComponentEntity } from 'src/engine/metadata-modules/front-component/entities/front-component.entity';
import { type IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
import { type LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
import { type NavigationMenuItemEntity } from 'src/engine/metadata-modules/navigation-menu-item/entities/navigation-menu-item.entity';
import { type PageLayoutTabEntity } from 'src/engine/metadata-modules/page-layout-tab/entities/page-layout-tab.entity';
import { type PageLayoutWidgetEntity } from 'src/engine/metadata-modules/page-layout-widget/entities/page-layout-widget.entity';
import { type PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entities/page-layout.entity';
import { type RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity';
import { type RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
import { type RowLevelPermissionPredicateGroupEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate-group.entity';
import { type RowLevelPermissionPredicateEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate.entity';
import { type FlatRowLevelPermissionPredicateGroupMaps } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate-group-maps.type';
import { type FlatRowLevelPermissionPredicateGroup } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate-group.type';
import { type FlatRowLevelPermissionPredicateMaps } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate-maps.type';
import { type FlatRowLevelPermissionPredicate } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate.type';
import { type SkillEntity } from 'src/engine/metadata-modules/skill/entities/skill.entity';
import { type ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity';
import { type ViewFilterGroupEntity } from 'src/engine/metadata-modules/view-filter-group/entities/view-filter-group.entity';
import { type ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entities/view-filter.entity';
import { type ViewGroupEntity } from 'src/engine/metadata-modules/view-group/entities/view-group.entity';
import { type ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
import { type WebhookEntity } from 'src/engine/metadata-modules/webhook/entities/webhook.entity';
import { type UniversalFlatEntityFrom } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-from.type';
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
import { type UniversalFlatSkill } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-skill.type';
import { type UniversalFlatViewField } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-field.type';
import { type UniversalFlatViewFilterGroup } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-filter-group.type';
import { type UniversalFlatViewFilter } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-filter.type';
import { type UniversalFlatViewGroup } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-group.type';
import { type UniversalFlatView } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view.type';
import {
type FlatCreateAgentAction,
type FlatDeleteAgentAction,
type FlatUpdateAgentAction,
type UniversalDeleteAgentAction,
type UniversalUpdateAgentAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/agent/types/workspace-migration-agent-action-builder.service';
import {
type FlatCreateCommandMenuItemAction,
type FlatDeleteCommandMenuItemAction,
type FlatUpdateCommandMenuItemAction,
type UniversalDeleteCommandMenuItemAction,
type UniversalUpdateCommandMenuItemAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/command-menu-item/types/workspace-migration-command-menu-item-action.type';
import {
type FlatCreateFieldAction,
@@ -87,24 +77,29 @@ import {
type FlatDeleteFrontComponentAction,
type FlatUpdateFrontComponentAction,
type UniversalDeleteFrontComponentAction,
type UniversalUpdateFrontComponentAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/front-component/types/workspace-migration-front-component-action.type';
import {
type UniversalCreateIndexAction,
type FlatCreateIndexAction,
type FlatDeleteIndexAction,
type FlatUpdateIndexAction,
type UniversalDeleteIndexAction,
type UniversalUpdateIndexAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/index/types/workspace-migration-index-action';
import {
type FlatCreateLogicFunctionAction,
type FlatDeleteLogicFunctionAction,
type FlatUpdateLogicFunctionAction,
type UniversalDeleteLogicFunctionAction,
type UniversalUpdateLogicFunctionAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/logic-function/types/workspace-migration-logic-function-action.type';
import {
type FlatCreateNavigationMenuItemAction,
type FlatDeleteNavigationMenuItemAction,
type FlatUpdateNavigationMenuItemAction,
type UniversalDeleteNavigationMenuItemAction,
type UniversalUpdateNavigationMenuItemAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/navigation-menu-item/types/workspace-migration-navigation-menu-item-action.type';
import {
type FlatCreateObjectAction,
@@ -119,84 +114,104 @@ import {
type FlatDeletePageLayoutTabAction,
type FlatUpdatePageLayoutTabAction,
type UniversalDeletePageLayoutTabAction,
type UniversalUpdatePageLayoutTabAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/page-layout-tab/types/workspace-migration-page-layout-tab-action.type';
import {
type FlatCreatePageLayoutWidgetAction,
type FlatDeletePageLayoutWidgetAction,
type FlatUpdatePageLayoutWidgetAction,
type UniversalDeletePageLayoutWidgetAction,
type UniversalUpdatePageLayoutWidgetAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/page-layout-widget/types/workspace-migration-page-layout-widget-action.type';
import {
type FlatCreatePageLayoutAction,
type FlatDeletePageLayoutAction,
type FlatUpdatePageLayoutAction,
type UniversalDeletePageLayoutAction,
type UniversalUpdatePageLayoutAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/page-layout/types/workspace-migration-page-layout-action.type';
import {
type FlatCreateRoleTargetAction,
type FlatDeleteRoleTargetAction,
type FlatUpdateRoleTargetAction,
type UniversalDeleteRoleTargetAction,
type UniversalUpdateRoleTargetAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/role-target/types/workspace-migration-role-target-action.type';
import {
type FlatCreateRoleAction,
type FlatDeleteRoleAction,
type FlatUpdateRoleAction,
type UniversalDeleteRoleAction,
type UniversalUpdateRoleAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/role/types/workspace-migration-role-action.type';
import {
type FlatCreateRowLevelPermissionPredicateGroupAction,
type FlatDeleteRowLevelPermissionPredicateGroupAction,
type FlatUpdateRowLevelPermissionPredicateGroupAction,
type UniversalDeleteRowLevelPermissionPredicateGroupAction,
type UniversalUpdateRowLevelPermissionPredicateGroupAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/row-level-permission-predicate-group/types/workspace-migration-row-level-permission-predicate-group-action.type';
import {
type FlatCreateRowLevelPermissionPredicateAction,
type FlatDeleteRowLevelPermissionPredicateAction,
type FlatUpdateRowLevelPermissionPredicateAction,
type UniversalDeleteRowLevelPermissionPredicateAction,
type UniversalUpdateRowLevelPermissionPredicateAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/row-level-permission-predicate/types/workspace-migration-row-level-permission-predicate-action.type';
import {
type FlatCreateSkillAction,
type FlatDeleteSkillAction,
type FlatUpdateSkillAction,
type UniversalCreateSkillAction,
type UniversalDeleteSkillAction,
type UniversalUpdateSkillAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/skill/types/workspace-migration-skill-action.type';
import {
type FlatCreateViewFieldAction,
type FlatDeleteViewFieldAction,
type FlatUpdateViewFieldAction,
type UniversalCreateViewFieldAction,
type UniversalDeleteViewFieldAction,
type UniversalUpdateViewFieldAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-field/types/workspace-migration-view-field-action.type';
import {
type FlatCreateViewFilterGroupAction,
type FlatDeleteViewFilterGroupAction,
type FlatUpdateViewFilterGroupAction,
type UniversalCreateViewFilterGroupAction,
type UniversalDeleteViewFilterGroupAction,
type UniversalUpdateViewFilterGroupAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-filter-group/types/workspace-migration-view-filter-group-action.type';
import {
type FlatCreateViewFilterAction,
type FlatDeleteViewFilterAction,
type FlatUpdateViewFilterAction,
type UniversalCreateViewFilterAction,
type UniversalDeleteViewFilterAction,
type UniversalUpdateViewFilterAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-filter/types/workspace-migration-view-filter-action.type';
import {
type FlatCreateViewGroupAction,
type FlatDeleteViewGroupAction,
type FlatUpdateViewGroupAction,
type UniversalCreateViewGroupAction,
type UniversalDeleteViewGroupAction,
type UniversalUpdateViewGroupAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view-group/types/workspace-migration-view-group-action.type';
import {
type FlatCreateViewAction,
type FlatDeleteViewAction,
type FlatUpdateViewAction,
type UniversalCreateViewAction,
type UniversalDeleteViewAction,
type UniversalUpdateViewAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/view/types/workspace-migration-view-action.type';
import {
type FlatCreateWebhookAction,
type FlatDeleteWebhookAction,
type FlatUpdateWebhookAction,
type UniversalDeleteWebhookAction,
type UniversalUpdateWebhookAction,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/builders/webhook/types/workspace-migration-webhook-action.type';
export type AllFlatEntityTypesByMetadataName = {
@@ -238,8 +253,8 @@ export type AllFlatEntityTypesByMetadataName = {
view: {
flatEntityMaps: FlatViewMaps;
universalActions: {
create: FlatCreateViewAction;
update: FlatUpdateViewAction;
create: UniversalCreateViewAction;
update: UniversalUpdateViewAction;
delete: UniversalDeleteViewAction;
};
flatActions: {
@@ -248,14 +263,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeleteViewAction;
};
flatEntity: FlatView;
universalFlatEntity: UniversalFlatEntityFrom<ViewEntity>;
universalFlatEntity: UniversalFlatView;
entity: MetadataEntity<'view'>;
};
viewField: {
flatEntityMaps: FlatViewFieldMaps;
universalActions: {
create: FlatCreateViewFieldAction;
update: FlatUpdateViewFieldAction;
create: UniversalCreateViewFieldAction;
update: UniversalUpdateViewFieldAction;
delete: UniversalDeleteViewFieldAction;
};
flatActions: {
@@ -264,14 +279,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeleteViewFieldAction;
};
flatEntity: FlatViewField;
universalFlatEntity: UniversalFlatEntityFrom<ViewFieldEntity>;
universalFlatEntity: UniversalFlatViewField;
entity: MetadataEntity<'viewField'>;
};
viewGroup: {
flatEntityMaps: FlatViewGroupMaps;
universalActions: {
create: FlatCreateViewGroupAction;
update: FlatUpdateViewGroupAction;
create: UniversalCreateViewGroupAction;
update: UniversalUpdateViewGroupAction;
delete: UniversalDeleteViewGroupAction;
};
flatActions: {
@@ -280,14 +295,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeleteViewGroupAction;
};
flatEntity: FlatViewGroup;
universalFlatEntity: UniversalFlatEntityFrom<ViewGroupEntity>;
universalFlatEntity: UniversalFlatViewGroup;
entity: MetadataEntity<'viewGroup'>;
};
rowLevelPermissionPredicate: {
flatEntityMaps: FlatRowLevelPermissionPredicateMaps;
universalActions: {
create: FlatCreateRowLevelPermissionPredicateAction;
update: FlatUpdateRowLevelPermissionPredicateAction;
update: UniversalUpdateRowLevelPermissionPredicateAction;
delete: UniversalDeleteRowLevelPermissionPredicateAction;
};
flatActions: {
@@ -296,14 +311,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeleteRowLevelPermissionPredicateAction;
};
flatEntity: FlatRowLevelPermissionPredicate;
universalFlatEntity: UniversalFlatEntityFrom<RowLevelPermissionPredicateEntity>;
universalFlatEntity: FlatRowLevelPermissionPredicate;
entity: MetadataEntity<'rowLevelPermissionPredicate'>;
};
rowLevelPermissionPredicateGroup: {
flatEntityMaps: FlatRowLevelPermissionPredicateGroupMaps;
universalActions: {
create: FlatCreateRowLevelPermissionPredicateGroupAction;
update: FlatUpdateRowLevelPermissionPredicateGroupAction;
update: UniversalUpdateRowLevelPermissionPredicateGroupAction;
delete: UniversalDeleteRowLevelPermissionPredicateGroupAction;
};
flatActions: {
@@ -312,14 +327,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeleteRowLevelPermissionPredicateGroupAction;
};
flatEntity: FlatRowLevelPermissionPredicateGroup;
universalFlatEntity: UniversalFlatEntityFrom<RowLevelPermissionPredicateGroupEntity>;
universalFlatEntity: FlatRowLevelPermissionPredicateGroup;
entity: MetadataEntity<'rowLevelPermissionPredicateGroup'>;
};
viewFilterGroup: {
flatEntityMaps: FlatViewFilterGroupMaps;
universalActions: {
create: FlatCreateViewFilterGroupAction;
update: FlatUpdateViewFilterGroupAction;
create: UniversalCreateViewFilterGroupAction;
update: UniversalUpdateViewFilterGroupAction;
delete: UniversalDeleteViewFilterGroupAction;
};
flatActions: {
@@ -328,14 +343,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeleteViewFilterGroupAction;
};
flatEntity: FlatViewFilterGroup;
universalFlatEntity: UniversalFlatEntityFrom<ViewFilterGroupEntity>;
universalFlatEntity: UniversalFlatViewFilterGroup;
entity: MetadataEntity<'viewFilterGroup'>;
};
index: {
flatEntityMaps: FlatEntityMaps<FlatIndexMetadata>;
universalActions: {
create: FlatCreateIndexAction;
update: FlatUpdateIndexAction;
create: UniversalCreateIndexAction;
update: UniversalUpdateIndexAction;
delete: UniversalDeleteIndexAction;
};
flatActions: {
@@ -344,14 +359,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeleteIndexAction;
};
flatEntity: FlatIndexMetadata;
universalFlatEntity: UniversalFlatEntityFrom<IndexMetadataEntity>;
universalFlatEntity: UniversalFlatIndexMetadata;
entity: MetadataEntity<'index'>;
};
logicFunction: {
flatEntityMaps: FlatEntityMaps<FlatLogicFunction>;
universalActions: {
create: FlatCreateLogicFunctionAction;
update: FlatUpdateLogicFunctionAction;
update: UniversalUpdateLogicFunctionAction;
delete: UniversalDeleteLogicFunctionAction;
};
flatActions: {
@@ -360,14 +375,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeleteLogicFunctionAction;
};
flatEntity: FlatLogicFunction;
universalFlatEntity: UniversalFlatEntityFrom<LogicFunctionEntity>;
universalFlatEntity: FlatLogicFunction;
entity: MetadataEntity<'logicFunction'>;
};
viewFilter: {
flatEntityMaps: FlatViewFilterMaps;
universalActions: {
create: FlatCreateViewFilterAction;
update: FlatUpdateViewFilterAction;
create: UniversalCreateViewFilterAction;
update: UniversalUpdateViewFilterAction;
delete: UniversalDeleteViewFilterAction;
};
flatActions: {
@@ -376,14 +391,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeleteViewFilterAction;
};
flatEntity: FlatViewFilter;
universalFlatEntity: UniversalFlatEntityFrom<ViewFilterEntity>;
universalFlatEntity: UniversalFlatViewFilter;
entity: MetadataEntity<'viewFilter'>;
};
role: {
flatEntityMaps: FlatEntityMaps<FlatRole>;
universalActions: {
create: FlatCreateRoleAction;
update: FlatUpdateRoleAction;
update: UniversalUpdateRoleAction;
delete: UniversalDeleteRoleAction;
};
flatActions: {
@@ -392,14 +407,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeleteRoleAction;
};
flatEntity: FlatRole;
universalFlatEntity: UniversalFlatEntityFrom<RoleEntity>;
universalFlatEntity: FlatRole;
entity: MetadataEntity<'role'>;
};
roleTarget: {
flatEntityMaps: FlatRoleTargetMaps;
universalActions: {
create: FlatCreateRoleTargetAction;
update: FlatUpdateRoleTargetAction;
update: UniversalUpdateRoleTargetAction;
delete: UniversalDeleteRoleTargetAction;
};
flatActions: {
@@ -408,14 +423,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeleteRoleTargetAction;
};
flatEntity: FlatRoleTarget;
universalFlatEntity: UniversalFlatEntityFrom<RoleTargetEntity>;
universalFlatEntity: FlatRoleTarget;
entity: MetadataEntity<'roleTarget'>;
};
agent: {
flatEntityMaps: FlatAgentMaps;
universalActions: {
create: FlatCreateAgentAction;
update: FlatUpdateAgentAction;
update: UniversalUpdateAgentAction;
delete: UniversalDeleteAgentAction;
};
flatActions: {
@@ -424,14 +439,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeleteAgentAction;
};
flatEntity: FlatAgent;
universalFlatEntity: UniversalFlatEntityFrom<AgentEntity>;
universalFlatEntity: FlatAgent;
entity: MetadataEntity<'agent'>;
};
skill: {
flatEntityMaps: FlatSkillMaps;
universalActions: {
create: FlatCreateSkillAction;
update: FlatUpdateSkillAction;
create: UniversalCreateSkillAction;
update: UniversalUpdateSkillAction;
delete: UniversalDeleteSkillAction;
};
flatActions: {
@@ -440,14 +455,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeleteSkillAction;
};
flatEntity: FlatSkill;
universalFlatEntity: UniversalFlatEntityFrom<SkillEntity>;
universalFlatEntity: UniversalFlatSkill;
entity: MetadataEntity<'skill'>;
};
commandMenuItem: {
flatEntityMaps: FlatCommandMenuItemMaps;
universalActions: {
create: FlatCreateCommandMenuItemAction;
update: FlatUpdateCommandMenuItemAction;
update: UniversalUpdateCommandMenuItemAction;
delete: UniversalDeleteCommandMenuItemAction;
};
flatActions: {
@@ -456,14 +471,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeleteCommandMenuItemAction;
};
flatEntity: FlatCommandMenuItem;
universalFlatEntity: UniversalFlatEntityFrom<CommandMenuItemEntity>;
universalFlatEntity: FlatCommandMenuItem;
entity: MetadataEntity<'commandMenuItem'>;
};
navigationMenuItem: {
flatEntityMaps: FlatNavigationMenuItemMaps;
universalActions: {
create: FlatCreateNavigationMenuItemAction;
update: FlatUpdateNavigationMenuItemAction;
update: UniversalUpdateNavigationMenuItemAction;
delete: UniversalDeleteNavigationMenuItemAction;
};
flatActions: {
@@ -472,14 +487,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeleteNavigationMenuItemAction;
};
flatEntity: FlatNavigationMenuItem;
universalFlatEntity: UniversalFlatEntityFrom<NavigationMenuItemEntity>;
universalFlatEntity: FlatNavigationMenuItem;
entity: NavigationMenuItemEntity;
};
pageLayout: {
flatEntityMaps: FlatPageLayoutMaps;
universalActions: {
create: FlatCreatePageLayoutAction;
update: FlatUpdatePageLayoutAction;
update: UniversalUpdatePageLayoutAction;
delete: UniversalDeletePageLayoutAction;
};
flatActions: {
@@ -488,14 +503,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeletePageLayoutAction;
};
flatEntity: FlatPageLayout;
universalFlatEntity: UniversalFlatEntityFrom<PageLayoutEntity>;
universalFlatEntity: FlatPageLayout;
entity: MetadataEntity<'pageLayout'>;
};
pageLayoutWidget: {
flatEntityMaps: FlatPageLayoutWidgetMaps;
universalActions: {
create: FlatCreatePageLayoutWidgetAction;
update: FlatUpdatePageLayoutWidgetAction;
update: UniversalUpdatePageLayoutWidgetAction;
delete: UniversalDeletePageLayoutWidgetAction;
};
flatActions: {
@@ -504,17 +519,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeletePageLayoutWidgetAction;
};
flatEntity: FlatPageLayoutWidget;
universalFlatEntity: UniversalFlatEntityFrom<
PageLayoutWidgetEntity,
'pageLayoutWidget'
>;
universalFlatEntity: FlatPageLayoutWidget;
entity: MetadataEntity<'pageLayoutWidget'>;
};
pageLayoutTab: {
flatEntityMaps: FlatPageLayoutTabMaps;
universalActions: {
create: FlatCreatePageLayoutTabAction;
update: FlatUpdatePageLayoutTabAction;
update: UniversalUpdatePageLayoutTabAction;
delete: UniversalDeletePageLayoutTabAction;
};
flatActions: {
@@ -523,14 +535,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeletePageLayoutTabAction;
};
flatEntity: FlatPageLayoutTab;
universalFlatEntity: UniversalFlatEntityFrom<PageLayoutTabEntity>;
universalFlatEntity: FlatPageLayoutTab;
entity: MetadataEntity<'pageLayoutTab'>;
};
frontComponent: {
flatEntityMaps: FlatFrontComponentMaps;
universalActions: {
create: FlatCreateFrontComponentAction;
update: FlatUpdateFrontComponentAction;
update: UniversalUpdateFrontComponentAction;
delete: UniversalDeleteFrontComponentAction;
};
flatActions: {
@@ -539,14 +551,14 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeleteFrontComponentAction;
};
flatEntity: FlatFrontComponent;
universalFlatEntity: UniversalFlatEntityFrom<FrontComponentEntity>;
universalFlatEntity: FlatFrontComponent;
entity: MetadataEntity<'frontComponent'>;
};
webhook: {
flatEntityMaps: FlatWebhookMaps;
universalActions: {
create: FlatCreateWebhookAction;
update: FlatUpdateWebhookAction;
update: UniversalUpdateWebhookAction;
delete: UniversalDeleteWebhookAction;
};
flatActions: {
@@ -555,7 +567,7 @@ export type AllFlatEntityTypesByMetadataName = {
delete: FlatDeleteWebhookAction;
};
flatEntity: FlatWebhook;
universalFlatEntity: UniversalFlatEntityFrom<WebhookEntity>;
universalFlatEntity: FlatWebhook;
entity: MetadataEntity<'webhook'>;
};
};
@@ -1,10 +1,8 @@
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';
import { type UniversalSyncableFlatEntity } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-from.type';
import { type UniversalFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-maps.type';
export type FlatEntityMaps<
T extends SyncableFlatEntity | UniversalSyncableFlatEntity,
> = {
byUniversalIdentifier: Partial<Record<string, T>>;
universalIdentifierById: Partial<Record<string, string>>;
universalIdentifiersByApplicationId: Partial<Record<string, string[]>>;
};
export type FlatEntityMaps<T extends SyncableFlatEntity> =
UniversalFlatEntityMaps<T> & {
universalIdentifierById: Partial<Record<string, string>>;
universalIdentifiersByApplicationId: Partial<Record<string, string[]>>;
};
@@ -1,6 +0,0 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type ALL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY } from 'src/engine/metadata-modules/flat-entity/constant/all-flat-entity-properties-to-compare-and-stringify.constant';
export type FlatEntityPropertiesToCompare<T extends AllMetadataName> =
(typeof ALL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY)[T]['propertiesToCompare'][number];
@@ -1,6 +0,0 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type ALL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY } from 'src/engine/metadata-modules/flat-entity/constant/all-flat-entity-properties-to-compare-and-stringify.constant';
export type FlatEntityPropertiesToStringify<T extends AllMetadataName> =
(typeof ALL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY)[T]['propertiesToStringify'][number];
@@ -1,11 +0,0 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type FlatEntityPropertiesToCompare } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-to-compare.type';
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
export type MetadataFlatEntityComparableProperties<T extends AllMetadataName> =
Extract<FlatEntityPropertiesToCompare<T>, keyof MetadataFlatEntity<T>>;
export type FlatEntityUpdate<T extends AllMetadataName> = Partial<
Pick<MetadataFlatEntity<T>, MetadataFlatEntityComparableProperties<T>>
>;
@@ -1,9 +1,9 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
import { type MetadataUniversalFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-universal-flat-entity.type';
export type FlatEntityToCreateDeleteUpdate<T extends AllMetadataName> = {
flatEntityToUpdate: MetadataFlatEntity<T>[];
flatEntityToCreate: MetadataFlatEntity<T>[];
flatEntityToDelete: MetadataFlatEntity<T>[];
flatEntityToUpdate: MetadataUniversalFlatEntity<T>[];
flatEntityToCreate: (MetadataUniversalFlatEntity<T> & { id?: string })[];
flatEntityToDelete: MetadataUniversalFlatEntity<T>[];
};
@@ -0,0 +1,27 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type 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 MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
type IsUniversalMappedProperty<
MetadataConfig,
P extends keyof MetadataConfig,
> = MetadataConfig[P] extends { universalProperty: string }
? MetadataConfig[P]['universalProperty']
: never;
export type FlatEntityUpdate<
T extends AllMetadataName,
MetadataPropertyConfig = (typeof ALL_ENTITY_PROPERTIES_CONFIGURATION_BY_METADATA_NAME)[T],
> = Partial<
Pick<
MetadataFlatEntity<T>,
Extract<keyof MetadataFlatEntity<T>, keyof MetadataPropertyConfig>
>
> & {
[K in keyof MetadataPropertyConfig as [
never,
] extends IsUniversalMappedProperty<MetadataPropertyConfig, K>
? never
: IsUniversalMappedProperty<MetadataPropertyConfig, K>]?: never;
};
@@ -1,14 +1,14 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { type MetadataRelatedFlatEntityMapsKeys } from 'src/engine/metadata-modules/flat-entity/types/metadata-related-flat-entity-maps-keys.type';
import { type MetadataToFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/types/metadata-to-flat-entity-maps-key';
import { type MetadataValidationRelatedMetadataNames } from 'src/engine/metadata-modules/flat-entity/types/metadata-validation-related-metadata-names.type';
import { type AllUniversalFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/all-universal-flat-entity-maps.type';
export type MetadataFlatEntityAndRelatedFlatEntityMapsForValidation<
export type MetadataUniversalFlatEntityAndRelatedFlatEntityMapsForValidation<
T extends AllMetadataName,
> = Pick<
AllFlatEntityMaps,
AllUniversalFlatEntityMaps,
| MetadataRelatedFlatEntityMapsKeys<T>
| MetadataToFlatEntityMapsKey<T>
| MetadataToFlatEntityMapsKey<MetadataValidationRelatedMetadataNames<T>>
@@ -4,6 +4,14 @@ import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/
import { type MetadataRelatedFlatEntityMapsKeys } from 'src/engine/metadata-modules/flat-entity/types/metadata-related-flat-entity-maps-keys.type';
import { type MetadataToFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/types/metadata-to-flat-entity-maps-key';
import { type MetadataValidationRelatedMetadataNames } from 'src/engine/metadata-modules/flat-entity/types/metadata-validation-related-metadata-names.type';
import { type AllUniversalFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/all-universal-flat-entity-maps.type';
export type MetadataUniversalFlatEntityAndRelatedUniversalFlatEntityMaps<
T extends AllMetadataName,
> = Pick<
AllUniversalFlatEntityMaps,
MetadataRelatedFlatEntityMapsKeys<T> | MetadataToFlatEntityMapsKey<T>
>;
export type MetadataFlatEntityAndRelatedFlatEntityMaps<
T extends AllMetadataName,
@@ -12,11 +20,13 @@ export type MetadataFlatEntityAndRelatedFlatEntityMaps<
MetadataRelatedFlatEntityMapsKeys<T> | MetadataToFlatEntityMapsKey<T>
>;
export type MetadataValidationRelatedFlatEntityMaps<T extends AllMetadataName> =
export type MetadataValidationRelatedUniversalFlatEntityMaps<
T extends AllMetadataName,
> =
MetadataValidationRelatedMetadataNames<T> extends undefined
? undefined
: Pick<
AllFlatEntityMaps,
AllUniversalFlatEntityMaps,
MetadataToFlatEntityMapsKey<
NonNullable<MetadataValidationRelatedMetadataNames<T>>
>
@@ -4,7 +4,7 @@ import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-enti
import { type MetadataFlatEntityAndRelatedFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-related-types.type';
import { addFlatEntityToFlatEntityAndRelatedEntityMapsThroughMutationOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-and-related-entity-maps-through-mutation-or-throw.util';
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/get-flat-object-metadata.mock';
@@ -12,14 +12,18 @@ import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
describe('addFlatEntityToFlatEntityAndRelatedEntityMapsThroughMutationOrThrow', () => {
it('should add a view and update related objectMetadata with viewId', () => {
it('should add a view and update related objectMetadata and fieldMetadata with both id and universal identifier aggregators', () => {
const objectMetadataId = 'object-1';
const viewId = 'view-1';
const applicationId = '20202020-f3ad-452e-b5b6-2d49d3ea88b1';
const workspaceId = '20202020-bc64-4148-8a79-b3144f743694';
const objectUniversalIdentifier = 'object-universal-1';
const fieldUniversalIdentifier = 'field-universal-1';
const viewUniversalIdentifier = 'view-universal-1';
const mockObjectMetadata = getFlatObjectMetadataMock({
id: objectMetadataId,
universalIdentifier: 'object-universal-1',
universalIdentifier: objectUniversalIdentifier,
viewIds: [],
fieldIds: [],
workspaceId,
@@ -34,7 +38,7 @@ describe('addFlatEntityToFlatEntityAndRelatedEntityMapsThroughMutationOrThrow',
type: FieldMetadataType.DATE,
workspaceId,
applicationId,
universalIdentifier: 'field-universal-1',
universalIdentifier: fieldUniversalIdentifier,
viewFieldIds: [],
viewFilterIds: [],
calendarViewIds: [],
@@ -44,13 +48,15 @@ describe('addFlatEntityToFlatEntityAndRelatedEntityMapsThroughMutationOrThrow',
const mockView: Pick<FlatView, 'id'> & Partial<FlatView> = {
id: viewId,
workspaceId,
universalIdentifier: 'view-universal-1',
universalIdentifier: viewUniversalIdentifier,
objectMetadataId: objectMetadataId,
objectMetadataUniversalIdentifier: objectUniversalIdentifier,
viewFieldIds: [],
viewFilterIds: [],
viewGroupIds: [],
applicationId,
calendarFieldMetadataId: mockFieldMetadata.id,
calendarFieldMetadataUniversalIdentifier: fieldUniversalIdentifier,
};
const flatEntityAndRelatedMapsToMutate: MetadataFlatEntityAndRelatedFlatEntityMaps<'view'> =
@@ -73,28 +79,30 @@ describe('addFlatEntityToFlatEntityAndRelatedEntityMapsThroughMutationOrThrow',
});
expect(
findFlatEntityByIdInFlatEntityMaps({
flatEntityId: mockView.id,
findFlatEntityByUniversalIdentifier({
universalIdentifier: viewUniversalIdentifier,
flatEntityMaps: flatEntityAndRelatedMapsToMutate.flatViewMaps,
}),
).toMatchObject(mockView);
expect(
findFlatEntityByIdInFlatEntityMaps({
flatEntityId: objectMetadataId,
findFlatEntityByUniversalIdentifier({
universalIdentifier: objectUniversalIdentifier,
flatEntityMaps: flatEntityAndRelatedMapsToMutate.flatObjectMetadataMaps,
}),
).toMatchObject<Partial<FlatObjectMetadata>>({
viewIds: [mockView.id],
viewUniversalIdentifiers: [viewUniversalIdentifier],
});
expect(
findFlatEntityByIdInFlatEntityMaps({
flatEntityId: mockFieldMetadata.id,
findFlatEntityByUniversalIdentifier({
universalIdentifier: fieldUniversalIdentifier,
flatEntityMaps: flatEntityAndRelatedMapsToMutate.flatFieldMetadataMaps,
}),
).toMatchObject<Partial<FlatFieldMetadata>>({
calendarViewIds: [mockView.id],
calendarViewUniversalIdentifiers: [viewUniversalIdentifier],
});
});
});
@@ -4,7 +4,7 @@ import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-enti
import { type MetadataFlatEntityAndRelatedFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-related-types.type';
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
import { deleteFlatEntityFromFlatEntityAndRelatedEntityMapsThroughMutationOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/delete-flat-entity-from-flat-entity-and-related-entity-maps-through-mutation-or-throw.util';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { getFlatObjectMetadataMock } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/get-flat-object-metadata.mock';
@@ -12,16 +12,20 @@ import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
describe('deleteFlatEntityFromFlatEntityAndRelatedEntityMapsThroughMutationOrThrow', () => {
it('should delete a view and update related objectMetadata and fieldMetadata by removing viewId', () => {
it('should delete a view and update related objectMetadata and fieldMetadata by removing both id and universal identifier aggregators', () => {
const objectMetadataId = 'object-1';
const viewId = 'view-1';
const applicationId = '20202020-f3ad-452e-b5b6-2d49d3ea88b1';
const workspaceId = '20202020-bc64-4148-8a79-b3144f743694';
const objectUniversalIdentifier = 'object-universal-1';
const fieldUniversalIdentifier = 'field-universal-1';
const viewUniversalIdentifier = 'view-universal-1';
const mockObjectMetadata = getFlatObjectMetadataMock({
id: objectMetadataId,
universalIdentifier: 'object-universal-1',
universalIdentifier: objectUniversalIdentifier,
viewIds: [viewId, 'something-else'],
viewUniversalIdentifiers: [viewUniversalIdentifier, 'something-else-ui'],
fieldIds: [],
workspaceId,
imageIdentifierFieldMetadataId: '20202020-9d65-415f-b0e1-216a2e257ea4',
@@ -33,24 +37,27 @@ describe('deleteFlatEntityFromFlatEntityAndRelatedEntityMapsThroughMutationOrThr
objectMetadataId,
id: '20202020-4087-423b-852a-91f91acf2df2',
type: FieldMetadataType.DATE,
universalIdentifier: 'field-universal-1',
universalIdentifier: fieldUniversalIdentifier,
viewFieldIds: [],
viewFilterIds: [],
workspaceId,
calendarViewIds: [viewId],
calendarViewUniversalIdentifiers: [viewUniversalIdentifier],
mainGroupByFieldMetadataViewIds: [],
applicationId,
});
const mockView: Partial<FlatView> = {
id: viewId,
universalIdentifier: 'view-universal-1',
universalIdentifier: viewUniversalIdentifier,
objectMetadataId: objectMetadataId,
objectMetadataUniversalIdentifier: objectUniversalIdentifier,
viewFieldIds: [],
viewFilterIds: [],
viewGroupIds: [],
workspaceId,
calendarFieldMetadataId: mockFieldMetadata.id,
calendarFieldMetadataUniversalIdentifier: fieldUniversalIdentifier,
createdAt: new Date('2024-01-01').toISOString(),
updatedAt: new Date('2024-01-01').toISOString(),
icon: 'icon',
@@ -83,28 +90,30 @@ describe('deleteFlatEntityFromFlatEntityAndRelatedEntityMapsThroughMutationOrThr
});
expect(
findFlatEntityByIdInFlatEntityMaps({
flatEntityId: viewId,
findFlatEntityByUniversalIdentifier({
universalIdentifier: viewUniversalIdentifier,
flatEntityMaps: flatEntityAndRelatedMapsToMutate.flatViewMaps,
}),
).toBeUndefined();
expect(
findFlatEntityByIdInFlatEntityMaps({
flatEntityId: objectMetadataId,
findFlatEntityByUniversalIdentifier({
universalIdentifier: objectUniversalIdentifier,
flatEntityMaps: flatEntityAndRelatedMapsToMutate.flatObjectMetadataMaps,
}),
).toMatchObject<Partial<FlatObjectMetadata>>({
viewIds: ['something-else'],
viewUniversalIdentifiers: ['something-else-ui'],
});
expect(
findFlatEntityByIdInFlatEntityMaps({
flatEntityId: mockFieldMetadata.id,
findFlatEntityByUniversalIdentifier({
universalIdentifier: fieldUniversalIdentifier,
flatEntityMaps: flatEntityAndRelatedMapsToMutate.flatFieldMetadataMaps,
}),
).toMatchObject<Partial<FlatFieldMetadata>>({
calendarViewIds: [],
calendarViewUniversalIdentifiers: [],
});
});
});
@@ -12,7 +12,7 @@ import { type MetadataRelatedFlatEntityMapsKeys } from 'src/engine/metadata-modu
import { type MetadataFlatEntityAndRelatedFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-related-types.type';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util';
import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/add-flat-entity-to-flat-entity-maps-through-mutation-or-throw.util';
import { addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/add-universal-flat-entity-to-universal-flat-entity-and-related-entity-maps-through-mutation-or-throw.util';
import { replaceFlatEntityInFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/replace-flat-entity-in-flat-entity-maps-through-mutation-or-throw.util';
type AddFlatEntityToFlatEntityAndRelatedEntityMapsThroughMutationOrThrowArgs<
@@ -22,21 +22,30 @@ type AddFlatEntityToFlatEntityAndRelatedEntityMapsThroughMutationOrThrowArgs<
flatEntity: MetadataFlatEntity<T>;
flatEntityAndRelatedMapsToMutate: MetadataFlatEntityAndRelatedFlatEntityMaps<T>;
};
export const addFlatEntityToFlatEntityAndRelatedEntityMapsThroughMutationOrThrow =
<T extends AllMetadataName>({
metadataName,
flatEntity,
flatEntityAndRelatedMapsToMutate,
}: AddFlatEntityToFlatEntityAndRelatedEntityMapsThroughMutationOrThrowArgs<T>) => {
addUniversalFlatEntityToUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName,
universalFlatEntity: flatEntity,
universalFlatEntityAndRelatedMapsToMutate:
flatEntityAndRelatedMapsToMutate,
},
);
const flatEntityMapsKey = getMetadataFlatEntityMapsKey(metadataName);
const selfFlatEntityMaps =
flatEntityAndRelatedMapsToMutate[flatEntityMapsKey];
addFlatEntityToFlatEntityMapsThroughMutationOrThrow({
flatEntity,
flatEntityMapsToMutate:
flatEntityAndRelatedMapsToMutate[flatEntityMapsKey],
});
selfFlatEntityMaps.universalIdentifierById[flatEntity.id] =
flatEntity.universalIdentifier;
const manyToOneRelations = Object.values(
const idBasedManyToOneRelations = Object.values(
ALL_METADATA_RELATIONS[metadataName].manyToOne,
) as Array<{
metadataName: AllMetadataName;
@@ -44,8 +53,8 @@ export const addFlatEntityToFlatEntityAndRelatedEntityMapsThroughMutationOrThrow
foreignKey: keyof MetadataFlatEntity<T>;
} | null>;
for (const relation of manyToOneRelations) {
if (!isDefined(relation)) {
for (const idBasedRelation of idBasedManyToOneRelations) {
if (!isDefined(idBasedRelation)) {
continue;
}
@@ -53,7 +62,7 @@ export const addFlatEntityToFlatEntityAndRelatedEntityMapsThroughMutationOrThrow
metadataName: relatedMetadataName,
flatEntityForeignKeyAggregator,
foreignKey,
} = relation;
} = idBasedRelation;
if (!isDefined(flatEntityForeignKeyAggregator)) {
continue;
@@ -61,6 +70,7 @@ export const addFlatEntityToFlatEntityAndRelatedEntityMapsThroughMutationOrThrow
const relatedFlatEntityMapsKey =
getMetadataFlatEntityMapsKey(relatedMetadataName);
const relatedFlatEntityMetadataMaps = flatEntityAndRelatedMapsToMutate[
relatedFlatEntityMapsKey as MetadataRelatedFlatEntityMapsKeys<T>
] as FlatEntityMaps<MetadataFlatEntity<typeof relatedMetadataName>>;
@@ -85,7 +95,7 @@ export const addFlatEntityToFlatEntityAndRelatedEntityMapsThroughMutationOrThrow
)
) {
throw new FlatEntityMapsException(
`Should never occur, invalid flat entity typing. flat ${metadataName} should contain ${flatEntityForeignKeyAggregator}`,
`Should never occur, invalid flat entity typing. flat ${relatedMetadataName} should contain ${String(flatEntityForeignKeyAggregator)}`,
FlatEntityMapsExceptionCode.ENTITY_MALFORMED,
);
}
@@ -1,78 +0,0 @@
import diff from 'microdiff';
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type FromTo } from 'twenty-shared/types';
import { parseJson } from 'twenty-shared/utils';
import { type FlatEntityPropertiesToCompare } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-to-compare.type';
import { type FlatEntityUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
import { transformFlatEntityForComparison } from 'src/engine/metadata-modules/flat-entity/utils/transform-flat-entity-for-comparison.util';
export const compareTwoFlatEntity = <
T extends AllMetadataName,
PToCompare extends Extract<
FlatEntityPropertiesToCompare<T>,
keyof MetadataFlatEntity<T>
>,
PJsonB extends PToCompare = PToCompare,
>({
fromFlatEntity,
toFlatEntity,
propertiesToCompare,
propertiesToStringify,
}: FromTo<MetadataFlatEntity<T>, 'flatEntity'> & {
propertiesToCompare: readonly PToCompare[];
propertiesToStringify: readonly PJsonB[];
}): FlatEntityUpdate<T> | undefined => {
const [transformedFromFlatEntity, transformedToFlatEntity] = [
fromFlatEntity,
toFlatEntity,
].map((flatEntity) =>
transformFlatEntityForComparison({
flatEntity,
propertiesToCompare,
propertiesToStringify,
}),
);
const flatEntityDifferences = diff(
transformedFromFlatEntity,
transformedToFlatEntity,
);
if (flatEntityDifferences.length === 0) {
return undefined;
}
const initialAccumulator: FlatEntityUpdate<T> = {};
return flatEntityDifferences.reduce((accumulator, difference) => {
switch (difference.type) {
case 'CHANGE': {
const { path, value } = difference;
const property = path[0] as PToCompare;
const isJsonb = propertiesToStringify.includes(
property as unknown as PJsonB,
);
if (isJsonb) {
return {
...accumulator,
[property]: parseJson(value),
};
}
return {
...accumulator,
[property]: value,
};
}
case 'CREATE':
case 'REMOVE':
default: {
// Should never occur, we should only provide null never undefined and so on
return accumulator;
}
}
}, initialAccumulator);
};
@@ -1,63 +0,0 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { type FlatEntityToCreateDeleteUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-to-create-delete-update.type';
import { type MetadataFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity-maps.type';
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
import { deleteFlatEntityFromFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/delete-flat-entity-from-flat-entity-maps-or-throw.util';
import { getSubFlatEntityByIdsMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/get-sub-flat-entity-by-ids-maps-or-throw.util';
import { replaceFlatEntityInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/replace-flat-entity-in-flat-entity-maps-or-throw.util';
export type ComputeFlatEntityMapsFromToArgs<T extends AllMetadataName> = {
flatEntityMaps: MetadataFlatEntityMaps<T>;
} & FlatEntityToCreateDeleteUpdate<T>;
export const computeFlatEntityMapsFromTo = <T extends AllMetadataName>({
flatEntityMaps,
flatEntityToCreate,
flatEntityToDelete,
flatEntityToUpdate,
}: ComputeFlatEntityMapsFromToArgs<T>): {
from: MetadataFlatEntityMaps<T>;
to: MetadataFlatEntityMaps<T>;
} => {
const fromFlatEntityMaps =
flatEntityToDelete.length > 0
? getSubFlatEntityByIdsMapsOrThrow({
flatEntityIds: [...flatEntityToDelete, ...flatEntityToUpdate].map(
({ id }) => id,
),
flatEntityMaps,
})
: flatEntityMaps;
const toFlatEntityMapsWithDeleted = flatEntityToDelete.reduce(
(flatEntityMaps, flatEntity) =>
deleteFlatEntityFromFlatEntityMapsOrThrow({
entityToDeleteId: flatEntity.id,
flatEntityMaps,
}),
fromFlatEntityMaps,
);
const toFlatEntityMapsWithUpdated = flatEntityToUpdate.reduce(
(flatEntityMaps, flatEntity) =>
replaceFlatEntityInFlatEntityMapsOrThrow({
flatEntity,
flatEntityMaps,
}),
toFlatEntityMapsWithDeleted,
);
const toFlatEntityMaps = flatEntityToCreate.reduce(
(flatEntityMaps, flatEntity) =>
addFlatEntityToFlatEntityMapsOrThrow({
flatEntity,
flatEntityMaps,
}),
toFlatEntityMapsWithUpdated,
);
return {
from: fromFlatEntityMaps,
to: toFlatEntityMaps,
};
};
@@ -12,7 +12,7 @@ import { type MetadataRelatedFlatEntityMapsKeys } from 'src/engine/metadata-modu
import { type MetadataFlatEntityAndRelatedFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-related-types.type';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util';
import { deleteFlatEntityFromFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/delete-flat-entity-from-flat-entity-maps-through-mutation-or-throw.util';
import { deleteUniversalFlatEntityFromUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/delete-universal-flat-entity-from-universal-flat-entity-and-related-entity-maps-through-mutation-or-throw.util';
import { replaceFlatEntityInFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/utils/replace-flat-entity-in-flat-entity-maps-through-mutation-or-throw.util';
type DeleteFlatEntityFromFlatEntityAndRelatedEntityMapsThroughMutationOrThrowArgs<
@@ -22,23 +22,23 @@ type DeleteFlatEntityFromFlatEntityAndRelatedEntityMapsThroughMutationOrThrowArg
flatEntity: MetadataFlatEntity<T>;
flatEntityAndRelatedMapsToMutate: MetadataFlatEntityAndRelatedFlatEntityMaps<T>;
};
export const deleteFlatEntityFromFlatEntityAndRelatedEntityMapsThroughMutationOrThrow =
<T extends AllMetadataName>({
metadataName,
flatEntity,
flatEntityAndRelatedMapsToMutate,
}: DeleteFlatEntityFromFlatEntityAndRelatedEntityMapsThroughMutationOrThrowArgs<T>) => {
const flatEntityMapsKey = getMetadataFlatEntityMapsKey(metadataName);
deleteUniversalFlatEntityFromUniversalFlatEntityAndRelatedEntityMapsThroughMutationOrThrow(
{
metadataName,
universalFlatEntity: flatEntity,
universalFlatEntityAndRelatedMapsToMutate:
flatEntityAndRelatedMapsToMutate,
},
);
deleteFlatEntityFromFlatEntityMapsThroughMutationOrThrow<
MetadataFlatEntity<T>
>({
entityToDeleteId: flatEntity.id,
flatEntityMapsToMutate:
flatEntityAndRelatedMapsToMutate[flatEntityMapsKey],
});
const manyToOneRelations = Object.values(
const idBasedManyToOneRelations = Object.values(
ALL_METADATA_RELATIONS[metadataName].manyToOne,
) as Array<{
metadataName: AllMetadataName;
@@ -46,8 +46,8 @@ export const deleteFlatEntityFromFlatEntityAndRelatedEntityMapsThroughMutationOr
foreignKey: keyof MetadataFlatEntity<T>;
} | null>;
for (const relation of manyToOneRelations) {
if (!isDefined(relation)) {
for (const idBasedRelation of idBasedManyToOneRelations) {
if (!isDefined(idBasedRelation)) {
continue;
}
@@ -55,7 +55,7 @@ export const deleteFlatEntityFromFlatEntityAndRelatedEntityMapsThroughMutationOr
metadataName: relatedMetadataName,
flatEntityForeignKeyAggregator,
foreignKey,
} = relation;
} = idBasedRelation;
if (!isDefined(flatEntityForeignKeyAggregator)) {
continue;
@@ -92,7 +92,7 @@ export const deleteFlatEntityFromFlatEntityAndRelatedEntityMapsThroughMutationOr
)
) {
throw new FlatEntityMapsException(
`Should never occur, invalid flat entity typing. flat ${metadataName} should contain ${flatEntityForeignKeyAggregator}`,
`Should never occur, invalid flat entity typing. flat ${relatedMetadataName} should contain ${flatEntityForeignKeyAggregator}`,
FlatEntityMapsExceptionCode.ENTITY_MALFORMED,
);
}
@@ -5,9 +5,9 @@ import {
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
import { type UniversalSyncableFlatEntity } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-from.type';
import { type UniversalFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-maps.type';
export const findFlatEntityByUniversalIdentifierOrThrow = <
T extends SyncableFlatEntity | UniversalSyncableFlatEntity,
@@ -15,7 +15,7 @@ export const findFlatEntityByUniversalIdentifierOrThrow = <
flatEntityMaps,
universalIdentifier,
}: {
flatEntityMaps: FlatEntityMaps<T>;
flatEntityMaps: UniversalFlatEntityMaps<T>;
universalIdentifier: string;
}): T => {
const flatEntity = findFlatEntityByUniversalIdentifier({
@@ -1,6 +1,6 @@
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type UniversalSyncableFlatEntity } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-from.type';
import { type UniversalFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-maps.type';
export const findFlatEntityByUniversalIdentifier = <
T extends SyncableFlatEntity | UniversalSyncableFlatEntity,
@@ -8,7 +8,7 @@ export const findFlatEntityByUniversalIdentifier = <
flatEntityMaps,
universalIdentifier,
}: {
flatEntityMaps: FlatEntityMaps<T>;
flatEntityMaps: UniversalFlatEntityMaps<T>;
universalIdentifier: string;
}): T | undefined => {
return flatEntityMaps.byUniversalIdentifier[universalIdentifier];
@@ -1,12 +1,12 @@
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { findFlatEntityByUniversalIdentifierOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier-or-throw.util';
import { type UniversalSyncableFlatEntity } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-from.type';
import { type UniversalFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-maps.type';
export type FindManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrowArgs<
T extends SyncableFlatEntity | UniversalSyncableFlatEntity,
> = {
flatEntityMaps: FlatEntityMaps<T>;
flatEntityMaps: UniversalFlatEntityMaps<T>;
universalIdentifiers: string[];
};
@@ -0,0 +1,15 @@
import { type AllMetadataName } from 'twenty-shared/metadata';
import { ALL_METADATA_RELATIONS } from 'src/engine/metadata-modules/flat-entity/constant/all-metadata-relations.constant';
export const getMetadataSerializedRelationNames = (
metadataName: AllMetadataName,
): AllMetadataName[] => {
const relations = ALL_METADATA_RELATIONS[metadataName];
if (!('serializedRelations' in relations)) {
return [];
}
return Object.keys(relations.serializedRelations) as AllMetadataName[];
};
@@ -0,0 +1,33 @@
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';
import { findFlatEntityByUniversalIdentifierOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier-or-throw.util';
import { type UniversalSyncableFlatEntity } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-from.type';
import { type UniversalFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-maps.type';
import { addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/utils/add-universal-flat-entity-to-universal-flat-entity-maps-through-mutation-or-throw.util';
export const getSubUniversalFlatEntityByUniversalIdentifiersMapsOrThrow = <
T extends SyncableFlatEntity | UniversalSyncableFlatEntity,
>({
universalIdentifiers,
universalFlatEntityMaps,
}: {
universalFlatEntityMaps: UniversalFlatEntityMaps<T>;
universalIdentifiers: string[];
}): UniversalFlatEntityMaps<T> => {
const subUniversalFlatEntityMaps: UniversalFlatEntityMaps<T> = {
byUniversalIdentifier: {},
};
for (const universalIdentifier of universalIdentifiers) {
const flatEntity = findFlatEntityByUniversalIdentifierOrThrow({
flatEntityMaps: universalFlatEntityMaps,
universalIdentifier,
});
addUniversalFlatEntityToUniversalFlatEntityMapsThroughMutationOrThrow({
universalFlatEntity: flatEntity,
universalFlatEntityMapsToMutate: subUniversalFlatEntityMaps,
});
}
return subUniversalFlatEntityMaps;
};
@@ -4,7 +4,7 @@ import { isDefined } from 'twenty-shared/utils';
import {
ALL_METADATA_RELATIONS,
type ManyToOneRelationValue,
type MetadataManyToOneRelationConfiguration,
} from 'src/engine/metadata-modules/flat-entity/constant/all-metadata-relations.constant';
import {
FlatEntityMapsException,
@@ -76,7 +76,9 @@ export const resolveEntityRelationUniversalIdentifiers = <
const relations = ALL_METADATA_RELATIONS[metadataName].manyToOne;
const result: Record<string, string | null> = {};
for (const relation of Object.values(relations) as ManyToOneRelationValue<
for (const relation of Object.values(
relations,
) as MetadataManyToOneRelationConfiguration<
T,
ExtractEntityManyToOneEntityRelationProperties<MetadataEntity<T>>
>[]) {
@@ -1,60 +0,0 @@
import { t } from '@lingui/core/macro';
import { type AllMetadataName } from 'twenty-shared/metadata';
import { isDefined } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { type MetadataFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
// @deprecated Use resolveEntityRelationUniversalIdentifiers instead
export const resolveUniversalIdentifierFromFlatEntityIdOrThrow = <
T extends AllMetadataName,
>({
flatEntityMaps,
flatEntityId,
metadataName,
}: {
flatEntityMaps: MetadataFlatEntityMaps<T>;
flatEntityId: string;
metadataName: T;
}): string => {
const flatEntity = findFlatEntityByIdInFlatEntityMaps({
flatEntityMaps,
flatEntityId,
});
if (!isDefined(flatEntity)) {
throw new FlatEntityMapsException(
t`Could not find ${metadataName}`,
FlatEntityMapsExceptionCode.ENTITY_NOT_FOUND,
);
}
return flatEntity.universalIdentifier;
};
// @deprecated Use resolveEntityRelationUniversalIdentifiers instead
export const resolveNullableUniversalIdentifierFromFlatEntityId = <
T extends AllMetadataName,
>({
flatEntityMaps,
flatEntityId,
metadataName,
}: {
flatEntityMaps: MetadataFlatEntityMaps<T>;
flatEntityId: string | null | undefined;
metadataName: T;
}): string | null => {
if (!isDefined(flatEntityId)) {
return null;
}
return resolveUniversalIdentifierFromFlatEntityIdOrThrow({
flatEntityMaps,
flatEntityId,
metadataName,
});
};
@@ -1,37 +0,0 @@
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';
import { orderObjectProperties } from 'src/engine/metadata-modules/flat-entity/utils/order-object-properties.util';
export function transformFlatEntityForComparison<
TFlatEntity extends SyncableFlatEntity,
PToCompare extends keyof TFlatEntity,
PJsonB extends PToCompare,
>({
flatEntity,
propertiesToCompare,
propertiesToStringify,
}: {
flatEntity: TFlatEntity;
propertiesToCompare: readonly PToCompare[];
propertiesToStringify: readonly PJsonB[];
}): Pick<TFlatEntity, PToCompare> {
return propertiesToCompare.reduce(
(flatEntityAccumulator, propertyToCompare) => {
const currentValue = flatEntity[propertyToCompare];
if (propertiesToStringify.includes(propertyToCompare as PJsonB)) {
const orderedValue = orderObjectProperties(currentValue);
return {
...flatEntityAccumulator,
[propertyToCompare]: JSON.stringify(orderedValue),
};
}
return {
...flatEntityAccumulator,
[propertyToCompare]: currentValue,
};
},
{} as Pick<TFlatEntity, PToCompare>,
);
}
@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test suite Failure cases should fail when morphRelationsCreationPayload has different relation types 1`] = `
{
@@ -116,15 +116,12 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
"result": {
"flatFieldMetadatas": [
{
"applicationId": Any<String>,
"applicationUniversalIdentifier": Any<String>,
"calendarViewIds": [],
"calendarViewUniversalIdentifiers": [],
"createdAt": Any<String>,
"defaultValue": null,
"description": "new field description",
"icon": "IconRelationOneToMany",
"id": Any<String>,
"isActive": true,
"isCustom": true,
"isLabelSyncedWithName": false,
@@ -132,23 +129,15 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
"isSystem": false,
"isUIReadOnly": false,
"isUnique": false,
"kanbanAggregateOperationViewIds": [],
"kanbanAggregateOperationViewUniversalIdentifiers": [],
"label": "newFieldLabel",
"mainGroupByFieldMetadataViewIds": [],
"mainGroupByFieldMetadataViewUniversalIdentifiers": [],
"morphId": Any<String>,
"name": "newFieldPets",
"objectMetadataId": Any<String>,
"objectMetadataUniversalIdentifier": Any<String>,
"options": null,
"relationTargetFieldMetadataId": Any<String>,
"relationTargetFieldMetadataUniversalIdentifier": Any<String>,
"relationTargetObjectMetadataId": Any<String>,
"relationTargetObjectMetadataUniversalIdentifier": Any<String>,
"settings": {
"relationType": "ONE_TO_MANY",
},
"standardOverrides": null,
"type": "MORPH_RELATION",
"universalIdentifier": Any<String>,
@@ -156,22 +145,16 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
"relationType": "ONE_TO_MANY",
},
"updatedAt": Any<String>,
"viewFieldIds": [],
"viewFieldUniversalIdentifiers": [],
"viewFilterIds": [],
"viewFilterUniversalIdentifiers": [],
"workspaceId": Any<String>,
},
{
"applicationId": Any<String>,
"applicationUniversalIdentifier": Any<String>,
"calendarViewIds": [],
"calendarViewUniversalIdentifiers": [],
"createdAt": Any<String>,
"defaultValue": null,
"description": "new field description",
"icon": "IconPet",
"id": Any<String>,
"isActive": true,
"isCustom": true,
"isLabelSyncedWithName": false,
@@ -179,25 +162,15 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
"isSystem": false,
"isUIReadOnly": false,
"isUnique": false,
"kanbanAggregateOperationViewIds": [],
"kanbanAggregateOperationViewUniversalIdentifiers": [],
"label": "Pet",
"mainGroupByFieldMetadataViewIds": [],
"mainGroupByFieldMetadataViewUniversalIdentifiers": [],
"morphId": null,
"name": "pet",
"objectMetadataId": Any<String>,
"objectMetadataUniversalIdentifier": Any<String>,
"options": null,
"relationTargetFieldMetadataId": Any<String>,
"relationTargetFieldMetadataUniversalIdentifier": Any<String>,
"relationTargetObjectMetadataId": Any<String>,
"relationTargetObjectMetadataUniversalIdentifier": Any<String>,
"settings": {
"joinColumnName": "petId",
"onDelete": "SET_NULL",
"relationType": "MANY_TO_ONE",
},
"standardOverrides": null,
"type": "RELATION",
"universalIdentifier": Any<String>,
@@ -207,22 +180,16 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
"relationType": "MANY_TO_ONE",
},
"updatedAt": Any<String>,
"viewFieldIds": [],
"viewFieldUniversalIdentifiers": [],
"viewFilterIds": [],
"viewFilterUniversalIdentifiers": [],
"workspaceId": Any<String>,
},
{
"applicationId": Any<String>,
"applicationUniversalIdentifier": Any<String>,
"calendarViewIds": [],
"calendarViewUniversalIdentifiers": [],
"createdAt": Any<String>,
"defaultValue": null,
"description": "new field description",
"icon": "IconRelationOneToMany",
"id": Any<String>,
"isActive": true,
"isCustom": true,
"isLabelSyncedWithName": false,
@@ -230,23 +197,15 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
"isSystem": false,
"isUIReadOnly": false,
"isUnique": false,
"kanbanAggregateOperationViewIds": [],
"kanbanAggregateOperationViewUniversalIdentifiers": [],
"label": "newFieldLabel",
"mainGroupByFieldMetadataViewIds": [],
"mainGroupByFieldMetadataViewUniversalIdentifiers": [],
"morphId": Any<String>,
"name": "newFieldCompanies",
"objectMetadataId": Any<String>,
"objectMetadataUniversalIdentifier": Any<String>,
"options": null,
"relationTargetFieldMetadataId": Any<String>,
"relationTargetFieldMetadataUniversalIdentifier": Any<String>,
"relationTargetObjectMetadataId": Any<String>,
"relationTargetObjectMetadataUniversalIdentifier": Any<String>,
"settings": {
"relationType": "ONE_TO_MANY",
},
"standardOverrides": null,
"type": "MORPH_RELATION",
"universalIdentifier": Any<String>,
@@ -254,22 +213,16 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
"relationType": "ONE_TO_MANY",
},
"updatedAt": Any<String>,
"viewFieldIds": [],
"viewFieldUniversalIdentifiers": [],
"viewFilterIds": [],
"viewFilterUniversalIdentifiers": [],
"workspaceId": Any<String>,
},
{
"applicationId": Any<String>,
"applicationUniversalIdentifier": Any<String>,
"calendarViewIds": [],
"calendarViewUniversalIdentifiers": [],
"createdAt": Any<String>,
"defaultValue": null,
"description": "new field description",
"icon": "IconBuilding",
"id": Any<String>,
"isActive": true,
"isCustom": true,
"isLabelSyncedWithName": false,
@@ -277,25 +230,15 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
"isSystem": false,
"isUIReadOnly": false,
"isUnique": false,
"kanbanAggregateOperationViewIds": [],
"kanbanAggregateOperationViewUniversalIdentifiers": [],
"label": "Company",
"mainGroupByFieldMetadataViewIds": [],
"mainGroupByFieldMetadataViewUniversalIdentifiers": [],
"morphId": null,
"name": "company",
"objectMetadataId": Any<String>,
"objectMetadataUniversalIdentifier": Any<String>,
"options": null,
"relationTargetFieldMetadataId": Any<String>,
"relationTargetFieldMetadataUniversalIdentifier": Any<String>,
"relationTargetObjectMetadataId": Any<String>,
"relationTargetObjectMetadataUniversalIdentifier": Any<String>,
"settings": {
"joinColumnName": "companyId",
"onDelete": "SET_NULL",
"relationType": "MANY_TO_ONE",
},
"standardOverrides": null,
"type": "RELATION",
"universalIdentifier": Any<String>,
@@ -305,65 +248,52 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
"relationType": "MANY_TO_ONE",
},
"updatedAt": Any<String>,
"viewFieldIds": [],
"viewFieldUniversalIdentifiers": [],
"viewFilterIds": [],
"viewFilterUniversalIdentifiers": [],
"workspaceId": Any<String>,
},
],
"indexMetadatas": [
{
"applicationId": Any<String>,
"applicationUniversalIdentifier": Any<String>,
"createdAt": Any<String>,
"flatIndexFieldMetadatas": [
{
"createdAt": Any<String>,
"fieldMetadataId": Any<String>,
"id": Any<String>,
"indexMetadataId": Any<String>,
"order": 0,
"updatedAt": Any<String>,
},
],
"id": Any<String>,
"indexType": "BTREE",
"indexWhereClause": null,
"isCustom": true,
"isUnique": false,
"name": "IDX_f687e4e4252800dddd8e5518362",
"objectMetadataId": Any<String>,
"objectMetadataUniversalIdentifier": Any<String>,
"universalIdentifier": Any<String>,
"updatedAt": Any<String>,
"workspaceId": Any<String>,
},
{
"applicationId": Any<String>,
"applicationUniversalIdentifier": Any<String>,
"createdAt": Any<String>,
"flatIndexFieldMetadatas": [
"universalFlatIndexFieldMetadatas": [
{
"createdAt": Any<String>,
"fieldMetadataId": Any<String>,
"id": Any<String>,
"indexMetadataId": Any<String>,
"fieldMetadataUniversalIdentifier": Any<String>,
"indexMetadataUniversalIdentifier": Any<String>,
"order": 0,
"updatedAt": Any<String>,
},
],
"id": Any<String>,
"universalIdentifier": Any<String>,
"updatedAt": Any<String>,
},
{
"applicationUniversalIdentifier": Any<String>,
"createdAt": Any<String>,
"indexType": "BTREE",
"indexWhereClause": null,
"isCustom": true,
"isUnique": false,
"name": "IDX_cb15d901e889e25d0a9acecb595",
"objectMetadataId": Any<String>,
"objectMetadataUniversalIdentifier": Any<String>,
"universalFlatIndexFieldMetadatas": [
{
"createdAt": Any<String>,
"fieldMetadataUniversalIdentifier": Any<String>,
"indexMetadataUniversalIdentifier": Any<String>,
"order": 0,
"updatedAt": Any<String>,
},
],
"universalIdentifier": Any<String>,
"updatedAt": Any<String>,
"workspaceId": Any<String>,
},
],
},
@@ -22,9 +22,9 @@ import { ROCKET_FLAT_OBJECT_MOCK } from 'src/engine/metadata-modules/flat-object
const MOCK_FLAT_APPLICATION: FlatApplication = {
id: '20202020-81ee-42da-a281-668632f32fe7',
universalIdentifier: '20202020-81ee-42da-a281-668632f32fe7',
workspaceId: 'mock-workspace-id',
name: 'Workspace Custom Application',
description: null,
workspaceId: 'workspace-id',
version: null,
sourceType: 'local',
sourcePath: '',
@@ -62,8 +62,6 @@ type TestCase = EachTestingContext<{
}>;
describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test suite', () => {
const mockWorkspaceId = 'mock-workspace-id';
describe('Success cases', () => {
const successTestCases: TestCase[] = [
{
@@ -93,7 +91,6 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
},
],
},
workspaceId: mockWorkspaceId,
flatObjectMetadataMaps,
flatFieldMetadataMaps: emptyFlatFieldMetadataMaps,
},
@@ -140,7 +137,6 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
objectMetadataId: ROCKET_FLAT_OBJECT_MOCK.id,
morphRelationsCreationPayload: undefined as any,
},
workspaceId: mockWorkspaceId,
flatObjectMetadataMaps: FLAT_OBJECT_METADATA_MAPS_MOCKS,
flatFieldMetadataMaps: emptyFlatFieldMetadataMaps,
},
@@ -160,7 +156,6 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
objectMetadataId: ROCKET_FLAT_OBJECT_MOCK.id,
morphRelationsCreationPayload: [],
},
workspaceId: mockWorkspaceId,
flatObjectMetadataMaps: FLAT_OBJECT_METADATA_MAPS_MOCKS,
flatFieldMetadataMaps: emptyFlatFieldMetadataMaps,
},
@@ -194,7 +189,6 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
},
],
},
workspaceId: mockWorkspaceId,
flatObjectMetadataMaps: FLAT_OBJECT_METADATA_MAPS_MOCKS,
flatFieldMetadataMaps: emptyFlatFieldMetadataMaps,
},
@@ -228,7 +222,6 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
},
],
},
workspaceId: mockWorkspaceId,
flatObjectMetadataMaps: FLAT_OBJECT_METADATA_MAPS_MOCKS,
flatFieldMetadataMaps: emptyFlatFieldMetadataMaps,
},
@@ -255,7 +248,6 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
} as any,
],
},
workspaceId: mockWorkspaceId,
flatObjectMetadataMaps: FLAT_OBJECT_METADATA_MAPS_MOCKS,
flatFieldMetadataMaps: emptyFlatFieldMetadataMaps,
},
@@ -282,7 +274,6 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
},
],
},
workspaceId: mockWorkspaceId,
flatObjectMetadataMaps: FLAT_OBJECT_METADATA_MAPS_MOCKS,
flatFieldMetadataMaps: emptyFlatFieldMetadataMaps,
},
@@ -1,4 +1,4 @@
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type MetadataEntityPropertyName } from 'src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant';
export const FLAT_FIELD_METADATA_EDITABLE_PROPERTIES = {
custom: [
@@ -23,4 +23,7 @@ export const FLAT_FIELD_METADATA_EDITABLE_PROPERTIES = {
'settings',
'isUnique',
],
} as const satisfies Record<'standard' | 'custom', (keyof FlatFieldMetadata)[]>;
} as const satisfies Record<
'standard' | 'custom',
MetadataEntityPropertyName<'fieldMetadata'>[]
>;
@@ -1,4 +1,4 @@
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type MetadataEntityPropertyName } from 'src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant';
export const FLAT_FIELD_METADATA_MORPH_RELATION_EDITABLE_PROPERTIES_ON_SIBLING_MORPH_RELATION_UPDATE_CONSTANT =
{
@@ -22,5 +22,5 @@ export const FLAT_FIELD_METADATA_MORPH_RELATION_EDITABLE_PROPERTIES_ON_SIBLING_M
],
} as const satisfies Record<
'standard' | 'custom',
(keyof FlatFieldMetadata)[]
MetadataEntityPropertyName<'fieldMetadata'>[]
>;
@@ -1,4 +1,4 @@
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type MetadataEntityPropertyName } from 'src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant';
export const FLAT_FIELD_METADATA_RELATION_EDITABLE_PROPERTIES_ON_SIBLING_MORPH_OR_RELATION_UPDATE_CONSTANT =
['isActive'] as const satisfies (keyof FlatFieldMetadata)[];
['isActive'] as const satisfies MetadataEntityPropertyName<'fieldMetadata'>[];
@@ -1,4 +1,4 @@
import { type ALL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY } from 'src/engine/metadata-modules/flat-entity/constant/all-flat-entity-properties-to-compare-and-stringify.constant';
import { type ALL_UNIVERSAL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY } from 'src/engine/metadata-modules/flat-entity/constant/all-universal-flat-entity-properties-to-compare-and-stringify.constant';
export const FLAT_FIELD_METADATA_RELATION_PROPERTIES_TO_COMPARE = [
'label',
@@ -7,5 +7,5 @@ export const FLAT_FIELD_METADATA_RELATION_PROPERTIES_TO_COMPARE = [
'standardOverrides',
'icon',
'name',
'settings',
] as const satisfies (typeof ALL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY.fieldMetadata.propertiesToCompare)[number][];
'universalSettings', // TODO prastoin VERY IMPORTANT
] as const satisfies (typeof ALL_UNIVERSAL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY.fieldMetadata.propertiesToCompare)[number][];
@@ -5,29 +5,25 @@ import { isDefined } from 'class-validator';
import { FieldMetadataType } from 'twenty-shared/types';
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { FlatEntityUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { type FlatFieldMetadataTypeValidator } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-type-validator.type';
import {
FlatFieldMetadataTypeValidationArgs,
type FlatFieldMetadataTypeValidator,
} from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-type-validator.type';
import { FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type';
import { validateEnumSelectFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-enum-flat-field-metadata.util';
import { validateFilesFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-files-flat-field-metadata.util';
import { validateMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-morph-or-relation-flat-field-metadata.util';
import { validateMorphRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-morph-relation-flat-field-metadata.util';
import { FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-validation-args.type';
const DEFAULT_NO_VALIDATION = (): FlatFieldMetadataValidationError[] => [];
export type GenericValidateFlatFieldMetadataTypeSpecificitiesArgs =
FlatEntityValidationArgs<'fieldMetadata'> & {
update?: FlatEntityUpdate<'fieldMetadata'>;
};
const rejectUserCreation = (
fieldType: FieldMetadataType,
message: string,
userFriendlyMessage: ReturnType<typeof msg>,
) => {
return (
args: GenericValidateFlatFieldMetadataTypeSpecificitiesArgs,
args: FlatFieldMetadataTypeValidationArgs<FieldMetadataType>,
): FlatFieldMetadataValidationError[] => {
const isCreation = !isDefined(args.update);
const isCustomField = args.flatEntityToValidate.isCustom;
@@ -94,7 +90,7 @@ export class FlatFieldMetadataTypeValidatorService {
};
public validateFlatFieldMetadataTypeSpecificities(
args: GenericValidateFlatFieldMetadataTypeSpecificitiesArgs,
args: FlatFieldMetadataTypeValidationArgs<FieldMetadataType>,
): FlatFieldMetadataValidationError[] {
const { flatEntityToValidate } = args;
const fieldType = flatEntityToValidate.type;
@@ -1,15 +1,18 @@
import { type FieldMetadataType } from 'twenty-shared/types';
import { type GenericValidateFlatFieldMetadataTypeSpecificitiesArgs } from 'src/engine/metadata-modules/flat-field-metadata/services/flat-field-metadata-type-validator.service';
import { type FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type UniversalFlatEntityUpdate } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-update.type';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
import { type UniversalFlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-validation-args.type';
export type FlatFieldMetadataTypeValidationArgs<T extends FieldMetadataType> =
Omit<
GenericValidateFlatFieldMetadataTypeSpecificitiesArgs,
UniversalFlatEntityValidationArgs<'fieldMetadata'> & {
update?: UniversalFlatEntityUpdate<'fieldMetadata'>;
},
'flatEntityToValidate'
> & {
flatEntityToValidate: FlatFieldMetadata<T>;
flatEntityToValidate: UniversalFlatFieldMetadata<T>;
};
export type FlatFieldMetadataTypeValidator = {
@@ -17,10 +17,10 @@ import { PET_FLAT_OBJECT_MOCK } from 'src/engine/metadata-modules/flat-object-me
const MOCK_FLAT_APPLICATION: FlatApplication = {
id: '20202020-81ee-42da-a281-668632f32fe7',
universalIdentifier: '20202020-81ee-42da-a281-668632f32fe7',
workspaceId: '20202020-1c25-4d02-bf25-6aeccf7ea419',
name: 'Workspace Custom Application',
description: null,
version: null,
workspaceId: 'workspace-id',
sourceType: 'local',
sourcePath: '',
packageJsonChecksum: null,
@@ -51,8 +51,6 @@ type TestCase = EachTestingContext<{
}>;
describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () => {
const mockWorkspaceId = '20202020-1c25-4d02-bf25-6aeccf7ea419';
describe('Success cases', () => {
const testCases: TestCase[] = [
{
@@ -64,7 +62,6 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
targetFlatObjectMetadata: PET_FLAT_OBJECT_MOCK,
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
sourceFlatObjectMetadataJoinColumnName: 'petId',
workspaceId: mockWorkspaceId,
flatApplication: MOCK_FLAT_APPLICATION,
createFieldInput: {
name: 'pets',
@@ -72,13 +69,13 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
description: 'Company pets',
icon: 'IconCat',
type: FieldMetadataType.RELATION,
objectMetadataId: COMPANY_FLAT_OBJECT_MOCK.id,
isCustom: true,
isSystem: false,
isUnique: false,
relationCreationPayload: {
type: RelationType.ONE_TO_MANY,
targetObjectMetadataId: PET_FLAT_OBJECT_MOCK.id,
targetObjectMetadataId:
PET_FLAT_OBJECT_MOCK.universalIdentifier,
targetFieldLabel: 'Company',
targetFieldIcon: 'IconBuildingSkyscraper',
},
@@ -100,7 +97,6 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
targetFlatObjectMetadata: PET_FLAT_OBJECT_MOCK,
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
sourceFlatObjectMetadataJoinColumnName: 'petId',
workspaceId: mockWorkspaceId,
flatApplication: MOCK_FLAT_APPLICATION,
createFieldInput: {
name: 'pets',
@@ -108,13 +104,13 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
description: 'Company pets',
icon: 'IconCat',
type: FieldMetadataType.RELATION,
objectMetadataId: COMPANY_FLAT_OBJECT_MOCK.id,
isCustom: true,
isSystem: false,
isUnique: false,
relationCreationPayload: {
type: RelationType.MANY_TO_ONE,
targetObjectMetadataId: PET_FLAT_OBJECT_MOCK.id,
targetObjectMetadataId:
PET_FLAT_OBJECT_MOCK.universalIdentifier,
targetFieldLabel: 'Company',
targetFieldIcon: 'IconBuildingSkyscraper',
},
@@ -136,7 +132,6 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
targetFlatObjectMetadata: PET_FLAT_OBJECT_MOCK,
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
sourceFlatObjectMetadataJoinColumnName: 'petId',
workspaceId: mockWorkspaceId,
flatApplication: MOCK_FLAT_APPLICATION,
createFieldInput: {
name: 'pets',
@@ -144,13 +139,13 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
description: 'Company pets',
icon: 'IconCat',
type: FieldMetadataType.RELATION,
objectMetadataId: COMPANY_FLAT_OBJECT_MOCK.id,
isCustom: false,
isSystem: true,
isUnique: true,
relationCreationPayload: {
type: RelationType.MANY_TO_ONE,
targetObjectMetadataId: PET_FLAT_OBJECT_MOCK.id,
targetObjectMetadataId:
PET_FLAT_OBJECT_MOCK.universalIdentifier,
targetFieldLabel: 'Company',
targetFieldIcon: 'IconBuildingSkyscraper',
},
@@ -172,7 +167,6 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
targetFlatObjectMetadata: PET_FLAT_OBJECT_MOCK,
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
sourceFlatObjectMetadataJoinColumnName: 'targetPetId',
workspaceId: mockWorkspaceId,
flatApplication: MOCK_FLAT_APPLICATION,
morphId: '20202020-9a2b-4c3d-a4e5-f6a7b8c9d0e1',
createFieldInput: {
@@ -181,13 +175,13 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
description: 'Morph relation to pet',
icon: 'IconCat',
type: FieldMetadataType.MORPH_RELATION,
objectMetadataId: COMPANY_FLAT_OBJECT_MOCK.id,
isCustom: false,
isSystem: true,
isUnique: false,
relationCreationPayload: {
type: RelationType.MANY_TO_ONE,
targetObjectMetadataId: PET_FLAT_OBJECT_MOCK.id,
targetObjectMetadataId:
PET_FLAT_OBJECT_MOCK.universalIdentifier,
targetFieldLabel: 'Companies',
targetFieldIcon: 'IconBuildingSkyscraper',
},
@@ -209,7 +203,6 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
targetFlatObjectMetadata: PET_FLAT_OBJECT_MOCK,
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
sourceFlatObjectMetadataJoinColumnName: 'targetPetId',
workspaceId: mockWorkspaceId,
flatApplication: MOCK_FLAT_APPLICATION,
morphId: '20202020-9a2b-4c3d-a4e5-f6a7b8c9d0e1',
createFieldInput: {
@@ -218,13 +211,13 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
description: 'Morph relation to pet',
icon: 'IconCat',
type: FieldMetadataType.MORPH_RELATION,
objectMetadataId: COMPANY_FLAT_OBJECT_MOCK.id,
isCustom: false,
isSystem: true,
isUnique: false,
relationCreationPayload: {
type: RelationType.ONE_TO_MANY,
targetObjectMetadataId: PET_FLAT_OBJECT_MOCK.id,
targetObjectMetadataId:
PET_FLAT_OBJECT_MOCK.universalIdentifier,
targetFieldLabel: 'Companies',
targetFieldIcon: 'IconBuildingSkyscraper',
},
@@ -246,7 +239,6 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
targetFlatObjectMetadata: PET_FLAT_OBJECT_MOCK,
targetFlatFieldMetadataType: FieldMetadataType.MORPH_RELATION,
sourceFlatObjectMetadataJoinColumnName: 'targetPetId',
workspaceId: mockWorkspaceId,
flatApplication: MOCK_FLAT_APPLICATION,
morphId: '20202020-9a2b-4c3d-a4e5-f6a7b8c9d0e1',
createFieldInput: {
@@ -255,13 +247,13 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
description: 'Morph relation to pet',
icon: 'IconCat',
type: FieldMetadataType.RELATION,
objectMetadataId: COMPANY_FLAT_OBJECT_MOCK.id,
isCustom: false,
isSystem: true,
isUnique: false,
relationCreationPayload: {
type: RelationType.ONE_TO_MANY,
targetObjectMetadataId: PET_FLAT_OBJECT_MOCK.id,
targetObjectMetadataId:
PET_FLAT_OBJECT_MOCK.universalIdentifier,
targetFieldLabel: 'Companies',
targetFieldIcon: 'IconBuildingSkyscraper',
},
@@ -300,16 +292,16 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
expect(sourceFieldMetadata.type).toBe(expectedSourceFieldType);
expect(sourceFieldMetadata.name).toBe(input.createFieldInput.name);
expect(sourceFieldMetadata.label).toBe(input.createFieldInput.label);
expect(sourceFieldMetadata.objectMetadataId).toBe(
input.sourceFlatObjectMetadata.id,
);
expect(sourceFieldMetadata.relationTargetObjectMetadataId).toBe(
input.targetFlatObjectMetadata.id,
expect(sourceFieldMetadata.objectMetadataUniversalIdentifier).toBe(
input.sourceFlatObjectMetadata.universalIdentifier,
);
expect(
sourceFieldMetadata.relationTargetObjectMetadataUniversalIdentifier,
).toBe(input.targetFlatObjectMetadata.universalIdentifier);
const sourceSettings =
sourceFieldMetadata.settings as FieldMetadataSettingsMapping['RELATION'];
sourceFieldMetadata.universalSettings as FieldMetadataSettingsMapping['RELATION'];
const targetSettings =
targetFieldMetadata.settings as FieldMetadataSettingsMapping['RELATION'];
targetFieldMetadata.universalSettings as FieldMetadataSettingsMapping['RELATION'];
expect(sourceSettings.relationType).toBe(expectedSourceRelationType);
@@ -320,20 +312,20 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
}
expect(targetFieldMetadata.type).toBe(expectedTargetFieldType);
expect(targetFieldMetadata.objectMetadataId).toBe(
input.targetFlatObjectMetadata.id,
);
expect(targetFieldMetadata.relationTargetObjectMetadataId).toBe(
input.sourceFlatObjectMetadata.id,
expect(targetFieldMetadata.objectMetadataUniversalIdentifier).toBe(
input.targetFlatObjectMetadata.universalIdentifier,
);
expect(
targetFieldMetadata.relationTargetObjectMetadataUniversalIdentifier,
).toBe(input.sourceFlatObjectMetadata.universalIdentifier);
expect(targetSettings.relationType).toBe(expectedTargetRelationType);
expect(sourceFieldMetadata.relationTargetFieldMetadataId).toBe(
targetFieldMetadata.id,
);
expect(targetFieldMetadata.relationTargetFieldMetadataId).toBe(
sourceFieldMetadata.id,
);
expect(
sourceFieldMetadata.relationTargetFieldMetadataUniversalIdentifier,
).toBe(targetFieldMetadata.universalIdentifier);
expect(
targetFieldMetadata.relationTargetFieldMetadataUniversalIdentifier,
).toBe(sourceFieldMetadata.universalIdentifier);
if (expectedSourceRelationType === RelationType.MANY_TO_ONE) {
expect(sourceSettings.joinColumnName).toBe(
@@ -359,7 +351,6 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
targetFlatObjectMetadata: PET_FLAT_OBJECT_MOCK,
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
sourceFlatObjectMetadataJoinColumnName: 'petId',
workspaceId: mockWorkspaceId,
flatApplication: MOCK_FLAT_APPLICATION,
createFieldInput: {
name: 'pets',
@@ -367,7 +358,6 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
description: 'Company pets',
icon: 'IconCat',
type: FieldMetadataType.RELATION,
objectMetadataId: COMPANY_FLAT_OBJECT_MOCK.id,
isCustom: true,
isSystem: false,
isUnique: false,
@@ -1,7 +1,14 @@
import { FieldMetadataType, type FromTo } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { type UpdateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input';
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 { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { FLAT_FIELD_METADATA_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-editable-properties.constant';
import { FLAT_FIELD_METADATA_MORPH_RELATION_EDITABLE_PROPERTIES_ON_SIBLING_MORPH_RELATION_UPDATE_CONSTANT } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-morph-relation-editable-properties-on-sibling-morph-relation-update.constant';
import { FLAT_FIELD_METADATA_RELATION_EDITABLE_PROPERTIES_ON_SIBLING_MORPH_OR_RELATION_UPDATE_CONSTANT } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-relation-editable-properties-on-sibling-morph-or-relation-update.constant';
@@ -58,6 +65,45 @@ export const computeFlatFieldToUpdateAndRelatedFlatFieldToUpdate = ({
standardOverrides,
};
if (updatedEditableFieldProperties.settings !== undefined) {
const updatedSettings = toFlatFieldMetadata.settings;
const isRelationSettings =
isFieldMetadataSettingsOfType(
updatedSettings,
FieldMetadataType.RELATION,
) ||
isFieldMetadataSettingsOfType(
updatedSettings,
FieldMetadataType.MORPH_RELATION,
);
if (
isRelationSettings &&
isDefined(updatedSettings?.junctionTargetFieldId)
) {
const junctionFlatFieldMetadata = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: updatedSettings.junctionTargetFieldId,
flatEntityMaps: flatFieldMetadataMaps,
});
if (!isDefined(junctionFlatFieldMetadata)) {
throw new FlatEntityMapsException(
`Field metadata universal identifier not found for id: ${updatedSettings.junctionTargetFieldId}`,
FlatEntityMapsExceptionCode.RELATION_UNIVERSAL_IDENTIFIER_NOT_FOUND,
);
}
toFlatFieldMetadata.universalSettings = {
...updatedSettings,
junctionTargetFieldUniversalIdentifier:
junctionFlatFieldMetadata.universalIdentifier,
};
} else {
toFlatFieldMetadata.universalSettings = updatedSettings;
}
}
if (
isFlatFieldMetadataOfType(fromFlatFieldMetadata, FieldMetadataType.RELATION)
) {
@@ -7,14 +7,15 @@ import { computeMorphRelationFieldName, isDefined } from 'twenty-shared/utils';
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.util';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { extractJunctionTargetSettingsFromSettings } from 'src/engine/metadata-modules/flat-field-metadata/utils/extract-junction-target-settings-from-settings.util';
import { generateMorphOrRelationFlatFieldMetadataPair } from 'src/engine/metadata-modules/flat-field-metadata/utils/generate-morph-or-relation-flat-field-metadata-pair.util';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { getMorphNameFromMorphFieldMetadataName } from 'src/engine/metadata-modules/flat-object-metadata/utils/get-morph-name-from-morph-field-metadata-name.util';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
type ComputeFlatFieldToUpdateFromMorphRelationUpdatePayloadArgs = {
flatApplication: FlatApplication;
@@ -31,11 +32,11 @@ export const computeFlatFieldToUpdateFromMorphRelationUpdatePayload = ({
fieldMetadataToUpdate,
flatObjectMetadataMaps,
}: ComputeFlatFieldToUpdateFromMorphRelationUpdatePayloadArgs): {
flatFieldMetadatasToCreate: FlatFieldMetadata[];
flatIndexMetadatasToCreate: FlatIndexMetadata[];
flatFieldMetadatasToCreate: UniversalFlatFieldMetadata[];
flatIndexMetadatasToCreate: UniversalFlatIndexMetadata[];
} => {
const flatFieldMetadatasToCreate: FlatFieldMetadata[] = [];
const flatIndexMetadatasToCreate: FlatIndexMetadata[] = [];
const flatFieldMetadatasToCreate: UniversalFlatFieldMetadata[] = [];
const flatIndexMetadatasToCreate: UniversalFlatIndexMetadata[] = [];
if (!isDefined(morphRelationsUpdatePayload)) {
return { flatFieldMetadatasToCreate, flatIndexMetadatasToCreate };
@@ -57,7 +58,7 @@ export const computeFlatFieldToUpdateFromMorphRelationUpdatePayload = ({
const morphNameWithoutObjectName = getMorphNameFromMorphFieldMetadataName({
morphRelationFlatFieldMetadata: {
name: fieldMetadataToUpdate.name,
settings: fieldMetadataToUpdate.settings,
universalSettings: fieldMetadataToUpdate.universalSettings,
},
nameSingular: initialFlatFieldMetadataTargetObjectMetadata.nameSingular,
namePlural: initialFlatFieldMetadataTargetObjectMetadata.namePlural,
@@ -69,7 +70,6 @@ export const computeFlatFieldToUpdateFromMorphRelationUpdatePayload = ({
});
const commonTargetFieldLabel = initialTargetFieldMetadata.label;
const commonTargetFieldName = initialTargetFieldMetadata.name;
const commonObjectMetadataId = initialTargetFieldMetadata.objectMetadataId;
const { junctionTargetFieldId } = extractJunctionTargetSettingsFromSettings(
fieldMetadataToUpdate.settings,
@@ -102,7 +102,6 @@ export const computeFlatFieldToUpdateFromMorphRelationUpdatePayload = ({
type: FieldMetadataType.MORPH_RELATION,
name: computedMorphName,
label: morphRelationsCommonLabel,
objectMetadataId: commonObjectMetadataId,
relationCreationPayload: {
type: fieldMetadataToUpdate.settings.relationType,
targetObjectMetadataId,
@@ -113,7 +112,6 @@ export const computeFlatFieldToUpdateFromMorphRelationUpdatePayload = ({
sourceFlatObjectMetadata: sourceObjectMetadata,
targetFlatObjectMetadata: newTargetObjectMetadata,
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
workspaceId: fieldMetadataToUpdate.workspaceId,
flatApplication,
sourceFlatObjectMetadataJoinColumnName:
computeMorphOrRelationFieldJoinColumnName({
@@ -17,29 +17,27 @@ import { generateRatingOptions } from 'src/engine/metadata-modules/field-metadat
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { type FieldInputTranspilationResult } from 'src/engine/metadata-modules/flat-field-metadata/types/field-input-transpilation-result.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { fromMorphRelationCreateFieldInputToFlatFieldMetadatas } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-morph-relation-create-field-input-to-flat-field-metadatas.util';
import { fromRelationCreateFieldInputToFlatFieldMetadatas } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-relation-create-field-input-to-flat-field-metadatas.util';
import { generateIndexForFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/generate-index-for-flat-field-metadata.util';
import { getDefaultFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/get-default-flat-field-metadata-from-create-field-input.util';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
export type FromCreateFieldInputToFlatObjectMetadataArgs = {
createFieldInput: Omit<CreateFieldInput, 'workspaceId'>;
workspaceId: string;
flatApplication: FlatApplication;
} & Pick<AllFlatEntityMaps, 'flatObjectMetadataMaps' | 'flatFieldMetadataMaps'>;
export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
createFieldInput: rawCreateFieldInput,
workspaceId,
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
flatApplication,
}: FromCreateFieldInputToFlatObjectMetadataArgs): Promise<
FieldInputTranspilationResult<{
flatFieldMetadatas: FlatFieldMetadata[];
indexMetadatas: FlatIndexMetadata[];
flatFieldMetadatas: UniversalFlatFieldMetadata[];
indexMetadatas: UniversalFlatIndexMetadata[];
}>
> => {
if (rawCreateFieldInput.isRemoteCreation) {
@@ -77,11 +75,8 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
};
}
const fieldMetadataId = v4();
const commonFlatFieldMetadata = getDefaultFlatFieldMetadata({
createFieldInput,
workspaceId,
fieldMetadataId,
flatApplication,
objectMetadataUniversalIdentifier:
parentFlatObjectMetadata.universalIdentifier,
@@ -97,7 +92,6 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
existingFlatObjectMetadataMaps,
existingFlatFieldMetadataMaps,
sourceFlatObjectMetadata: parentFlatObjectMetadata,
workspaceId,
flatApplication,
});
}
@@ -110,7 +104,6 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
...createFieldInput,
type: createFieldInput.type,
},
workspaceId,
flatApplication,
});
}
@@ -122,11 +115,12 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
{
...commonFlatFieldMetadata,
type: createFieldInput.type,
settings: null,
defaultValue: commonFlatFieldMetadata.defaultValue as string, // Could this be improved ?
options: generateRatingOptions(),
universalSettings: null,
} satisfies FlatFieldMetadata<typeof createFieldInput.type>,
} satisfies UniversalFlatFieldMetadata<
typeof createFieldInput.type
>,
],
indexMetadatas: [],
},
@@ -153,9 +147,10 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
type: createFieldInput.type,
options,
defaultValue: commonFlatFieldMetadata.defaultValue as string, // Could this be improved ?
settings: null,
universalSettings: null,
} satisfies FlatFieldMetadata<typeof createFieldInput.type>,
} satisfies UniversalFlatFieldMetadata<
typeof createFieldInput.type
>,
],
indexMetadatas: [],
},
@@ -192,14 +187,13 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
case FieldMetadataType.RICH_TEXT_V2:
case FieldMetadataType.ACTOR:
case FieldMetadataType.ARRAY: {
const indexMetadatas: FlatIndexMetadata[] = [];
const indexMetadatas: UniversalFlatIndexMetadata[] = [];
if (commonFlatFieldMetadata.isUnique) {
indexMetadatas.push(
generateIndexForFlatFieldMetadata({
flatFieldMetadata: commonFlatFieldMetadata,
flatObjectMetadata: parentFlatObjectMetadata,
workspaceId,
}),
);
}
@@ -9,13 +9,14 @@ import {
FieldMetadataExceptionCode,
} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { findFlatEntityByUniversalIdentifierOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier-or-throw.util';
import { findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-universal-identifier-in-universal-flat-entity-maps-or-throw.util';
import { computeFlatFieldMetadataRelatedFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/compute-flat-field-metadata-related-flat-field-metadata.util';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { generateFlatIndexMetadataWithNameOrThrow } from 'src/engine/metadata-modules/index-metadata/utils/generate-flat-index.util';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
type FromDeleteFieldInputToFlatFieldMetadatasToDeleteArgs = {
deleteOneFieldInput: DeleteOneFieldInput;
@@ -30,9 +31,9 @@ export const fromDeleteFieldInputToFlatFieldMetadatasToDelete = ({
flatIndexMaps: existingFlatIndexMaps,
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
}: FromDeleteFieldInputToFlatFieldMetadatasToDeleteArgs): {
flatFieldMetadatasToDelete: FlatFieldMetadata[];
flatIndexesToUpdate: FlatIndexMetadata[];
flatIndexesToDelete: FlatIndexMetadata[];
flatFieldMetadatasToDelete: UniversalFlatFieldMetadata[];
flatIndexesToUpdate: UniversalFlatIndexMetadata[];
flatIndexesToDelete: UniversalFlatIndexMetadata[];
} => {
const { id: fieldMetadataToDeleteId } =
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
@@ -125,8 +126,8 @@ export const fromDeleteFieldInputToFlatFieldMetadatasToDelete = ({
const { flatIndexesToDelete, flatIndexesToUpdate } = [
...flatIndexMap.values(),
].reduce<{
flatIndexesToUpdate: FlatIndexMetadata[];
flatIndexesToDelete: FlatIndexMetadata[];
flatIndexesToUpdate: UniversalFlatIndexMetadata[];
flatIndexesToDelete: UniversalFlatIndexMetadata[];
}>(
(acc, flatIndex) => {
if (flatIndex.flatIndexFieldMetadatas.length === 0) {
@@ -136,15 +137,17 @@ export const fromDeleteFieldInputToFlatFieldMetadatasToDelete = ({
};
}
const flatObjectMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
const flatObjectMetadata = findFlatEntityByUniversalIdentifierOrThrow({
flatEntityMaps: existingFlatObjectMetadataMaps,
flatEntityId: flatIndex.objectMetadataId,
universalIdentifier: flatIndex.objectMetadataUniversalIdentifier,
});
const objectFlatFieldMetadatas =
findManyFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityMaps: existingFlatFieldMetadataMaps,
flatEntityIds: flatObjectMetadata.fieldIds,
});
findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrow(
{
flatEntityMaps: existingFlatFieldMetadataMaps,
universalIdentifiers: flatObjectMetadata.fieldUniversalIdentifiers,
},
);
const newIndex = generateFlatIndexMetadataWithNameOrThrow({
flatObjectMetadata,
@@ -14,8 +14,9 @@ import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-m
import { extractJunctionTargetSettingsFromSettings } from 'src/engine/metadata-modules/flat-field-metadata/utils/extract-junction-target-settings-from-settings.util';
import { generateMorphOrRelationFlatFieldMetadataPair } from 'src/engine/metadata-modules/flat-field-metadata/utils/generate-morph-or-relation-flat-field-metadata-pair.util';
import { validateMorphRelationCreationPayload } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-morph-relation-creation-payload.util';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
type FromMorphRelationCreateFieldInputToFlatFieldMetadatasArgs = {
createFieldInput: Omit<CreateFieldInput, 'workspaceId'> & {
@@ -24,7 +25,6 @@ type FromMorphRelationCreateFieldInputToFlatFieldMetadatasArgs = {
existingFlatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
existingFlatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
sourceFlatObjectMetadata: FlatObjectMetadata;
workspaceId: string;
flatApplication: FlatApplication;
};
export const fromMorphRelationCreateFieldInputToFlatFieldMetadatas = async ({
@@ -32,12 +32,11 @@ export const fromMorphRelationCreateFieldInputToFlatFieldMetadatas = async ({
existingFlatObjectMetadataMaps,
existingFlatFieldMetadataMaps,
sourceFlatObjectMetadata,
workspaceId,
flatApplication,
}: FromMorphRelationCreateFieldInputToFlatFieldMetadatasArgs): Promise<
FieldInputTranspilationResult<{
flatFieldMetadatas: FlatFieldMetadata[];
indexMetadatas: FlatIndexMetadata[];
flatFieldMetadatas: UniversalFlatFieldMetadata[];
indexMetadatas: UniversalFlatIndexMetadata[];
}>
> => {
const rawMorphCreationPayload =
@@ -64,7 +63,8 @@ export const fromMorphRelationCreateFieldInputToFlatFieldMetadatas = async ({
await validateMorphRelationCreationPayload({
existingFlatObjectMetadataMaps,
morphRelationCreationPayload: rawMorphCreationPayload,
objectMetadataId: sourceFlatObjectMetadata.id,
objectMetadataUniversalIdentifier:
sourceFlatObjectMetadata.universalIdentifier,
});
if (morphRelationCreationPayloadValidation.status === 'fail') {
@@ -108,7 +108,6 @@ export const fromMorphRelationCreateFieldInputToFlatFieldMetadatas = async ({
sourceFlatObjectMetadata,
targetFlatObjectMetadata,
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
workspaceId,
morphId,
flatApplication,
junctionTargetFlatFieldMetadata,
@@ -11,12 +11,11 @@ import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/
import { type FieldInputTranspilationResult } from 'src/engine/metadata-modules/flat-field-metadata/types/field-input-transpilation-result.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { extractJunctionTargetSettingsFromSettings } from 'src/engine/metadata-modules/flat-field-metadata/utils/extract-junction-target-settings-from-settings.util';
import {
generateMorphOrRelationFlatFieldMetadataPair,
type SourceTargetMorphOrRelationFlatFieldAndFlatIndex,
} from 'src/engine/metadata-modules/flat-field-metadata/utils/generate-morph-or-relation-flat-field-metadata-pair.util';
import { generateMorphOrRelationFlatFieldMetadataPair } from 'src/engine/metadata-modules/flat-field-metadata/utils/generate-morph-or-relation-flat-field-metadata-pair.util';
import { validateRelationCreationPayload } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-relation-creation-payload.util';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
type FromRelationCreateFieldInputToFlatFieldMetadataArgs = {
createFieldInput: Omit<CreateFieldInput, 'workspaceId'> & {
@@ -25,7 +24,6 @@ type FromRelationCreateFieldInputToFlatFieldMetadataArgs = {
existingFlatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
existingFlatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
sourceFlatObjectMetadata: FlatObjectMetadata;
workspaceId: string;
flatApplication: FlatApplication;
};
export const fromRelationCreateFieldInputToFlatFieldMetadatas = async ({
@@ -33,10 +31,12 @@ export const fromRelationCreateFieldInputToFlatFieldMetadatas = async ({
existingFlatFieldMetadataMaps,
sourceFlatObjectMetadata,
createFieldInput,
workspaceId,
flatApplication,
}: FromRelationCreateFieldInputToFlatFieldMetadataArgs): Promise<
FieldInputTranspilationResult<SourceTargetMorphOrRelationFlatFieldAndFlatIndex>
FieldInputTranspilationResult<{
flatFieldMetadatas: UniversalFlatFieldMetadata[];
indexMetadatas: UniversalFlatIndexMetadata[];
}>
> => {
const rawCreationPayload = createFieldInput.relationCreationPayload;
@@ -87,7 +87,6 @@ export const fromRelationCreateFieldInputToFlatFieldMetadatas = async ({
sourceFlatObjectMetadata,
targetFlatObjectMetadata,
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
workspaceId,
flatApplication,
junctionTargetFlatFieldMetadata,
});
@@ -12,7 +12,6 @@ import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { type FieldInputTranspilationResult } from 'src/engine/metadata-modules/flat-field-metadata/types/field-input-transpilation-result.type';
import { type FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { computeFlatFieldToUpdateAndRelatedFlatFieldToUpdate } from 'src/engine/metadata-modules/flat-field-metadata/utils/compute-flat-field-to-update-and-related-flat-field-to-update.util';
import { computeFlatFieldToUpdateFromMorphRelationUpdatePayload } from 'src/engine/metadata-modules/flat-field-metadata/utils/compute-flat-field-to-update-from-morph-relation-update-payload.util';
import {
@@ -21,6 +20,7 @@ import {
handleFlatFieldMetadataUpdateSideEffect,
} from 'src/engine/metadata-modules/flat-field-metadata/utils/handle-flat-field-metadata-update-side-effect.util';
import { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
type FromUpdateFieldInputToFlatFieldMetadataArgs = {
updateFieldInput: UpdateFieldInput;
@@ -38,8 +38,8 @@ type FromUpdateFieldInputToFlatFieldMetadataArgs = {
>;
type FlatFieldMetadataAndIndexToUpdate = {
flatFieldMetadatasToUpdate: FlatFieldMetadata[];
flatFieldMetadatasToCreate: FlatFieldMetadata[];
flatFieldMetadatasToUpdate: UniversalFlatFieldMetadata[];
flatFieldMetadatasToCreate: UniversalFlatFieldMetadata[];
} & FlatFieldMetadataUpdateSideEffects;
export const fromUpdateFieldInputToFlatFieldMetadata = ({
flatApplication,
@@ -1,58 +1,51 @@
import { v4 } from 'uuid';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { IndexType } from 'src/engine/metadata-modules/index-metadata/types/indexType.types';
import { generateFlatIndexMetadataWithNameOrThrow } from 'src/engine/metadata-modules/index-metadata/utils/generate-flat-index.util';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
type GenerateIndexForFlatFieldMetadataArgs = {
flatFieldMetadata: FlatFieldMetadata;
flatObjectMetadata: FlatObjectMetadata;
workspaceId: string;
flatFieldMetadata: UniversalFlatFieldMetadata;
flatObjectMetadata: UniversalFlatObjectMetadata;
};
export const generateIndexForFlatFieldMetadata = ({
flatFieldMetadata,
flatObjectMetadata,
workspaceId,
}: GenerateIndexForFlatFieldMetadataArgs): FlatIndexMetadata => {
const indexId = v4();
}: GenerateIndexForFlatFieldMetadataArgs): UniversalFlatIndexMetadata => {
const indexMetadataUniversalIdentifier = v4();
const createdAt = new Date().toISOString();
const flatIndex: FlatIndexMetadata = generateFlatIndexMetadataWithNameOrThrow(
{
const flatIndex: UniversalFlatIndexMetadata =
generateFlatIndexMetadataWithNameOrThrow({
objectFlatFieldMetadatas: [flatFieldMetadata],
flatIndex: {
createdAt,
flatIndexFieldMetadatas: [
universalFlatIndexFieldMetadatas: [
{
createdAt,
fieldMetadataId: flatFieldMetadata.id,
id: v4(),
indexMetadataId: indexId,
fieldMetadataUniversalIdentifier:
flatFieldMetadata.universalIdentifier,
indexMetadataUniversalIdentifier,
order: 0,
updatedAt: createdAt,
},
],
id: indexId,
indexType: IndexType.BTREE,
indexWhereClause: null,
isCustom: true,
isUnique: flatFieldMetadata.isUnique ?? false,
objectMetadataId: flatObjectMetadata.id,
objectMetadataUniversalIdentifier:
flatObjectMetadata.universalIdentifier,
universalIdentifier: indexId,
universalIdentifier: indexMetadataUniversalIdentifier,
updatedAt: createdAt,
workspaceId,
applicationId: flatFieldMetadata.applicationId,
applicationUniversalIdentifier:
flatFieldMetadata.applicationUniversalIdentifier,
},
flatObjectMetadata,
},
);
});
return flatIndex;
};
@@ -13,27 +13,23 @@ import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-m
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { generateIndexForFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/generate-index-for-flat-field-metadata.util';
import { getDefaultFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/get-default-flat-field-metadata-from-create-field-input.util';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { buildDescriptionForRelationFieldMetadataOnFromField } from 'src/engine/metadata-modules/object-metadata/utils/build-description-for-relation-field-on-from-field.util';
import { buildDescriptionForRelationFieldMetadataOnToField } from 'src/engine/metadata-modules/object-metadata/utils/build-description-for-relation-field-on-to-field.util';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
type ComputeFieldMetadataRelationSettingsForRelationTypeArgs = {
relationType: RelationType;
joinColumnName: string;
junctionTargetFieldId?: string;
junctionTargetFieldUniversalIdentifier?: string;
};
const computeFieldMetadataRelationSettingsForRelationType = ({
relationType,
joinColumnName,
junctionTargetFieldId,
junctionTargetFieldUniversalIdentifier,
}: ComputeFieldMetadataRelationSettingsForRelationTypeArgs): Pick<
FlatFieldMetadata<MorphOrRelationFieldMetadataType>,
'settings' | 'universalSettings'
> => {
}: ComputeFieldMetadataRelationSettingsForRelationTypeArgs): FlatFieldMetadata<MorphOrRelationFieldMetadataType>['universalSettings'] => {
if (relationType === RelationType.MANY_TO_ONE) {
const settings = {
relationType: RelationType.MANY_TO_ONE,
@@ -41,33 +37,26 @@ const computeFieldMetadataRelationSettingsForRelationType = ({
joinColumnName,
};
return { settings, universalSettings: settings };
return settings;
}
return {
settings: {
relationType: RelationType.ONE_TO_MANY,
...(junctionTargetFieldId && { junctionTargetFieldId }),
},
universalSettings: {
relationType: RelationType.ONE_TO_MANY,
...(junctionTargetFieldUniversalIdentifier && {
junctionTargetFieldUniversalIdentifier,
}),
},
relationType: RelationType.ONE_TO_MANY,
...(junctionTargetFieldUniversalIdentifier && {
junctionTargetFieldUniversalIdentifier,
}),
};
};
type GenerateMorphOrRelationFlatFieldMetadataPairArgs = {
targetFlatObjectMetadata: FlatObjectMetadata;
sourceFlatObjectMetadata: FlatObjectMetadata;
targetFlatObjectMetadata: UniversalFlatObjectMetadata;
sourceFlatObjectMetadata: UniversalFlatObjectMetadata;
targetFlatFieldMetadataType: FieldMetadataType;
sourceFlatObjectMetadataJoinColumnName: string;
createFieldInput: Omit<CreateFieldInput, 'workspaceId'> &
createFieldInput: Omit<CreateFieldInput, 'workspaceId' | 'objectMetadataId'> &
Required<
Pick<CreateFieldInput, 'relationCreationPayload' | 'type' | 'name'>
> & { type: MorphOrRelationFieldMetadataType };
workspaceId: string;
morphId?: string | null;
flatApplication: FlatApplication;
targetFieldName?: string;
@@ -75,8 +64,8 @@ type GenerateMorphOrRelationFlatFieldMetadataPairArgs = {
};
export type SourceTargetMorphOrRelationFlatFieldAndFlatIndex = {
flatFieldMetadatas: FlatFieldMetadata[];
indexMetadatas: FlatIndexMetadata[];
flatFieldMetadatas: UniversalFlatFieldMetadata[];
indexMetadatas: UniversalFlatIndexMetadata[];
};
export const generateMorphOrRelationFlatFieldMetadataPair = ({
@@ -84,7 +73,6 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({
sourceFlatObjectMetadata,
targetFlatObjectMetadata,
targetFlatFieldMetadataType,
workspaceId,
flatApplication,
sourceFlatObjectMetadataJoinColumnName,
morphId = null,
@@ -95,18 +83,14 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({
const { relationCreationPayload } = createFieldInput;
const {
settings: sourceFlatFieldMetadataSettings,
universalSettings: sourceFlatFieldMetadataUniversalSettings,
} = computeFieldMetadataRelationSettingsForRelationType({
joinColumnName: sourceFlatObjectMetadataJoinColumnName,
relationType: relationCreationPayload.type,
junctionTargetFieldId: junctionTargetFlatFieldMetadata?.id,
junctionTargetFieldUniversalIdentifier:
junctionTargetFlatFieldMetadata?.universalIdentifier,
});
const targetRelationTargetFieldMetadataId = v4();
const sourceRelationTargetFieldMetadataId = v4();
const sourceFlatFieldMetadataUniversalSettings =
computeFieldMetadataRelationSettingsForRelationType({
joinColumnName: sourceFlatObjectMetadataJoinColumnName,
relationType: relationCreationPayload.type,
junctionTargetFieldUniversalIdentifier:
junctionTargetFlatFieldMetadata?.universalIdentifier,
});
const sourceFieldUniversalIdentifier = v4();
const targetFieldUniversalIdentifier = v4();
const defaultDescriptionFromField =
@@ -119,40 +103,40 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({
relationObjectMetadataNamePlural: targetFlatObjectMetadata.namePlural,
targetObjectLabelSingular: sourceFlatObjectMetadata.labelSingular,
});
const sourceFlatFieldMetadata: Omit<
FlatFieldMetadata<MorphOrRelationFieldMetadataType>,
'flatRelationTargetFieldMetadata'
> = {
...getDefaultFlatFieldMetadata({
createFieldInput,
workspaceId,
fieldMetadataId: sourceRelationTargetFieldMetadataId,
flatApplication,
objectMetadataUniversalIdentifier:
sourceFlatObjectMetadata.universalIdentifier,
}),
morphId:
sourceFlatFieldMetadataType === FieldMetadataType.MORPH_RELATION
? morphId
: null,
objectMetadataId: sourceFlatObjectMetadata.id,
icon: createFieldInput.icon ?? 'IconRelationOneToMany',
type: sourceFlatFieldMetadataType,
description:
createFieldInput.description ?? defaultDescriptionFromField.description,
defaultValue: null,
settings: sourceFlatFieldMetadataSettings,
universalSettings: sourceFlatFieldMetadataUniversalSettings,
options: null,
relationTargetFieldMetadataId: targetRelationTargetFieldMetadataId,
relationTargetObjectMetadataId: targetFlatObjectMetadata.id,
relationTargetObjectMetadataUniversalIdentifier:
targetFlatObjectMetadata.universalIdentifier,
relationTargetFieldMetadataUniversalIdentifier:
targetFieldUniversalIdentifier,
};
const sourceFlatFieldMetadata: UniversalFlatFieldMetadata<MorphOrRelationFieldMetadataType> =
{
...getDefaultFlatFieldMetadata({
createFieldInput: {
...createFieldInput,
universalIdentifier:
createFieldInput.universalIdentifier ??
sourceFieldUniversalIdentifier,
},
flatApplication,
objectMetadataUniversalIdentifier:
sourceFlatObjectMetadata.universalIdentifier,
}),
morphId:
sourceFlatFieldMetadataType === FieldMetadataType.MORPH_RELATION
? morphId
: null,
icon: createFieldInput.icon ?? 'IconRelationOneToMany',
type: sourceFlatFieldMetadataType,
description:
createFieldInput.description ?? defaultDescriptionFromField.description,
defaultValue: null,
universalSettings: sourceFlatFieldMetadataUniversalSettings,
options: null,
relationTargetObjectMetadataUniversalIdentifier:
targetFlatObjectMetadata.universalIdentifier,
relationTargetFieldMetadataUniversalIdentifier:
targetFieldUniversalIdentifier,
};
const targetCreateFieldInput: CreateFieldInput = {
const targetCreateFieldInput: Omit<
CreateFieldInput,
'objectMetadataId' | 'workspaceId'
> = {
icon: relationCreationPayload.targetFieldIcon ?? 'Icon123',
description:
createFieldInput.description ?? defaultDescriptionToField.description,
@@ -162,25 +146,21 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({
computeMetadataNameFromLabel({
label: relationCreationPayload.targetFieldLabel,
}),
objectMetadataId: targetFlatObjectMetadata.id,
type: FieldMetadataType.RELATION,
workspaceId,
isSystem: createFieldInput.isSystem ?? false,
};
const {
settings: targetFlatFieldMetadataSettings,
universalSettings: targetFlatFieldMetadataUniversalSettings,
} = computeFieldMetadataRelationSettingsForRelationType({
joinColumnName: computeMorphOrRelationFieldJoinColumnName({
name: targetCreateFieldInput.name,
}),
relationType:
relationCreationPayload.type === RelationType.ONE_TO_MANY
? RelationType.MANY_TO_ONE
: RelationType.ONE_TO_MANY,
});
const targetFlatFieldMetadataUniversalSettings =
computeFieldMetadataRelationSettingsForRelationType({
joinColumnName: computeMorphOrRelationFieldJoinColumnName({
name: targetCreateFieldInput.name,
}),
relationType:
relationCreationPayload.type === RelationType.ONE_TO_MANY
? RelationType.MANY_TO_ONE
: RelationType.ONE_TO_MANY,
});
const targetFlatFieldMetadata: FlatFieldMetadata<
const targetFlatFieldMetadata: UniversalFlatFieldMetadata<
typeof targetFlatFieldMetadataType
> = {
...getDefaultFlatFieldMetadata({
@@ -188,8 +168,6 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({
...targetCreateFieldInput,
universalIdentifier: targetFieldUniversalIdentifier,
},
workspaceId,
fieldMetadataId: targetRelationTargetFieldMetadataId,
flatApplication,
objectMetadataUniversalIdentifier:
targetFlatObjectMetadata.universalIdentifier,
@@ -200,28 +178,25 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({
: null,
type: targetFlatFieldMetadataType,
defaultValue: null,
settings: targetFlatFieldMetadataSettings,
universalSettings: targetFlatFieldMetadataUniversalSettings,
options: null,
relationTargetFieldMetadataId: sourceRelationTargetFieldMetadataId,
relationTargetObjectMetadataId: sourceFlatObjectMetadata.id,
relationTargetObjectMetadataUniversalIdentifier:
sourceFlatObjectMetadata.universalIdentifier,
relationTargetFieldMetadataUniversalIdentifier:
sourceFlatFieldMetadata.universalIdentifier,
};
const indexMetadata: FlatIndexMetadata = generateIndexForFlatFieldMetadata({
flatFieldMetadata:
relationCreationPayload.type === RelationType.MANY_TO_ONE
? sourceFlatFieldMetadata
: targetFlatFieldMetadata,
flatObjectMetadata:
relationCreationPayload.type === RelationType.MANY_TO_ONE
? sourceFlatObjectMetadata
: targetFlatObjectMetadata,
workspaceId,
});
const indexMetadata: UniversalFlatIndexMetadata =
generateIndexForFlatFieldMetadata({
flatFieldMetadata:
relationCreationPayload.type === RelationType.MANY_TO_ONE
? sourceFlatFieldMetadata
: targetFlatFieldMetadata,
flatObjectMetadata:
relationCreationPayload.type === RelationType.MANY_TO_ONE
? sourceFlatObjectMetadata
: targetFlatObjectMetadata,
});
return {
flatFieldMetadatas: [sourceFlatFieldMetadata, targetFlatFieldMetadata],
@@ -5,19 +5,15 @@ import { type FlatApplication } from 'src/engine/core-modules/application/types/
import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
import { generateDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/generate-default-value';
import { generateNullable } from 'src/engine/metadata-modules/field-metadata/utils/generate-nullable';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
type GetDefaultFlatFieldMetadataArgs = {
fieldMetadataId: string;
createFieldInput: Omit<CreateFieldInput, 'workspaceId'>;
workspaceId: string;
createFieldInput: Omit<CreateFieldInput, 'workspaceId' | 'objectMetadataId'>;
flatApplication: FlatApplication;
objectMetadataUniversalIdentifier: string;
};
export const getDefaultFlatFieldMetadata = ({
createFieldInput,
fieldMetadataId,
workspaceId,
flatApplication,
objectMetadataUniversalIdentifier,
}: GetDefaultFlatFieldMetadataArgs) => {
@@ -29,11 +25,7 @@ export const getDefaultFlatFieldMetadata = ({
const createdAt = new Date().toISOString();
return {
calendarViewIds: [],
mainGroupByFieldMetadataViewIds: [],
viewFieldIds: [],
description: createFieldInput.description ?? null,
id: fieldMetadataId,
icon: createFieldInput.icon ?? null,
isActive: true,
isCustom: true,
@@ -46,23 +38,15 @@ export const getDefaultFlatFieldMetadata = ({
isUnique: createFieldInput.isUnique ?? false,
label: createFieldInput.label,
name: createFieldInput.name,
objectMetadataId: createFieldInput.objectMetadataId,
relationTargetFieldMetadataId: null,
relationTargetObjectMetadataId: null,
standardOverrides: null,
type: createFieldInput.type,
universalIdentifier: createFieldInput.universalIdentifier ?? v4(),
workspaceId,
options: createFieldInput.options ?? null,
defaultValue: defaultValue ?? generateDefaultValue(createFieldInput.type),
settings: settings ?? null,
createdAt,
updatedAt: createdAt,
isUIReadOnly: createFieldInput.isUIReadOnly ?? false,
morphId: null,
applicationId: flatApplication.id,
viewFilterIds: [],
kanbanAggregateOperationViewIds: [],
applicationUniversalIdentifier: flatApplication.universalIdentifier,
objectMetadataUniversalIdentifier,
relationTargetObjectMetadataUniversalIdentifier: null,
@@ -73,5 +57,5 @@ export const getDefaultFlatFieldMetadata = ({
calendarViewUniversalIdentifiers: [],
mainGroupByFieldMetadataViewUniversalIdentifiers: [],
universalSettings: settings ?? null,
} as const satisfies FlatFieldMetadata;
} as const satisfies UniversalFlatFieldMetadata;
};
@@ -1,59 +1,64 @@
import { RelationType } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-universal-identifier-in-universal-flat-entity-maps-or-throw.util';
import { isMorphOrRelationUniversalFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
import { type UniversalFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-maps.type';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
type ObjectFieldNamesAndJoinColumnNames = {
fieldNames: string[];
joinColumnNames: string[];
};
export const getObjectFieldNamesAndJoinColumnNames = ({
flatFieldMetadataMaps,
flatObjectMetadata,
universalFlatFieldMetadataMaps,
universalFlatObjectMetadata,
}: {
flatObjectMetadata: FlatObjectMetadata;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
universalFlatObjectMetadata: UniversalFlatObjectMetadata;
universalFlatFieldMetadataMaps: UniversalFlatEntityMaps<UniversalFlatFieldMetadata>;
}): {
objectFieldNamesAndJoinColumnNames: ObjectFieldNamesAndJoinColumnNames;
} => {
const objectFlatFieldMetadatas =
findManyFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityMaps: flatFieldMetadataMaps,
flatEntityIds: flatObjectMetadata.fieldIds,
const objectUniversalFlatFieldMetadatas =
findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrow({
flatEntityMaps: universalFlatFieldMetadataMaps,
universalIdentifiers:
universalFlatObjectMetadata.fieldUniversalIdentifiers,
});
const initialAccumulator: ObjectFieldNamesAndJoinColumnNames = {
joinColumnNames: [],
fieldNames: [],
};
const objectFieldNamesAndJoinColumnNames = objectFlatFieldMetadatas.reduce(
(acc, flatFieldMetadata) => {
if (
isMorphOrRelationFlatFieldMetadata(flatFieldMetadata) &&
flatFieldMetadata.settings.relationType === RelationType.MANY_TO_ONE &&
isDefined(flatFieldMetadata.settings.joinColumnName)
) {
const objectFieldNamesAndJoinColumnNames =
objectUniversalFlatFieldMetadatas.reduce(
(acc, universalFlatFieldMetadata) => {
if (
isMorphOrRelationUniversalFlatFieldMetadata(
universalFlatFieldMetadata,
) &&
universalFlatFieldMetadata.universalSettings.relationType ===
RelationType.MANY_TO_ONE &&
isDefined(universalFlatFieldMetadata.universalSettings.joinColumnName)
) {
return {
...acc,
fieldNames: [...acc.fieldNames, universalFlatFieldMetadata.name],
joinColumnNames: [
...acc.joinColumnNames,
universalFlatFieldMetadata.universalSettings.joinColumnName,
],
};
}
return {
...acc,
fieldNames: [...acc.fieldNames, flatFieldMetadata.name],
joinColumnNames: [
...acc.joinColumnNames,
flatFieldMetadata.settings.joinColumnName,
],
fieldNames: [...acc.fieldNames, universalFlatFieldMetadata.name],
};
}
return {
...acc,
fieldNames: [...acc.fieldNames, flatFieldMetadata.name],
};
},
initialAccumulator,
);
},
initialAccumulator,
);
return { objectFieldNamesAndJoinColumnNames };
};
@@ -96,6 +96,7 @@ export const handleFieldMetadataDeactivationSideEffects = ({
...flatView,
kanbanAggregateOperation: null,
kanbanAggregateOperationFieldMetadataId: null,
kanbanAggregateOperationFieldMetadataUniversalIdentifier: null,
}));
return {
@@ -14,11 +14,12 @@ import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/
import { recomputeIndexOnFlatFieldMetadataNameUpdate } from 'src/engine/metadata-modules/flat-field-metadata/utils/recompute-index-on-flat-field-metadata-name-update.util';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
export type FieldMetadataUpdateIndexSideEffect = {
flatIndexMetadatasToUpdate: FlatIndexMetadata[];
flatIndexMetadatasToDelete: FlatIndexMetadata[];
flatIndexMetadatasToCreate: FlatIndexMetadata[];
flatIndexMetadatasToUpdate: UniversalFlatIndexMetadata[];
flatIndexMetadatasToDelete: UniversalFlatIndexMetadata[];
flatIndexMetadatasToCreate: UniversalFlatIndexMetadata[];
};
type FromToFlatFieldMetadataAndFlatEntityMaps = FromTo<
@@ -110,7 +111,6 @@ const handleNoExistingIndexes = ({
const newIndex = generateIndexForFlatFieldMetadata({
flatFieldMetadata: toFlatFieldMetadata,
flatObjectMetadata,
workspaceId: flatObjectMetadata.workspaceId,
});
return {
@@ -146,7 +146,6 @@ const handleExistingIndexes = ({
isUnique: true,
},
flatObjectMetadata,
workspaceId: flatObjectMetadata.workspaceId,
});
const uniqueIndexToDelete = relatedIndexes.find(
@@ -58,8 +58,8 @@ export const handleLabelIdentifierChangesDuringFieldUpdate = ({
return {
...searchVectorField,
settings: {
...searchVectorField.settings,
universalSettings: {
...searchVectorField.universalSettings,
asExpression: newAsExpression,
},
};
@@ -4,6 +4,7 @@ import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-m
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { generateFlatIndexMetadataWithNameOrThrow } from 'src/engine/metadata-modules/index-metadata/utils/generate-flat-index.util';
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
type RecomputeIndexOnFlatFieldMetadataNameUpdateArgs = {
flatObjectMetadata: FlatObjectMetadata;
@@ -18,7 +19,7 @@ export const recomputeIndexOnFlatFieldMetadataNameUpdate = ({
flatObjectMetadata,
flatFieldMetadataMaps,
relatedFlatIndexMetadata,
}: RecomputeIndexOnFlatFieldMetadataNameUpdateArgs): FlatIndexMetadata[] => {
}: RecomputeIndexOnFlatFieldMetadataNameUpdateArgs): UniversalFlatIndexMetadata[] => {
if (relatedFlatIndexMetadata.length === 0) {
return [];
}
@@ -1,33 +1,36 @@
import { FieldMetadataType } from 'twenty-shared/types';
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type';
import { validateFilesFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-files-flat-field-metadata.util';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
const createFlatEntityToValidate = (
overrides: Partial<FlatFieldMetadata<FieldMetadataType.FILES>> = {},
): FlatFieldMetadata<FieldMetadataType.FILES> =>
overrides: Partial<UniversalFlatFieldMetadata<FieldMetadataType.FILES>> = {},
): UniversalFlatFieldMetadata<FieldMetadataType.FILES> =>
({
type: FieldMetadataType.FILES,
name: 'testFilesField',
label: 'Test Files Field',
settings: { maxNumberOfValues: 5 },
universalSettings: { maxNumberOfValues: 5 },
isUnique: false,
...overrides,
}) as FlatFieldMetadata<FieldMetadataType.FILES>;
}) as UniversalFlatFieldMetadata<FieldMetadataType.FILES>;
const callValidator = (
flatEntityToValidate: FlatFieldMetadata<FieldMetadataType.FILES>,
flatEntityToValidate: UniversalFlatFieldMetadata<FieldMetadataType.FILES>,
) =>
validateFilesFlatFieldMetadata({
flatEntityToValidate,
} as Parameters<typeof validateFilesFlatFieldMetadata>[0]);
const stripUserFriendlyMessage = (errors: FlatFieldMetadataValidationError[]) =>
errors.map(({ userFriendlyMessage: _, ...rest }) => rest);
describe('validateFilesFlatFieldMetadata', () => {
it('should return no errors for a valid files field', () => {
const errors = callValidator(createFlatEntityToValidate());
expect(errors).toHaveLength(0);
expect(errors).toMatchInlineSnapshot('[]');
});
it('should return error when isUnique is true', () => {
@@ -35,40 +38,62 @@ describe('validateFilesFlatFieldMetadata', () => {
createFlatEntityToValidate({ isUnique: true }),
);
expect(errors).toHaveLength(1);
expect(errors[0].code).toBe(FieldMetadataExceptionCode.INVALID_FIELD_INPUT);
expect(errors[0].message).toContain(
'Files field is not supported for unique fields',
);
expect(stripUserFriendlyMessage(errors)).toMatchInlineSnapshot(`
[
{
"code": "INVALID_FIELD_INPUT",
"message": "Files field is not supported for unique fields",
},
]
`);
});
it('should return error when settings is undefined', () => {
it('should return error when universalSettings is undefined', () => {
const errors = callValidator(
createFlatEntityToValidate({ settings: undefined }),
createFlatEntityToValidate({ universalSettings: undefined }),
);
expect(errors).toHaveLength(1);
expect(errors[0].code).toBe(FieldMetadataExceptionCode.INVALID_FIELD_INPUT);
expect(errors[0].message).toContain(
'maxNumberOfValues must be defined in settings',
);
expect(stripUserFriendlyMessage(errors)).toMatchInlineSnapshot(`
[
{
"code": "INVALID_FIELD_INPUT",
"message": "maxNumberOfValues must be defined in settings and be a number greater than 0 and less than or equal to 10",
},
]
`);
});
it('should return error when maxNumberOfValues is 0', () => {
const errors = callValidator(
createFlatEntityToValidate({ settings: { maxNumberOfValues: 0 } }),
createFlatEntityToValidate({
universalSettings: { maxNumberOfValues: 0 },
}),
);
expect(errors).toHaveLength(1);
expect(errors[0].code).toBe(FieldMetadataExceptionCode.INVALID_FIELD_INPUT);
expect(stripUserFriendlyMessage(errors)).toMatchInlineSnapshot(`
[
{
"code": "INVALID_FIELD_INPUT",
"message": "maxNumberOfValues must be defined in settings and be a number greater than 0 and less than or equal to 10",
},
]
`);
});
it('should return error when maxNumberOfValues exceeds max (11)', () => {
const errors = callValidator(
createFlatEntityToValidate({ settings: { maxNumberOfValues: 11 } }),
createFlatEntityToValidate({
universalSettings: { maxNumberOfValues: 11 },
}),
);
expect(errors).toHaveLength(1);
expect(errors[0].code).toBe(FieldMetadataExceptionCode.INVALID_FIELD_INPUT);
expect(stripUserFriendlyMessage(errors)).toMatchInlineSnapshot(`
[
{
"code": "INVALID_FIELD_INPUT",
"message": "maxNumberOfValues must be defined in settings and be a number greater than 0 and less than or equal to 10",
},
]
`);
});
});
@@ -17,9 +17,9 @@ import {
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { type FlatFieldMetadataTypeValidationArgs } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-type-validator.type';
import { type FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { IDENTIFIER_MAX_CHAR_LENGTH } from 'src/engine/metadata-modules/utils/constants/identifier-max-char-length.constants';
import { IDENTIFIER_MIN_CHAR_LENGTH } from 'src/engine/metadata-modules/utils/constants/identifier-min-char-length.constants';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
import { isSnakeCaseString } from 'src/utils/is-snake-case-string';
const validateMetadataOptionId = (sanitizedId?: string) => {
@@ -198,9 +198,9 @@ const validateDuplicates = (
};
const validateFieldMetadataInputOptions = (
flatFieldMetadata: FlatFieldMetadata<EnumFieldMetadataType>,
universalFlatFieldMetadata: UniversalFlatFieldMetadata<EnumFieldMetadataType>,
): FlatFieldMetadataValidationError[] => {
const { options } = flatFieldMetadata;
const { options } = universalFlatFieldMetadata;
if (!isDefined(options) || options.length === 0) {
return [
@@ -328,9 +328,9 @@ const validateFieldMetadataDefaultValue = ({
defaultValue,
options,
type,
}: Omit<FlatFieldMetadata<EnumFieldMetadataType>, 'defaultValue'> &
}: Omit<UniversalFlatFieldMetadata<EnumFieldMetadataType>, 'defaultValue'> &
NonNullableRequired<
Pick<FlatFieldMetadata<EnumFieldMetadataType>, 'defaultValue'>
Pick<UniversalFlatFieldMetadata<EnumFieldMetadataType>, 'defaultValue'>
>) => {
switch (type) {
case FieldMetadataType.SELECT:
@@ -354,18 +354,18 @@ const validateFieldMetadataDefaultValue = ({
};
export const validateEnumSelectFlatFieldMetadata = ({
flatEntityToValidate: flatFieldMetadataToValidate,
flatEntityToValidate: universalFlatFieldMetadataToValidate,
}: FlatFieldMetadataTypeValidationArgs<EnumFieldMetadataType>): FlatFieldMetadataValidationError[] => {
const optionsValidationErrors = validateFieldMetadataInputOptions(
flatFieldMetadataToValidate,
universalFlatFieldMetadataToValidate,
);
const defaultValueValidationErrors = isDefined(
flatFieldMetadataToValidate.defaultValue,
universalFlatFieldMetadataToValidate.defaultValue,
)
? validateFieldMetadataDefaultValue({
...flatFieldMetadataToValidate,
defaultValue: flatFieldMetadataToValidate.defaultValue,
...universalFlatFieldMetadataToValidate,
defaultValue: universalFlatFieldMetadataToValidate.defaultValue,
})
: [];
@@ -21,9 +21,9 @@ export const validateFilesFlatFieldMetadata = ({
}
if (
!isDefined(flatEntityToValidate?.settings?.maxNumberOfValues) ||
flatEntityToValidate.settings.maxNumberOfValues < 1 ||
flatEntityToValidate.settings.maxNumberOfValues >
!isDefined(flatEntityToValidate?.universalSettings?.maxNumberOfValues) ||
flatEntityToValidate.universalSettings.maxNumberOfValues < 1 ||
flatEntityToValidate.universalSettings.maxNumberOfValues >
FILES_FIELD_MAX_NUMBER_OF_VALUES
) {
errors.push({
@@ -5,56 +5,59 @@ import { isDefined } from 'twenty-shared/utils';
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { computeCompositeColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-column-name.util';
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-universal-identifier-in-universal-flat-entity-maps-or-throw.util';
import { type FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { getObjectFieldNamesAndJoinColumnNames } from 'src/engine/metadata-modules/flat-field-metadata/utils/get-object-field-names-and-join-column-names.util';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type UniversalFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-maps.type';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
import { type WorkspaceMigrationBuilderOptions } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/workspace-migration-builder-options.type';
const getReservedCompositeFieldNames = (
objectFlatFieldMetadatas: FlatFieldMetadata[],
objectUniversalFlatFieldMetadatas: UniversalFlatFieldMetadata[],
): string[] => {
return objectFlatFieldMetadatas.flatMap((flatFieldMetadata) => {
if (isCompositeFieldMetadataType(flatFieldMetadata.type)) {
const base = flatFieldMetadata.name;
const compositeType = compositeTypeDefinitions.get(
flatFieldMetadata.type,
);
return objectUniversalFlatFieldMetadatas.flatMap(
(universalFlatFieldMetadata) => {
if (isCompositeFieldMetadataType(universalFlatFieldMetadata.type)) {
const base = universalFlatFieldMetadata.name;
const compositeType = compositeTypeDefinitions.get(
universalFlatFieldMetadata.type,
);
if (!isDefined(compositeType)) {
return [];
if (!isDefined(compositeType)) {
return [];
}
return compositeType.properties.map((property) =>
computeCompositeColumnName(base, property),
);
}
return compositeType.properties.map((property) =>
computeCompositeColumnName(base, property),
);
}
return [];
});
return [];
},
);
};
export const validateFlatFieldMetadataNameAvailability = ({
name,
flatFieldMetadataMaps,
flatObjectMetadata,
universalFlatFieldMetadataMaps,
universalFlatObjectMetadata,
buildOptions,
}: {
buildOptions: WorkspaceMigrationBuilderOptions;
name: string;
flatObjectMetadata: FlatObjectMetadata;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
universalFlatObjectMetadata: UniversalFlatObjectMetadata;
universalFlatFieldMetadataMaps: UniversalFlatEntityMaps<UniversalFlatFieldMetadata>;
}): FlatFieldMetadataValidationError[] => {
const errors: FlatFieldMetadataValidationError[] = [];
const objectFlatFieldMetadatas =
findManyFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityMaps: flatFieldMetadataMaps,
flatEntityIds: flatObjectMetadata.fieldIds,
const objectUniversalFlatFieldMetadatas =
findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrow({
flatEntityMaps: universalFlatFieldMetadataMaps,
universalIdentifiers:
universalFlatObjectMetadata.fieldUniversalIdentifiers,
});
const reservedCompositeFieldsNames = getReservedCompositeFieldNames(
objectFlatFieldMetadatas,
objectUniversalFlatFieldMetadatas,
);
if (
@@ -71,8 +74,8 @@ export const validateFlatFieldMetadataNameAvailability = ({
const { objectFieldNamesAndJoinColumnNames } =
getObjectFieldNamesAndJoinColumnNames({
flatFieldMetadataMaps,
flatObjectMetadata,
universalFlatFieldMetadataMaps,
universalFlatObjectMetadata,
});
if (objectFieldNamesAndJoinColumnNames.fieldNames.includes(name)) {
@@ -1,19 +1,19 @@
import { type MessageDescriptor } from '@lingui/core';
import { msg } from '@lingui/core/macro';
import { FieldMetadataType, RelationType } from 'twenty-shared/types';
import { isDefined, isValidUuid } from 'twenty-shared/utils';
import { isDefined } from 'twenty-shared/utils';
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { type MorphOrRelationFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/morph-or-relation-field-metadata-type.type';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
import { type FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
import { isMorphOrRelationUniversalFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
import { type UniversalFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-maps.type';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
type ValidateJunctionTargetSettingsArgs = {
flatFieldMetadata: FlatFieldMetadata<MorphOrRelationFieldMetadataType>;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
universalFlatFieldMetadata: UniversalFlatFieldMetadata<MorphOrRelationFieldMetadataType>;
flatFieldMetadataMaps: UniversalFlatEntityMaps<UniversalFlatFieldMetadata>;
};
const createError = (
@@ -29,18 +29,22 @@ const createError = (
});
export const validateJunctionTargetSettings = ({
flatFieldMetadata,
universalFlatFieldMetadata,
flatFieldMetadataMaps,
}: ValidateJunctionTargetSettingsArgs): FlatFieldMetadataValidationError[] => {
const { settings } = flatFieldMetadata;
const { universalSettings } = universalFlatFieldMetadata;
const junctionTargetFieldId = settings.junctionTargetFieldId;
const junctionTargetFieldUniversalIdentifier =
universalSettings.junctionTargetFieldUniversalIdentifier;
if (!isDefined(junctionTargetFieldId) || junctionTargetFieldId.length === 0) {
if (
!isDefined(junctionTargetFieldUniversalIdentifier) ||
junctionTargetFieldUniversalIdentifier.length === 0
) {
return [];
}
if (settings.relationType !== RelationType.ONE_TO_MANY) {
if (universalSettings.relationType !== RelationType.ONE_TO_MANY) {
return [
createError(
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
@@ -50,19 +54,8 @@ export const validateJunctionTargetSettings = ({
];
}
if (!isValidUuid(junctionTargetFieldId)) {
return [
createError(
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
`Invalid junction target field ID: ${junctionTargetFieldId}`,
msg`Invalid junction target field ID`,
junctionTargetFieldId,
),
];
}
const targetField = findFlatEntityByIdInFlatEntityMaps<FlatFieldMetadata>({
flatEntityId: junctionTargetFieldId,
const targetField = findFlatEntityByUniversalIdentifier({
universalIdentifier: junctionTargetFieldUniversalIdentifier,
flatEntityMaps: flatFieldMetadataMaps,
});
@@ -70,34 +63,34 @@ export const validateJunctionTargetSettings = ({
return [
createError(
FieldMetadataExceptionCode.FIELD_METADATA_NOT_FOUND,
`Junction target field not found: ${junctionTargetFieldId}`,
`Junction target field not found: ${junctionTargetFieldUniversalIdentifier}`,
msg`Junction target field not found`,
junctionTargetFieldId,
junctionTargetFieldUniversalIdentifier,
),
];
}
if (
targetField.objectMetadataId !==
flatFieldMetadata.relationTargetObjectMetadataId
targetField.objectMetadataUniversalIdentifier !==
universalFlatFieldMetadata.relationTargetObjectMetadataUniversalIdentifier
) {
return [
createError(
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
`Junction target field ${junctionTargetFieldId} is not on the junction object`,
`Junction target field ${junctionTargetFieldUniversalIdentifier} is not on the junction object`,
msg`Junction target field must be on the junction object`,
junctionTargetFieldId,
junctionTargetFieldUniversalIdentifier,
),
];
}
if (!isMorphOrRelationFlatFieldMetadata(targetField)) {
if (!isMorphOrRelationUniversalFlatFieldMetadata(targetField)) {
return [
createError(
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
`Junction target field ${junctionTargetFieldId} is not a relation field`,
`Junction target field ${junctionTargetFieldUniversalIdentifier} is not a relation field`,
msg`Junction target field must be a relation field`,
junctionTargetFieldId,
junctionTargetFieldUniversalIdentifier,
),
];
}
@@ -107,13 +100,13 @@ export const validateJunctionTargetSettings = ({
return [];
}
if (targetField.settings.relationType !== RelationType.MANY_TO_ONE) {
if (targetField.universalSettings.relationType !== RelationType.MANY_TO_ONE) {
return [
createError(
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
`Junction target field ${junctionTargetFieldId} is not a MANY_TO_ONE relation`,
`Junction target field ${junctionTargetFieldUniversalIdentifier} is not a MANY_TO_ONE relation`,
msg`Junction target field must be a MANY_TO_ONE relation`,
junctionTargetFieldId,
junctionTargetFieldUniversalIdentifier,
),
];
}
@@ -4,15 +4,15 @@ import { assertUnreachable, isDefined } from 'twenty-shared/utils';
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { type MorphOrRelationFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/morph-or-relation-field-metadata-type.type';
import { type MetadataFlatEntityAndRelatedFlatEntityMapsForValidation } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity-and-related-flat-entity-maps-for-validation.type';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { type MetadataUniversalFlatEntityAndRelatedFlatEntityMapsForValidation } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity-and-related-flat-entity-maps-for-validation.type';
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
import { type FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { validateFlatFieldMetadataNameAvailability } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name-availability.util';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
import { type WorkspaceMigrationBuilderOptions } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/workspace-migration-builder-options.type';
export const validateMorphOrRelationFlatFieldJoinColumName = ({
flatFieldMetadata,
universalFlatFieldMetadata,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatFieldMetadataMaps,
flatObjectMetadataMaps,
@@ -20,14 +20,16 @@ export const validateMorphOrRelationFlatFieldJoinColumName = ({
buildOptions,
}: {
buildOptions: WorkspaceMigrationBuilderOptions;
flatFieldMetadata: FlatFieldMetadata<MorphOrRelationFieldMetadataType>;
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: MetadataFlatEntityAndRelatedFlatEntityMapsForValidation<'fieldMetadata'>;
universalFlatFieldMetadata: UniversalFlatFieldMetadata<MorphOrRelationFieldMetadataType>;
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: MetadataUniversalFlatEntityAndRelatedFlatEntityMapsForValidation<'fieldMetadata'>;
}): FlatFieldMetadataValidationError[] => {
const errors: FlatFieldMetadataValidationError[] = [];
switch (flatFieldMetadata.settings.relationType) {
switch (universalFlatFieldMetadata.universalSettings.relationType) {
case RelationType.MANY_TO_ONE: {
if (!isDefined(flatFieldMetadata.settings.joinColumnName)) {
if (
!isDefined(universalFlatFieldMetadata.universalSettings.joinColumnName)
) {
errors.push({
code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
message:
@@ -38,12 +40,13 @@ export const validateMorphOrRelationFlatFieldJoinColumName = ({
return errors;
}
const flatObjectMetadata = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: flatFieldMetadata.objectMetadataId,
const universalFlatObjectMetadata = findFlatEntityByUniversalIdentifier({
universalIdentifier:
universalFlatFieldMetadata.objectMetadataUniversalIdentifier,
flatEntityMaps: flatObjectMetadataMaps,
});
if (!isDefined(flatObjectMetadata)) {
if (!isDefined(universalFlatObjectMetadata)) {
errors.push({
code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
message: 'Could not find relation field parent flat object',
@@ -55,16 +58,18 @@ export const validateMorphOrRelationFlatFieldJoinColumName = ({
errors.push(
...validateFlatFieldMetadataNameAvailability({
name: flatFieldMetadata.settings.joinColumnName,
flatFieldMetadataMaps,
flatObjectMetadata,
name: universalFlatFieldMetadata.universalSettings.joinColumnName,
universalFlatFieldMetadataMaps: flatFieldMetadataMaps,
universalFlatObjectMetadata,
buildOptions,
}),
);
break;
}
case RelationType.ONE_TO_MANY: {
if (isDefined(flatFieldMetadata.settings.joinColumnName)) {
if (
isDefined(universalFlatFieldMetadata.universalSettings.joinColumnName)
) {
errors.push({
code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
message:
@@ -75,7 +80,9 @@ export const validateMorphOrRelationFlatFieldJoinColumName = ({
break;
}
default: {
assertUnreachable(flatFieldMetadata.settings.relationType);
assertUnreachable(
universalFlatFieldMetadata.universalSettings.relationType,
);
}
}
@@ -1,27 +1,27 @@
import { msg } from '@lingui/core/macro';
import { isDefined, isValidUuid } from 'twenty-shared/utils';
import { isDefined } from 'twenty-shared/utils';
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { type MorphOrRelationFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/morph-or-relation-field-metadata-type.type';
import { type FlatEntityUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
import { type FlatFieldMetadataTypeValidationArgs } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-type-validator.type';
import { type FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
import { isMorphOrRelationUniversalFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
import { validateJunctionTargetSettings } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-junction-target-settings.util';
import { validateMorphOrRelationFlatFieldJoinColumName } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-morph-or-relation-flat-field-join-column-name.util';
import { validateMorphOrRelationFlatFieldOnDelete } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-morph-or-relation-flat-field-on-delete.util';
import { type UniversalFlatEntityUpdate } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-update.type';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
type ValidateMorphOrRelationFlatFieldMetadataUpdatesArgs = Omit<
FlatFieldMetadataTypeValidationArgs<MorphOrRelationFieldMetadataType>,
'updates'
> & {
update: FlatEntityUpdate<'fieldMetadata'>;
update: UniversalFlatEntityUpdate<'fieldMetadata'>;
};
export const validateMorphOrRelationFlatFieldMetadataUpdates = ({
flatEntityToValidate: flatFieldMetadataToValidate,
flatEntityToValidate: universalFlatFieldMetadata,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatFieldMetadataMaps,
flatObjectMetadataMaps,
@@ -31,8 +31,8 @@ export const validateMorphOrRelationFlatFieldMetadataUpdates = ({
}: ValidateMorphOrRelationFlatFieldMetadataUpdatesArgs): FlatFieldMetadataValidationError[] => {
const errors: FlatFieldMetadataValidationError[] = [];
const fromFlatFieldMetadata = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: flatFieldMetadataToValidate.id,
const fromFlatFieldMetadata = findFlatEntityByUniversalIdentifier({
universalIdentifier: universalFlatFieldMetadata.universalIdentifier,
flatEntityMaps: flatFieldMetadataMaps,
});
@@ -46,7 +46,7 @@ export const validateMorphOrRelationFlatFieldMetadataUpdates = ({
];
}
if (!isMorphOrRelationFlatFieldMetadata(fromFlatFieldMetadata)) {
if (!isMorphOrRelationUniversalFlatFieldMetadata(fromFlatFieldMetadata)) {
return [
{
code: FieldMetadataExceptionCode.FIELD_METADATA_NOT_FOUND,
@@ -56,10 +56,10 @@ export const validateMorphOrRelationFlatFieldMetadataUpdates = ({
];
}
const toSettings = update.settings as
| FlatFieldMetadata<MorphOrRelationFieldMetadataType>['settings']
const toSettings = update.universalSettings as
| UniversalFlatFieldMetadata<MorphOrRelationFieldMetadataType>['universalSettings']
| undefined;
const fromSettings = fromFlatFieldMetadata.settings;
const fromSettings = fromFlatFieldMetadata.universalSettings;
const isJoinColumnNameUpdated =
isDefined(toSettings?.joinColumnName) &&
@@ -70,7 +70,7 @@ export const validateMorphOrRelationFlatFieldMetadataUpdates = ({
errors.push(
...validateMorphOrRelationFlatFieldJoinColumName({
buildOptions,
flatFieldMetadata: flatFieldMetadataToValidate,
universalFlatFieldMetadata,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatFieldMetadataMaps,
flatObjectMetadataMaps,
@@ -81,7 +81,7 @@ export const validateMorphOrRelationFlatFieldMetadataUpdates = ({
errors.push(
...validateMorphOrRelationFlatFieldOnDelete({
flatFieldMetadata: flatFieldMetadataToValidate,
universalFlatFieldMetadata,
}),
);
@@ -89,7 +89,7 @@ export const validateMorphOrRelationFlatFieldMetadataUpdates = ({
};
export const validateMorphOrRelationFlatFieldMetadata = ({
flatEntityToValidate: flatFieldMetadataToValidate,
flatEntityToValidate: universalFlatFieldMetadataToValidate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatFieldMetadataMaps,
flatObjectMetadataMaps,
@@ -100,43 +100,45 @@ export const validateMorphOrRelationFlatFieldMetadata = ({
workspaceId,
additionalCacheDataMaps,
}: FlatFieldMetadataTypeValidationArgs<MorphOrRelationFieldMetadataType>): FlatFieldMetadataValidationError[] => {
const { relationTargetFieldMetadataId, relationTargetObjectMetadataId } =
flatFieldMetadataToValidate;
const {
relationTargetFieldMetadataUniversalIdentifier,
relationTargetObjectMetadataUniversalIdentifier,
} = universalFlatFieldMetadataToValidate;
const uuidsValidation = [
relationTargetObjectMetadataId,
relationTargetFieldMetadataId,
].flatMap<FlatFieldMetadataValidationError>((id) =>
isValidUuid(id)
const universalIdentifiersValidation = [
relationTargetObjectMetadataUniversalIdentifier,
relationTargetFieldMetadataUniversalIdentifier,
].flatMap<FlatFieldMetadataValidationError>((universalIdentifier) =>
isDefined(universalIdentifier)
? []
: {
code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
message: `Invalid uuid ${id}`,
userFriendlyMessage: msg`Invalid uuid ${id}`,
value: id,
message: `Invalid universal identifier ${universalIdentifier}`,
userFriendlyMessage: msg`Invalid universal identifier ${universalIdentifier}`,
value: universalIdentifier,
},
);
if (uuidsValidation.length > 0) {
return uuidsValidation;
if (universalIdentifiersValidation.length > 0) {
return universalIdentifiersValidation;
}
const errors: FlatFieldMetadataValidationError[] = [];
const targetFlatObjectMetadata = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: relationTargetObjectMetadataId,
const targetFlatObjectMetadata = findFlatEntityByUniversalIdentifier({
universalIdentifier: relationTargetObjectMetadataUniversalIdentifier,
flatEntityMaps: flatObjectMetadataMaps,
});
const targetFlatFieldMetadata =
(remainingFlatEntityMapsToValidate
? findFlatEntityByIdInFlatEntityMaps({
flatEntityId: relationTargetFieldMetadataId,
? findFlatEntityByUniversalIdentifier({
universalIdentifier: relationTargetFieldMetadataUniversalIdentifier,
flatEntityMaps: remainingFlatEntityMapsToValidate,
})
: undefined) ??
findFlatEntityByIdInFlatEntityMaps({
flatEntityId: relationTargetFieldMetadataId,
findFlatEntityByUniversalIdentifier({
universalIdentifier: relationTargetFieldMetadataUniversalIdentifier,
flatEntityMaps: flatFieldMetadataMaps,
});
@@ -159,7 +161,7 @@ export const validateMorphOrRelationFlatFieldMetadata = ({
userFriendlyMessage: msg`Relation field target metadata not found`,
});
} else {
if (!isMorphOrRelationFlatFieldMetadata(targetFlatFieldMetadata)) {
if (!isMorphOrRelationUniversalFlatFieldMetadata(targetFlatFieldMetadata)) {
errors.push({
code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
message:
@@ -168,8 +170,8 @@ export const validateMorphOrRelationFlatFieldMetadata = ({
});
} else {
if (
targetFlatFieldMetadata.objectMetadataId !==
flatFieldMetadataToValidate.relationTargetObjectMetadataId
targetFlatFieldMetadata.objectMetadataUniversalIdentifier !==
universalFlatFieldMetadataToValidate.relationTargetObjectMetadataUniversalIdentifier
) {
errors.push({
code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
@@ -180,8 +182,8 @@ export const validateMorphOrRelationFlatFieldMetadata = ({
}
if (
targetFlatFieldMetadata.relationTargetObjectMetadataId !==
flatFieldMetadataToValidate.objectMetadataId
targetFlatFieldMetadata.relationTargetObjectMetadataUniversalIdentifier !==
universalFlatFieldMetadataToValidate.objectMetadataUniversalIdentifier
) {
errors.push({
code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
@@ -192,8 +194,8 @@ export const validateMorphOrRelationFlatFieldMetadata = ({
}
if (
targetFlatFieldMetadata.relationTargetFieldMetadataId !==
flatFieldMetadataToValidate.id
targetFlatFieldMetadata.relationTargetFieldMetadataUniversalIdentifier !==
universalFlatFieldMetadataToValidate.universalIdentifier
) {
errors.push({
code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
@@ -209,7 +211,7 @@ export const validateMorphOrRelationFlatFieldMetadata = ({
if (isDefined(update)) {
errors.push(
...validateMorphOrRelationFlatFieldMetadataUpdates({
flatEntityToValidate: flatFieldMetadataToValidate,
flatEntityToValidate: universalFlatFieldMetadataToValidate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatFieldMetadataMaps,
flatObjectMetadataMaps,
@@ -225,21 +227,21 @@ export const validateMorphOrRelationFlatFieldMetadata = ({
errors.push(
...validateMorphOrRelationFlatFieldJoinColumName({
buildOptions,
flatFieldMetadata: flatFieldMetadataToValidate,
universalFlatFieldMetadata: universalFlatFieldMetadataToValidate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: {
flatFieldMetadataMaps,
flatObjectMetadataMaps,
},
}),
...validateMorphOrRelationFlatFieldOnDelete({
flatFieldMetadata: flatFieldMetadataToValidate,
universalFlatFieldMetadata: universalFlatFieldMetadataToValidate,
}),
);
}
errors.push(
...validateJunctionTargetSettings({
flatFieldMetadata: flatFieldMetadataToValidate,
universalFlatFieldMetadata: universalFlatFieldMetadataToValidate,
flatFieldMetadataMaps,
}),
);
@@ -5,18 +5,19 @@ import { isDefined } from 'twenty-shared/utils';
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { type MorphOrRelationFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/morph-or-relation-field-metadata-type.type';
import { type FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
export const validateMorphOrRelationFlatFieldOnDelete = ({
flatFieldMetadata,
universalFlatFieldMetadata,
}: {
flatFieldMetadata: FlatFieldMetadata<MorphOrRelationFieldMetadataType>;
universalFlatFieldMetadata: UniversalFlatFieldMetadata<MorphOrRelationFieldMetadataType>;
}): FlatFieldMetadataValidationError[] => {
const errors: FlatFieldMetadataValidationError[] = [];
if (
isDefined(flatFieldMetadata.settings.onDelete) &&
flatFieldMetadata.settings.relationType !== RelationType.MANY_TO_ONE
isDefined(universalFlatFieldMetadata.universalSettings.onDelete) &&
universalFlatFieldMetadata.universalSettings.relationType !==
RelationType.MANY_TO_ONE
) {
errors.push({
code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
@@ -21,12 +21,12 @@ type RelationCreationPayloadAndObjectMetadata = {
type ValidateMorphRelationCreationPayloadUtilArgs = {
morphRelationCreationPayload: RelationCreationPayload[];
existingFlatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
objectMetadataId: string;
objectMetadataUniversalIdentifier: string;
};
export const validateMorphRelationCreationPayload = async ({
existingFlatObjectMetadataMaps,
morphRelationCreationPayload,
objectMetadataId,
objectMetadataUniversalIdentifier,
}: ValidateMorphRelationCreationPayloadUtilArgs): Promise<
FieldInputTranspilationResult<RelationCreationPayloadAndObjectMetadata[]>
> => {
@@ -72,7 +72,9 @@ export const validateMorphRelationCreationPayload = async ({
...new Set(allRelatedObjectMetadataIds),
];
if (allRelatedObjectMetadataIdsSet.includes(objectMetadataId)) {
if (
allRelatedObjectMetadataIdsSet.includes(objectMetadataUniversalIdentifier)
) {
return {
status: 'fail',
errors: [
@@ -3,7 +3,7 @@ import { FieldMetadataType } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
import { type FlatFieldMetadataTypeValidationArgs } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-type-validator.type';
import { type FlatFieldMetadataValidationError } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-validation-error.type';
import { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
@@ -13,32 +13,33 @@ export const validateMorphRelationFlatFieldMetadata = (
args: FlatFieldMetadataTypeValidationArgs<FieldMetadataType.MORPH_RELATION>,
): FlatFieldMetadataValidationError[] => {
const {
flatEntityToValidate: flatFieldMetadataToValidate,
flatEntityToValidate: universalFlatFieldMetadataToValidate,
optimisticFlatEntityMapsAndRelatedFlatEntityMaps: { flatFieldMetadataMaps },
remainingFlatEntityMapsToValidate,
} = args;
const { relationTargetFieldMetadataId } = flatFieldMetadataToValidate;
const { relationTargetFieldMetadataUniversalIdentifier } =
universalFlatFieldMetadataToValidate;
const errors: FlatFieldMetadataValidationError[] = [];
errors.push(...validateMorphOrRelationFlatFieldMetadata(args));
const targetFlatFieldMetadata =
const targetUniversalFlatFieldMetadata =
(remainingFlatEntityMapsToValidate
? findFlatEntityByIdInFlatEntityMaps({
flatEntityId: relationTargetFieldMetadataId,
? findFlatEntityByUniversalIdentifier({
universalIdentifier: relationTargetFieldMetadataUniversalIdentifier,
flatEntityMaps: remainingFlatEntityMapsToValidate,
})
: undefined) ??
findFlatEntityByIdInFlatEntityMaps({
flatEntityId: relationTargetFieldMetadataId,
findFlatEntityByUniversalIdentifier({
universalIdentifier: relationTargetFieldMetadataUniversalIdentifier,
flatEntityMaps: flatFieldMetadataMaps,
});
if (
isDefined(targetFlatFieldMetadata) &&
isDefined(targetUniversalFlatFieldMetadata) &&
!isFlatFieldMetadataOfType(
targetFlatFieldMetadata,
targetUniversalFlatFieldMetadata,
FieldMetadataType.RELATION,
)
) {
@@ -49,11 +50,15 @@ export const validateMorphRelationFlatFieldMetadata = (
});
}
const sourceObjectMetadataId = flatFieldMetadataToValidate.objectMetadataId;
const targetObjectMetadataId =
flatFieldMetadataToValidate.relationTargetObjectMetadataId;
const sourceObjectMetadataUniversalIdentifier =
universalFlatFieldMetadataToValidate.objectMetadataUniversalIdentifier;
const targetObjectMetadataUniversalIdentifier =
universalFlatFieldMetadataToValidate.relationTargetObjectMetadataUniversalIdentifier;
if (sourceObjectMetadataId === targetObjectMetadataId) {
if (
sourceObjectMetadataUniversalIdentifier ===
targetObjectMetadataUniversalIdentifier
) {
errors.push({
code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
message: 'Source object cannot be the target object',
@@ -61,7 +66,7 @@ export const validateMorphRelationFlatFieldMetadata = (
});
}
if (!isDefined(flatFieldMetadataToValidate.morphId)) {
if (!isDefined(universalFlatFieldMetadataToValidate.morphId)) {
errors.push({
code: FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
message: 'Morph relation field must have a morph id',
@@ -1,4 +1,4 @@
import { type FlatFrontComponent } from 'src/engine/metadata-modules/flat-front-component/types/flat-front-component.type';
import { type MetadataEntityPropertyName } from 'src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant';
export const FLAT_FRONT_COMPONENT_EDITABLE_PROPERTIES = [
'name',
@@ -7,4 +7,4 @@ export const FLAT_FRONT_COMPONENT_EDITABLE_PROPERTIES = [
'sourceComponentPath',
'builtComponentPath',
'componentName',
] as const satisfies (keyof FlatFrontComponent)[];
] as const satisfies MetadataEntityPropertyName<'frontComponent'>[];
@@ -19,6 +19,7 @@ export const getFlatIndexMetadataMock = (
const createdAt = faker.date.anytime().toISOString();
return {
universalFlatIndexFieldMetadatas: [],
flatIndexFieldMetadatas: [],
createdAt,
id: faker.string.uuid(),
@@ -6,6 +6,7 @@ import { Repository } from 'typeorm';
import { WorkspaceCacheProvider } from 'src/engine/workspace-cache/interfaces/workspace-cache-provider.service';
import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity';
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
import { FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
@@ -28,6 +29,8 @@ export class WorkspaceFlatIndexMapCacheService extends WorkspaceCacheProvider<
private readonly applicationRepository: Repository<ApplicationEntity>,
@InjectRepository(ObjectMetadataEntity)
private readonly objectMetadataRepository: Repository<ObjectMetadataEntity>,
@InjectRepository(FieldMetadataEntity)
private readonly fieldMetadataRepository: Repository<FieldMetadataEntity>,
) {
super();
}
@@ -35,34 +38,42 @@ export class WorkspaceFlatIndexMapCacheService extends WorkspaceCacheProvider<
async computeForCache(
workspaceId: string,
): Promise<FlatEntityMaps<FlatIndexMetadata>> {
const [indexes, applications, objectMetadatas] = await Promise.all([
this.indexMetadataRepository.find({
where: {
workspaceId,
},
withDeleted: true,
relationLoadStrategy: 'join',
select: {
// Note: We need all IndexFieldMetadataEntity in order to build a FlatIndex
indexFieldMetadatas: true,
},
relations: ['indexFieldMetadatas'],
}),
this.applicationRepository.find({
where: { workspaceId },
select: ['id', 'universalIdentifier'],
}),
this.objectMetadataRepository.find({
where: { workspaceId },
select: ['id', 'universalIdentifier'],
withDeleted: true,
}),
]);
const [indexes, applications, objectMetadatas, fieldMetadatas] =
await Promise.all([
this.indexMetadataRepository.find({
where: {
workspaceId,
},
withDeleted: true,
relationLoadStrategy: 'join',
select: {
// Note: We need all IndexFieldMetadataEntity in order to build a FlatIndex
indexFieldMetadatas: true,
},
relations: ['indexFieldMetadatas'],
}),
this.applicationRepository.find({
where: { workspaceId },
select: ['id', 'universalIdentifier'],
}),
this.objectMetadataRepository.find({
where: { workspaceId },
select: ['id', 'universalIdentifier'],
withDeleted: true,
}),
this.fieldMetadataRepository.find({
where: { workspaceId },
select: ['id', 'universalIdentifier'],
withDeleted: true,
}),
]);
const applicationIdToUniversalIdentifierMap =
createIdToUniversalIdentifierMap(applications);
const objectMetadataIdToUniversalIdentifierMap =
createIdToUniversalIdentifierMap(objectMetadatas);
const fieldMetadataIdToUniversalIdentifierMap =
createIdToUniversalIdentifierMap(fieldMetadatas);
const flatIndexMaps = createEmptyFlatEntityMaps();
@@ -71,6 +82,7 @@ export class WorkspaceFlatIndexMapCacheService extends WorkspaceCacheProvider<
entity: indexEntity,
applicationIdToUniversalIdentifierMap,
objectMetadataIdToUniversalIdentifierMap,
fieldMetadataIdToUniversalIdentifierMap,
});
addFlatEntityToFlatEntityMapsThroughMutationOrThrow({
@@ -1,10 +1,10 @@
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';
import { type IndexFieldMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-field-metadata.entity';
import { type IndexMetadataEntity } from 'src/engine/metadata-modules/index-metadata/index-metadata.entity';
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
export type FlatIndexFieldMetadata = FlatEntityFrom<IndexFieldMetadataEntity>;
export type FlatIndexMetadata = FlatEntityFrom<IndexMetadataEntity> & {
universalIdentifier: string;
flatIndexFieldMetadatas: FlatIndexFieldMetadata[];
};
} & Pick<UniversalFlatIndexMetadata, 'universalFlatIndexFieldMetadatas'>;
@@ -12,7 +12,10 @@ export const fromIndexMetadataEntityToFlatIndexMetadata = ({
entity: indexMetadataEntity,
applicationIdToUniversalIdentifierMap,
objectMetadataIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'index'>): FlatIndexMetadata => {
fieldMetadataIdToUniversalIdentifierMap,
}: FromEntityToFlatEntityArgs<'index'> & {
fieldMetadataIdToUniversalIdentifierMap: Map<string, string>;
}): FlatIndexMetadata => {
const applicationUniversalIdentifier =
applicationIdToUniversalIdentifierMap.get(
indexMetadataEntity.applicationId,
@@ -58,6 +61,29 @@ export const fromIndexMetadataEntityToFlatIndexMetadata = ({
updatedAt: indexFieldMetadata.updatedAt.toISOString(),
}),
),
universalFlatIndexFieldMetadatas:
indexMetadataEntity.indexFieldMetadatas.map((indexFieldMetadata) => {
const fieldMetadataUniversalIdentifier =
fieldMetadataIdToUniversalIdentifierMap.get(
indexFieldMetadata.fieldMetadataId,
);
if (!isDefined(fieldMetadataUniversalIdentifier)) {
throw new FlatEntityMapsException(
`FieldMetadata with id ${indexFieldMetadata.fieldMetadataId} not found for index field metadata ${indexFieldMetadata.id}`,
FlatEntityMapsExceptionCode.RELATION_UNIVERSAL_IDENTIFIER_NOT_FOUND,
);
}
return {
order: indexFieldMetadata.order,
createdAt: indexFieldMetadata.createdAt.toISOString(),
updatedAt: indexFieldMetadata.updatedAt.toISOString(),
indexMetadataUniversalIdentifier:
indexMetadataEntity.universalIdentifier,
fieldMetadataUniversalIdentifier,
};
}),
applicationUniversalIdentifier,
objectMetadataUniversalIdentifier,
};
@@ -1,7 +1,7 @@
import { type FlatNavigationMenuItem } from 'src/engine/metadata-modules/flat-navigation-menu-item/types/flat-navigation-menu-item.type';
import { type MetadataEntityPropertyName } from 'src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant';
export const FLAT_NAVIGATION_MENU_ITEM_EDITABLE_PROPERTIES = [
'position',
'folderId',
'name',
] as const satisfies (keyof FlatNavigationMenuItem)[];
] as const satisfies MetadataEntityPropertyName<'navigationMenuItem'>[];
@@ -1,4 +1,4 @@
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type MetadataEntityPropertyName } from 'src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant';
export const FLAT_OBJECT_METADATA_EDITABLE_PROPERTIES = {
custom: [
@@ -15,5 +15,5 @@ export const FLAT_OBJECT_METADATA_EDITABLE_PROPERTIES = {
standard: ['description', 'icon', 'isActive', 'labelPlural', 'labelSingular'],
} as const satisfies Record<
'standard' | 'custom',
(keyof FlatObjectMetadata)[]
MetadataEntityPropertyName<'objectMetadata'>[]
>;
@@ -1,7 +1,7 @@
import { FieldMetadataType, RelationType } from 'twenty-shared/types';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { getMorphNameFromMorphFieldMetadataName } from 'src/engine/metadata-modules/flat-object-metadata/utils/get-morph-name-from-morph-field-metadata-name.util';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
describe('getMorphNameFromMorphFieldMetadataName', () => {
const createMorphRelationFlatFieldMetadataMock = (
@@ -12,8 +12,8 @@ describe('getMorphNameFromMorphFieldMetadataName', () => {
name,
type: FieldMetadataType.MORPH_RELATION,
label: name,
settings: { relationType },
}) as unknown as FlatFieldMetadata<FieldMetadataType.MORPH_RELATION>;
universalSettings: { relationType },
}) as unknown as UniversalFlatFieldMetadata<FieldMetadataType.MORPH_RELATION>;
it('should extract base morph field name for MANY_TO_ONE (removes singular suffix)', () => {
const morphRelationFlatFieldMetadata =
@@ -1,6 +1,6 @@
import { computeMetadataNameFromLabel } from 'twenty-shared/metadata';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
export const areFlatObjectMetadataNamesSyncedWithLabels = ({
flatObjectdMetadata,
@@ -8,7 +8,7 @@ export const areFlatObjectMetadataNamesSyncedWithLabels = ({
}: {
isSystemBuild: boolean;
flatObjectdMetadata: Pick<
FlatObjectMetadata,
UniversalFlatObjectMetadata,
'namePlural' | 'nameSingular' | 'labelPlural' | 'labelSingular'
>;
}) => {
@@ -8,33 +8,31 @@ import { type FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interf
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type CreateObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/create-object.input';
import { buildDefaultFlatFieldMetadatasForCustomObject } from 'src/engine/metadata-modules/object-metadata/utils/build-default-flat-field-metadatas-for-custom-object.util';
import { buildDefaultIndexesForCustomObject } from 'src/engine/metadata-modules/object-metadata/utils/build-default-index-for-custom-object.util';
import { buildDefaultRelationFlatFieldMetadatasForCustomObject } from 'src/engine/metadata-modules/object-metadata/utils/build-default-relation-flat-field-metadatas-for-custom-object.util';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
type FromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCreateArgs =
{
createObjectInput: CreateObjectInput;
workspaceId: string;
flatApplication: FlatApplication;
existingFeatureFlagsMap: FeatureFlagMap;
} & Pick<AllFlatEntityMaps, 'flatObjectMetadataMaps'>;
export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCreate =
({
createObjectInput: rawCreateObjectInput,
workspaceId,
flatApplication,
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
existingFeatureFlagsMap,
}: FromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCreateArgs): {
flatObjectMetadataToCreate: FlatObjectMetadata;
relationTargetFlatFieldMetadataToCreate: FlatFieldMetadata[];
flatFieldMetadataToCreateOnObject: FlatFieldMetadata[];
flatIndexMetadataToCreate: FlatIndexMetadata[];
flatObjectMetadataToCreate: UniversalFlatObjectMetadata & { id: string };
relationTargetFlatFieldMetadataToCreate: UniversalFlatFieldMetadata[];
flatFieldMetadataToCreateOnObject: UniversalFlatFieldMetadata[];
flatIndexMetadataToCreate: UniversalFlatIndexMetadata[];
} => {
const createObjectInput =
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
@@ -55,35 +53,29 @@ export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCre
const defaultFlatFieldForCustomObjectMaps =
buildDefaultFlatFieldMetadatasForCustomObject({
flatObjectMetadata: {
id: objectMetadataId,
applicationId: flatApplication.id,
applicationUniversalIdentifier: flatApplication.universalIdentifier,
universalIdentifier,
},
workspaceId,
skipNameField: createObjectInput.skipNameField,
});
const createdAt = new Date().toISOString();
// Use nameField.id if it exists, otherwise use idField.id (for junction tables without name)
const nameField = defaultFlatFieldForCustomObjectMaps.fields.nameField;
const labelIdentifierFieldMetadataId =
nameField?.id ?? defaultFlatFieldForCustomObjectMaps.fields.idField.id;
const labelIdentifierFieldMetadataUniversalIdentifier =
nameField?.universalIdentifier ??
defaultFlatFieldForCustomObjectMaps.fields.idField.universalIdentifier;
const flatObjectMetadataToCreate: FlatObjectMetadata = {
fieldIds: [],
viewIds: [],
indexMetadataIds: [],
const universalFlatObjectMetadataToCreate: UniversalFlatObjectMetadata & {
id: string;
} = {
id: objectMetadataId,
universalIdentifier,
createdAt,
updatedAt: createdAt,
duplicateCriteria: null,
description: createObjectInput.description ?? null,
icon: createObjectInput.icon ?? null,
id: objectMetadataId,
imageIdentifierFieldMetadataId: null,
isActive: true,
isAuditLogged: true,
isCustom: true,
@@ -92,17 +84,13 @@ export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCre
isSearchable: true,
isUIReadOnly: false,
isSystem: false,
labelIdentifierFieldMetadataId,
labelPlural: capitalize(createObjectInput.labelPlural),
labelSingular: capitalize(createObjectInput.labelSingular),
namePlural: createObjectInput.namePlural,
nameSingular: createObjectInput.nameSingular,
shortcut: createObjectInput.shortcut ?? null,
standardOverrides: null,
applicationId: flatApplication.id,
universalIdentifier,
targetTableName: 'DEPRECATED',
workspaceId,
applicationUniversalIdentifier: flatApplication.universalIdentifier,
fieldUniversalIdentifiers: [],
viewUniversalIdentifiers: [],
@@ -116,13 +104,12 @@ export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCre
standardTargetFlatFieldMetadatas,
} = buildDefaultRelationFlatFieldMetadatasForCustomObject({
existingFlatObjectMetadataMaps,
sourceFlatObjectMetadata: flatObjectMetadataToCreate,
workspaceId,
sourceFlatObjectMetadata: universalFlatObjectMetadataToCreate,
flatApplication,
existingFeatureFlagsMap,
});
const objectFlatFieldMetadatas: FlatFieldMetadata[] = [
const objectFlatFieldMetadatas: UniversalFlatFieldMetadata[] = [
...Object.values(defaultFlatFieldForCustomObjectMaps.fields),
...standardSourceFlatFieldMetadatas,
];
@@ -130,12 +117,11 @@ export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCre
const defaultIndexesForCustomObject = buildDefaultIndexesForCustomObject({
objectFlatFieldMetadatas,
defaultFlatFieldForCustomObjectMaps,
flatObjectMetadata: flatObjectMetadataToCreate,
workspaceId,
flatObjectMetadata: universalFlatObjectMetadataToCreate,
});
return {
flatObjectMetadataToCreate,
flatObjectMetadataToCreate: universalFlatObjectMetadataToCreate,
flatIndexMetadataToCreate: Object.values(
defaultIndexesForCustomObject.indexes,
),
@@ -6,16 +6,16 @@ import {
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { findRelationFlatFieldMetadataTargetFlatFieldMetadataOrThrow } from 'src/engine/metadata-modules/flat-field-metadata/utils/find-relation-flat-field-metadatas-target-flat-field-metadata-or-throw.util';
import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type DeleteOneObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/delete-object.input';
import {
ObjectMetadataException,
ObjectMetadataExceptionCode,
} from 'src/engine/metadata-modules/object-metadata/object-metadata.exception';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
type FromDeleteObjectInputToFlatFieldMetadatasToDeleteArgs = {
deleteObjectInput: DeleteOneObjectInput;
@@ -30,8 +30,8 @@ export const fromDeleteObjectInputToFlatFieldMetadatasToDelete = ({
flatIndexMaps,
// This should return an AllFlatEntityMaps
}: FromDeleteObjectInputToFlatFieldMetadatasToDeleteArgs): {
flatFieldMetadatasToDelete: FlatFieldMetadata[];
flatObjectMetadataToDelete: FlatObjectMetadata;
flatFieldMetadatasToDelete: UniversalFlatFieldMetadata[];
flatObjectMetadataToDelete: UniversalFlatObjectMetadata;
flatIndexToDelete: FlatIndexMetadata[];
} => {
const { id: objectMetadataToDeleteId } =
@@ -4,9 +4,9 @@ import {
} from 'twenty-shared/utils';
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { FLAT_OBJECT_METADATA_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/flat-object-metadata/constants/flat-object-metadata-editable-properties.constant';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import {
type FlatObjectMetadataUpdateSideEffects,
handleFlatObjectMetadataUpdateSideEffect,
@@ -18,6 +18,7 @@ import {
ObjectMetadataExceptionCode,
} from 'src/engine/metadata-modules/object-metadata/object-metadata.exception';
import { belongsToTwentyStandardApp } from 'src/engine/metadata-modules/utils/belongs-to-twenty-standard-app.util';
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
import { mergeUpdateInExistingRecord } from 'src/utils/merge-update-in-existing-record.util';
type FromUpdateObjectInputToFlatObjectMetadataArgs = {
@@ -40,7 +41,7 @@ export const fromUpdateObjectInputToFlatObjectMetadataAndRelatedFlatEntities =
flatViewFieldMaps,
flatViewMaps,
}: FromUpdateObjectInputToFlatObjectMetadataArgs): FlatObjectMetadataUpdateSideEffects & {
flatObjectMetadataToUpdate: FlatObjectMetadata;
flatObjectMetadataToUpdate: UniversalFlatObjectMetadata;
} => {
const { id: objectMetadataIdToUpdate } =
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
@@ -81,6 +82,19 @@ export const fromUpdateObjectInputToFlatObjectMetadataAndRelatedFlatEntities =
standardOverrides,
};
if (
isDefined(updatedEditableObjectProperties.labelIdentifierFieldMetadataId)
) {
const flatFieldMetadata = findFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityMaps: flatFieldMetadataMaps,
flatEntityId:
updatedEditableObjectProperties.labelIdentifierFieldMetadataId,
});
toFlatObjectMetadata.labelIdentifierFieldMetadataUniversalIdentifier =
flatFieldMetadata?.universalIdentifier;
}
const {
flatIndexMetadatasToUpdate,
flatViewFieldsToCreate,
@@ -1,8 +1,8 @@
import { type FieldMetadataType, RelationType } from 'twenty-shared/types';
import { capitalize } from 'twenty-shared/utils';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { searchAndReplaceLast } from 'src/engine/metadata-modules/flat-object-metadata/utils/search-and-replace-last.util';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
export const getMorphNameFromMorphFieldMetadataName = ({
morphRelationFlatFieldMetadata,
@@ -10,14 +10,14 @@ export const getMorphNameFromMorphFieldMetadataName = ({
namePlural,
}: {
morphRelationFlatFieldMetadata: Pick<
FlatFieldMetadata<FieldMetadataType.MORPH_RELATION>,
'name' | 'settings'
UniversalFlatFieldMetadata<FieldMetadataType.MORPH_RELATION>,
'name' | 'universalSettings'
>;
nameSingular: string;
namePlural: string;
}): string => {
const isManyToOneRelationType =
morphRelationFlatFieldMetadata.settings.relationType ===
morphRelationFlatFieldMetadata.universalSettings.relationType ===
RelationType.MANY_TO_ONE;
return searchAndReplaceLast({
@@ -3,20 +3,21 @@ import { isDefined } from 'twenty-shared/utils';
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { recomputeIndexAfterFlatObjectMetadataSingularNameUpdate } from 'src/engine/metadata-modules/flat-object-metadata/utils/recompute-index-after-flat-object-metadata-singular-name-update.util';
import { recomputeSearchVectorFieldAfterLabelIdentifierUpdate } from 'src/engine/metadata-modules/flat-object-metadata/utils/recompute-search-vector-field-after-label-identifier-update.util';
import { recomputeViewFieldIdentifierAfterFlatObjectIdentifierUpdate } from 'src/engine/metadata-modules/flat-object-metadata/utils/recompute-view-field-identifier-after-flat-object-identifier-update.util';
import { renameRelatedMorphFieldOnObjectNamesUpdate } from 'src/engine/metadata-modules/flat-object-metadata/utils/rename-related-morph-field-on-object-names-update.util';
import { type FlatViewField } from 'src/engine/metadata-modules/flat-view-field/types/flat-view-field.type';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
import { type UniversalFlatViewField } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-view-field.type';
export type FlatObjectMetadataUpdateSideEffects = {
otherObjectFlatFieldMetadatasToUpdate: FlatFieldMetadata[];
sameObjectFlatFieldMetadatasToUpdate: FlatFieldMetadata[];
flatViewFieldsToUpdate: FlatViewField[];
flatViewFieldsToCreate: FlatViewField[];
flatIndexMetadatasToUpdate: FlatIndexMetadata[];
otherObjectFlatFieldMetadatasToUpdate: UniversalFlatFieldMetadata[];
sameObjectFlatFieldMetadatasToUpdate: UniversalFlatFieldMetadata[];
flatViewFieldsToUpdate: UniversalFlatViewField[];
flatViewFieldsToCreate: UniversalFlatViewField[];
flatIndexMetadatasToUpdate: UniversalFlatIndexMetadata[];
};
type HandleFlatObjectMetadataUpdateSideEffectArgs = FromTo<
@@ -88,16 +89,18 @@ export const handleFlatObjectMetadataUpdateSideEffect = ({
if (
toFlatObjectMetadata.isSearchable &&
isDefined(toFlatObjectMetadata.labelIdentifierFieldMetadataId) &&
fromFlatObjectMetadata.labelIdentifierFieldMetadataId !==
toFlatObjectMetadata.labelIdentifierFieldMetadataId
isDefined(
toFlatObjectMetadata.labelIdentifierFieldMetadataUniversalIdentifier,
) &&
fromFlatObjectMetadata.labelIdentifierFieldMetadataUniversalIdentifier !==
toFlatObjectMetadata.labelIdentifierFieldMetadataUniversalIdentifier
) {
const updatedSearchVectorField =
recomputeSearchVectorFieldAfterLabelIdentifierUpdate({
existingFlatObjectMetadata: fromFlatObjectMetadata,
flatFieldMetadataMaps,
updatedLabelIdentifierFieldMetadataId:
toFlatObjectMetadata.labelIdentifierFieldMetadataId,
labelIdentifierFieldMetadataUniversalIdentifier:
toFlatObjectMetadata.labelIdentifierFieldMetadataUniversalIdentifier,
});
if (isDefined(updatedSearchVectorField)) {
@@ -1,8 +1,8 @@
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-universal-identifier-in-universal-flat-entity-maps-or-throw.util';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { generateFlatIndexMetadataWithNameOrThrow } from 'src/engine/metadata-modules/index-metadata/utils/generate-flat-index.util';
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
type RecomputeIndexAfterFlatObjectMetadataSingularNameUpdateArgs = {
existingFlatObjectMetadata: FlatObjectMetadata;
@@ -13,10 +13,11 @@ export const recomputeIndexAfterFlatObjectMetadataSingularNameUpdate = ({
flatIndexMaps,
updatedSingularName,
flatFieldMetadataMaps,
}: RecomputeIndexAfterFlatObjectMetadataSingularNameUpdateArgs): FlatIndexMetadata[] => {
}: RecomputeIndexAfterFlatObjectMetadataSingularNameUpdateArgs): UniversalFlatIndexMetadata[] => {
const allRelatedFlatIndexMetadata =
findManyFlatEntityByIdInFlatEntityMapsOrThrow({
flatEntityIds: existingFlatObjectMetadata.indexMetadataIds,
findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrow({
universalIdentifiers:
existingFlatObjectMetadata.indexMetadataUniversalIdentifiers,
flatEntityMaps: flatIndexMaps,
});
@@ -30,18 +31,21 @@ export const recomputeIndexAfterFlatObjectMetadataSingularNameUpdate = ({
};
const objectFlatFieldMetadatas =
findManyFlatEntityByIdInFlatEntityMapsOrThrow({
findManyFlatEntityByUniversalIdentifierInUniversalFlatEntityMapsOrThrow({
flatEntityMaps: flatFieldMetadataMaps,
flatEntityIds: optimisticFlatObjectMetadata.fieldIds,
universalIdentifiers:
optimisticFlatObjectMetadata.fieldUniversalIdentifiers,
});
return allRelatedFlatIndexMetadata.map<FlatIndexMetadata>((flatIndex) => {
const newIndex = generateFlatIndexMetadataWithNameOrThrow({
flatIndex,
flatObjectMetadata: optimisticFlatObjectMetadata,
objectFlatFieldMetadatas,
});
return allRelatedFlatIndexMetadata.map<UniversalFlatIndexMetadata>(
(flatIndex) => {
const newIndex = generateFlatIndexMetadataWithNameOrThrow({
flatIndex,
flatObjectMetadata: optimisticFlatObjectMetadata,
objectFlatFieldMetadatas,
});
return newIndex;
});
return newIndex;
},
);
};
@@ -2,7 +2,7 @@ import { type FieldMetadataType } from 'twenty-shared/types';
import { findOrThrow, isDefined } from 'twenty-shared/utils';
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
@@ -16,13 +16,13 @@ import { type SearchableFieldType } from 'src/engine/workspace-manager/utils/is-
type RecomputeSearchVectorFieldAfterLabelIdentifierUpdateArgs = {
existingFlatObjectMetadata: FlatObjectMetadata;
updatedLabelIdentifierFieldMetadataId: string;
labelIdentifierFieldMetadataUniversalIdentifier: string;
} & Pick<AllFlatEntityMaps, 'flatFieldMetadataMaps'>;
export const recomputeSearchVectorFieldAfterLabelIdentifierUpdate = ({
existingFlatObjectMetadata,
flatFieldMetadataMaps,
updatedLabelIdentifierFieldMetadataId,
labelIdentifierFieldMetadataUniversalIdentifier,
}: RecomputeSearchVectorFieldAfterLabelIdentifierUpdateArgs):
| FlatFieldMetadata<FieldMetadataType.TS_VECTOR>
| undefined => {
@@ -37,9 +37,9 @@ export const recomputeSearchVectorFieldAfterLabelIdentifierUpdate = ({
(field) => field.name === SEARCH_VECTOR_FIELD.name,
) as FlatFieldMetadata<FieldMetadataType.TS_VECTOR>;
const newLabelIdentifierField = findFlatEntityByIdInFlatEntityMaps({
const newLabelIdentifierField = findFlatEntityByUniversalIdentifier({
flatEntityMaps: flatFieldMetadataMaps,
flatEntityId: updatedLabelIdentifierFieldMetadataId,
universalIdentifier: labelIdentifierFieldMetadataUniversalIdentifier,
});
if (!isDefined(newLabelIdentifierField)) {
@@ -59,8 +59,8 @@ export const recomputeSearchVectorFieldAfterLabelIdentifierUpdate = ({
return {
...searchVectorField,
settings: {
...searchVectorField.settings,
universalSettings: {
...searchVectorField.universalSettings,
asExpression: newAsExpression,
generatedType: 'STORED',
},
@@ -9,27 +9,27 @@ import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-m
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { findManyFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { findFieldRelatedIndexes } from 'src/engine/metadata-modules/flat-field-metadata/utils/find-field-related-index.util';
import { recomputeIndexOnFlatFieldMetadataNameUpdate } from 'src/engine/metadata-modules/flat-field-metadata/utils/recompute-index-on-flat-field-metadata-name-update.util';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { getFlatObjectMetadataTargetMorphRelationFlatFieldMetadatasOrThrow } from 'src/engine/metadata-modules/flat-object-metadata/utils/get-flat-object-metadata-many-to-one-target-morph-relation-flat-field-metadatas-or-throw.util';
import { getMorphNameFromMorphFieldMetadataName } from 'src/engine/metadata-modules/flat-object-metadata/utils/get-morph-name-from-morph-field-metadata-name.util';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
import { type UniversalFlatIndexMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-index-metadata.type';
type UpdateMorphFlatFieldNameArgs = FromTo<
FlatObjectMetadata,
'relationTargetFlatObjectMetadata'
> & {
fromMorphFlatFieldMetadata: FlatFieldMetadata<FieldMetadataType.MORPH_RELATION>;
fromMorphFlatFieldMetadata: UniversalFlatFieldMetadata<FieldMetadataType.MORPH_RELATION>;
};
const updateMorphFlatFieldName = ({
fromMorphFlatFieldMetadata,
fromRelationTargetFlatObjectMetadata,
toRelationTargetFlatObjectMetadata,
}: UpdateMorphFlatFieldNameArgs): FlatFieldMetadata<FieldMetadataType.MORPH_RELATION> => {
}: UpdateMorphFlatFieldNameArgs): UniversalFlatFieldMetadata<FieldMetadataType.MORPH_RELATION> => {
const isManyToOneRelationType =
fromMorphFlatFieldMetadata.settings.relationType ===
fromMorphFlatFieldMetadata.universalSettings.relationType ===
RelationType.MANY_TO_ONE;
const initialMorphRelationFieldName = getMorphNameFromMorphFieldMetadataName({
morphRelationFlatFieldMetadata: fromMorphFlatFieldMetadata,
@@ -39,7 +39,7 @@ const updateMorphFlatFieldName = ({
const newMorphFieldName = computeMorphRelationFieldName({
fieldName: initialMorphRelationFieldName,
relationType: fromMorphFlatFieldMetadata.settings.relationType,
relationType: fromMorphFlatFieldMetadata.universalSettings.relationType,
targetObjectMetadataNameSingular:
toRelationTargetFlatObjectMetadata.nameSingular,
targetObjectMetadataNamePlural:
@@ -55,8 +55,8 @@ const updateMorphFlatFieldName = ({
return {
...fromMorphFlatFieldMetadata,
name: newMorphFieldName,
settings: {
...fromMorphFlatFieldMetadata.settings,
universalSettings: {
...fromMorphFlatFieldMetadata.universalSettings,
joinColumnName: newJoinColumnName,
},
};
@@ -72,8 +72,8 @@ type RenameRelatedMorphFieldOnObjectNamesUpdateArgs = FromTo<
>;
type RenameRelatedMorphFieldOnObjectNamesUpdateReturnType = {
morphFlatFieldMetadatasToUpdate: FlatFieldMetadata<FieldMetadataType.MORPH_RELATION>[];
morphRelatedFlatIndexesToUpdate: FlatIndexMetadata[];
morphFlatFieldMetadatasToUpdate: UniversalFlatFieldMetadata<FieldMetadataType.MORPH_RELATION>[];
morphRelatedFlatIndexesToUpdate: UniversalFlatIndexMetadata[];
};
export const renameRelatedMorphFieldOnObjectNamesUpdate = ({
fromFlatObjectMetadata,
@@ -4,63 +4,69 @@ import {
isLabelIdentifierFieldMetadataTypes,
} from 'twenty-shared/utils';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier.util';
import { type FlatObjectMetadataValidationError } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata-validation-error.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { ObjectMetadataExceptionCode } from 'src/engine/metadata-modules/object-metadata/object-metadata.exception';
import { type UniversalFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-maps.type';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
export const validateFlatObjectMetadataIdentifiers = ({
flatObjectMetadata,
flatFieldMetadataMaps,
universalFlatObjectMetadata,
universalFlatFieldMetadataMaps,
}: {
flatObjectMetadata: Pick<
FlatObjectMetadata,
'labelIdentifierFieldMetadataId' | 'imageIdentifierFieldMetadataId'
universalFlatObjectMetadata: Pick<
UniversalFlatObjectMetadata,
| 'labelIdentifierFieldMetadataUniversalIdentifier'
| 'imageIdentifierFieldMetadataUniversalIdentifier'
>;
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
universalFlatFieldMetadataMaps: UniversalFlatEntityMaps<UniversalFlatFieldMetadata>;
}) => {
const errors: FlatObjectMetadataValidationError[] = [];
const { labelIdentifierFieldMetadataId, imageIdentifierFieldMetadataId } =
flatObjectMetadata;
const {
labelIdentifierFieldMetadataUniversalIdentifier,
imageIdentifierFieldMetadataUniversalIdentifier,
} = universalFlatObjectMetadata;
// TODO should not be nullable
if (isDefined(labelIdentifierFieldMetadataId)) {
const flatFieldMetadata = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: labelIdentifierFieldMetadataId,
flatEntityMaps: flatFieldMetadataMaps,
if (isDefined(labelIdentifierFieldMetadataUniversalIdentifier)) {
const universalFlatFieldMetadata = findFlatEntityByUniversalIdentifier({
universalIdentifier: labelIdentifierFieldMetadataUniversalIdentifier,
flatEntityMaps: universalFlatFieldMetadataMaps,
});
if (!isDefined(flatFieldMetadata)) {
if (!isDefined(universalFlatFieldMetadata)) {
errors.push({
code: ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT,
message:
'labelIdentifierFieldMetadataId validation failed: related field metadata not found',
'labelIdentifierFieldMetadataUniversalIdentifier validation failed: related field metadata not found',
userFriendlyMessage: msg`Field declared as label identifier not found`,
});
} else if (!isLabelIdentifierFieldMetadataTypes(flatFieldMetadata.type)) {
} else if (
!isLabelIdentifierFieldMetadataTypes(universalFlatFieldMetadata.type)
) {
errors.push({
code: ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT,
message:
'labelIdentifierFieldMetadataId validation failed: field type not compatible',
'labelIdentifierFieldMetadataUniversalIdentifier validation failed: field type not compatible',
userFriendlyMessage: msg`Field cannot be used as label identifier`,
});
}
}
if (isDefined(imageIdentifierFieldMetadataId)) {
const relatedFlatFieldMetadata = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: imageIdentifierFieldMetadataId,
flatEntityMaps: flatFieldMetadataMaps,
});
if (isDefined(imageIdentifierFieldMetadataUniversalIdentifier)) {
const relatedUniversalFlatFieldMetadata =
findFlatEntityByUniversalIdentifier({
universalIdentifier: imageIdentifierFieldMetadataUniversalIdentifier,
flatEntityMaps: universalFlatFieldMetadataMaps,
});
if (!isDefined(relatedFlatFieldMetadata)) {
if (!isDefined(relatedUniversalFlatFieldMetadata)) {
errors.push({
code: ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT,
message:
'imageIdentifierFieldMetadataId validation failed: related field metadata not found',
'imageIdentifierFieldMetadataUniversalIdentifier validation failed: related field metadata not found',
userFriendlyMessage: msg`Field declared as image identifier not found`,
});
}
@@ -1,16 +1,16 @@
import { msg } from '@lingui/core/macro';
import { type FlatObjectMetadataValidationError } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata-validation-error.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type ObjectMetadataMinimalInformation } from 'src/engine/metadata-modules/flat-object-metadata/types/object-metadata-minimal-information.type';
import { ObjectMetadataExceptionCode } from 'src/engine/metadata-modules/object-metadata/object-metadata.exception';
import { IDENTIFIER_MAX_CHAR_LENGTH } from 'src/engine/metadata-modules/utils/constants/identifier-max-char-length.constants';
import { IDENTIFIER_MIN_CHAR_LENGTH } from 'src/engine/metadata-modules/utils/constants/identifier-min-char-length.constants';
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
export const validateFlatObjectMetadataLabel = ({
labelPlural,
labelSingular,
}: Pick<FlatObjectMetadata, 'labelPlural' | 'labelSingular'> &
}: Pick<UniversalFlatObjectMetadata, 'labelPlural' | 'labelSingular'> &
ObjectMetadataMinimalInformation): FlatObjectMetadataValidationError[] => {
const errors: FlatObjectMetadataValidationError[] = [];
@@ -1,68 +1,72 @@
import { msg, t } from '@lingui/core/macro';
import { isDefined } from 'twenty-shared/utils';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatObjectMetadataValidationError } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata-validation-error.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { areFlatObjectMetadataNamesSyncedWithLabels } from 'src/engine/metadata-modules/flat-object-metadata/utils/are-flat-object-metadata-names-synced-with-labels.util';
import { validateFlatObjectMetadataLabel } from 'src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-label.util';
import { validateFlatObjectMetadataNames } from 'src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-name.util';
import { ObjectMetadataExceptionCode } from 'src/engine/metadata-modules/object-metadata/object-metadata.exception';
import { type UniversalFlatEntityMaps } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-maps.type';
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
import { type WorkspaceMigrationBuilderOptions } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/workspace-migration-builder-options.type';
type ValidateNoOtherObjectWithSameNameExistsOrThrowsParams = {
objectMetadataNameSingular: string;
objectMetadataNamePlural: string;
existingObjectMetadataId?: string;
objectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
existingObjectMetadataUniversalIdentifier?: string;
universalFlatObjectMetadataMaps: UniversalFlatEntityMaps<UniversalFlatObjectMetadata>;
};
export const doesOtherObjectWithSameNameExists = ({
objectMetadataMaps,
universalFlatObjectMetadataMaps,
objectMetadataNamePlural,
objectMetadataNameSingular,
existingObjectMetadataId,
existingObjectMetadataUniversalIdentifier,
}: ValidateNoOtherObjectWithSameNameExistsOrThrowsParams) =>
Object.values(objectMetadataMaps.byUniversalIdentifier)
Object.values(universalFlatObjectMetadataMaps.byUniversalIdentifier)
.filter(isDefined)
.some(
(objectMetadata) =>
(objectMetadata.nameSingular === objectMetadataNameSingular ||
objectMetadata.namePlural === objectMetadataNamePlural ||
objectMetadata.nameSingular === objectMetadataNamePlural ||
objectMetadata.namePlural === objectMetadataNameSingular) &&
objectMetadata.id !== existingObjectMetadataId,
(universalFlatObjectMetadata) =>
(universalFlatObjectMetadata.nameSingular ===
objectMetadataNameSingular ||
universalFlatObjectMetadata.namePlural === objectMetadataNamePlural ||
universalFlatObjectMetadata.nameSingular ===
objectMetadataNamePlural ||
universalFlatObjectMetadata.namePlural ===
objectMetadataNameSingular) &&
universalFlatObjectMetadata.universalIdentifier !==
existingObjectMetadataUniversalIdentifier,
);
export const validateFlatObjectMetadataNameAndLabels = ({
optimisticFlatObjectMetadataMaps,
flatObjectMetadataToValidate,
optimisticUniversalFlatObjectMetadataMaps,
universalFlatObjectMetadataToValidate,
buildOptions,
}: {
flatObjectMetadataToValidate: FlatObjectMetadata;
optimisticFlatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
universalFlatObjectMetadataToValidate: UniversalFlatObjectMetadata;
optimisticUniversalFlatObjectMetadataMaps: UniversalFlatEntityMaps<UniversalFlatObjectMetadata>;
buildOptions: WorkspaceMigrationBuilderOptions;
}): FlatObjectMetadataValidationError[] => {
const errors: FlatObjectMetadataValidationError[] = [];
errors.push(
...validateFlatObjectMetadataNames({
namePlural: flatObjectMetadataToValidate.namePlural,
nameSingular: flatObjectMetadataToValidate.nameSingular,
namePlural: universalFlatObjectMetadataToValidate.namePlural,
nameSingular: universalFlatObjectMetadataToValidate.nameSingular,
}),
);
errors.push(
...validateFlatObjectMetadataLabel({
labelPlural: flatObjectMetadataToValidate.labelPlural,
labelSingular: flatObjectMetadataToValidate.labelSingular,
labelPlural: universalFlatObjectMetadataToValidate.labelPlural,
labelSingular: universalFlatObjectMetadataToValidate.labelSingular,
}),
);
if (
flatObjectMetadataToValidate.isLabelSyncedWithName &&
universalFlatObjectMetadataToValidate.isLabelSyncedWithName &&
!areFlatObjectMetadataNamesSyncedWithLabels({
flatObjectdMetadata: flatObjectMetadataToValidate,
flatObjectdMetadata: universalFlatObjectMetadataToValidate,
isSystemBuild: buildOptions.isSystemBuild,
})
) {
@@ -75,10 +79,14 @@ export const validateFlatObjectMetadataNameAndLabels = ({
if (
doesOtherObjectWithSameNameExists({
objectMetadataNamePlural: flatObjectMetadataToValidate.namePlural,
objectMetadataNameSingular: flatObjectMetadataToValidate.nameSingular,
objectMetadataMaps: optimisticFlatObjectMetadataMaps,
existingObjectMetadataId: flatObjectMetadataToValidate.id,
objectMetadataNamePlural:
universalFlatObjectMetadataToValidate.namePlural,
objectMetadataNameSingular:
universalFlatObjectMetadataToValidate.nameSingular,
universalFlatObjectMetadataMaps:
optimisticUniversalFlatObjectMetadataMaps,
existingObjectMetadataUniversalIdentifier:
universalFlatObjectMetadataToValidate.universalIdentifier,
})
) {
errors.push({
@@ -2,11 +2,11 @@ import { msg } from '@lingui/core/macro';
import { RESERVED_METADATA_NAME_KEYWORDS } from 'twenty-shared/metadata';
import { type FlatObjectMetadataValidationError } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata-validation-error.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { type ObjectMetadataMinimalInformation } from 'src/engine/metadata-modules/flat-object-metadata/types/object-metadata-minimal-information.type';
import { ObjectMetadataExceptionCode } from 'src/engine/metadata-modules/object-metadata/object-metadata.exception';
import { IDENTIFIER_MAX_CHAR_LENGTH } from 'src/engine/metadata-modules/utils/constants/identifier-max-char-length.constants';
import { IDENTIFIER_MIN_CHAR_LENGTH } from 'src/engine/metadata-modules/utils/constants/identifier-min-char-length.constants';
import { type UniversalFlatObjectMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-object-metadata.type';
const STARTS_WITH_LOWER_CASE_AND_CONTAINS_ONLY_CAPS_AND_LOWER_LETTERS_AND_NUMBER_STRING_REGEX =
/^[a-z][a-zA-Z0-9]*$/;
@@ -14,7 +14,7 @@ const STARTS_WITH_LOWER_CASE_AND_CONTAINS_ONLY_CAPS_AND_LOWER_LETTERS_AND_NUMBER
export const validateFlatObjectMetadataNames = ({
namePlural,
nameSingular,
}: Pick<FlatObjectMetadata, 'nameSingular' | 'namePlural'> &
}: Pick<UniversalFlatObjectMetadata, 'nameSingular' | 'namePlural'> &
ObjectMetadataMinimalInformation) => {
const errors: FlatObjectMetadataValidationError[] = [];
@@ -1,6 +1,6 @@
import { type FlatPageLayoutTab } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab.type';
import { type MetadataEntityPropertyName } from 'src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant';
export const FLAT_PAGE_LAYOUT_TAB_EDITABLE_PROPERTIES = [
'title',
'position',
] as const satisfies (keyof FlatPageLayoutTab)[];
] as const satisfies MetadataEntityPropertyName<'pageLayoutTab'>[];
@@ -1,4 +1,4 @@
import { type FlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget.type';
import { type MetadataEntityPropertyName } from 'src/engine/metadata-modules/flat-entity/constant/all-entity-properties-configuration-by-metadata-name.constant';
export const FLAT_PAGE_LAYOUT_WIDGET_EDITABLE_PROPERTIES = [
'title',
@@ -7,4 +7,4 @@ export const FLAT_PAGE_LAYOUT_WIDGET_EDITABLE_PROPERTIES = [
'gridPosition',
'position',
'configuration',
] as const satisfies (keyof FlatPageLayoutWidget)[];
] as const satisfies MetadataEntityPropertyName<'pageLayoutWidget'>[];
@@ -3,7 +3,6 @@ import { Injectable } from '@nestjs/common';
import { msg } from '@lingui/core/macro';
import { isDefined } from 'twenty-shared/utils';
import { FlatEntityUpdate } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-properties-updates.type';
import {
type FlatPageLayoutWidgetTypeValidatorForCreation,
type FlatPageLayoutWidgetTypeValidatorForUpdate,
@@ -20,19 +19,20 @@ import { validateStandaloneRichTextFlatPageLayoutWidgetForCreation } from 'src/e
import { validateStandaloneRichTextFlatPageLayoutWidgetForUpdate } from 'src/engine/metadata-modules/flat-page-layout-widget/validators/utils/validate-standalone-rich-text-flat-page-layout-widget-for-update.util';
import { WidgetType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-type.enum';
import { PageLayoutWidgetExceptionCode } from 'src/engine/metadata-modules/page-layout-widget/exceptions/page-layout-widget.exception';
import { FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/flat-entity-validation-args.type';
import { UniversalFlatEntityUpdate } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-update.type';
import { UniversalFlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/universal-flat-entity-validation-args.type';
export type GenericValidateFlatPageLayoutWidgetTypeSpecificitiesArgs =
FlatEntityValidationArgs<'pageLayoutWidget'> & {
update?: FlatEntityUpdate<'pageLayoutWidget'>;
UniversalFlatEntityValidationArgs<'pageLayoutWidget'> & {
update?: UniversalFlatEntityUpdate<'pageLayoutWidget'>;
};
export type ValidateFlatPageLayoutWidgetTypeSpecificitiesForCreationArgs =
FlatEntityValidationArgs<'pageLayoutWidget'>;
UniversalFlatEntityValidationArgs<'pageLayoutWidget'>;
export type ValidateFlatPageLayoutWidgetTypeSpecificitiesForUpdateArgs =
FlatEntityValidationArgs<'pageLayoutWidget'> & {
update: FlatEntityUpdate<'pageLayoutWidget'>;
UniversalFlatEntityValidationArgs<'pageLayoutWidget'> & {
update: UniversalFlatEntityUpdate<'pageLayoutWidget'>;
};
@Injectable()
@@ -77,8 +77,9 @@ export class WorkspaceFlatPageLayoutWidgetMapCacheService extends WorkspaceCache
createIdToUniversalIdentifierMap(pageLayoutTabs);
const objectMetadataIdToUniversalIdentifierMap =
createIdToUniversalIdentifierMap(objectMetadatas);
const fieldMetadataIdToUniversalIdentifierMap =
createIdToUniversalIdentifierMap(fieldMetadatas);
const fieldMetadataUniversalIdentifierById = Object.fromEntries(
createIdToUniversalIdentifierMap(fieldMetadatas),
);
const flatPageLayoutWidgetMaps = createEmptyFlatEntityMaps();
@@ -89,7 +90,7 @@ export class WorkspaceFlatPageLayoutWidgetMapCacheService extends WorkspaceCache
applicationIdToUniversalIdentifierMap,
pageLayoutTabIdToUniversalIdentifierMap,
objectMetadataIdToUniversalIdentifierMap,
fieldMetadataIdToUniversalIdentifierMap,
fieldMetadataUniversalIdentifierById,
});
addFlatEntityToFlatEntityMapsThroughMutationOrThrow({
@@ -1,6 +1,4 @@
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget.type';
export type FlatPageLayoutWidgetMaps = FlatEntityMaps<
Omit<FlatPageLayoutWidget, 'universalConfiguration'>
>;
export type FlatPageLayoutWidgetMaps = FlatEntityMaps<FlatPageLayoutWidget>;
@@ -4,4 +4,4 @@ import { type WidgetConfigurationType } from 'src/engine/metadata-modules/page-l
export type FlatPageLayoutWidget<
T extends WidgetConfigurationType = WidgetConfigurationType,
> = Omit<FlatEntityFrom<PageLayoutWidgetEntity<T>>, 'universalConfiguration'>;
> = FlatEntityFrom<PageLayoutWidgetEntity<T>>;
@@ -5,6 +5,7 @@ import { type FlatApplication } from 'src/engine/core-modules/application/types/
import { type AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
import { resolveEntityRelationUniversalIdentifiers } from 'src/engine/metadata-modules/flat-entity/utils/resolve-entity-relation-universal-identifiers.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 { type CreatePageLayoutWidgetInput } from 'src/engine/metadata-modules/page-layout-widget/dtos/inputs/create-page-layout-widget.input';
import { validateWidgetConfigurationInput } from 'src/engine/metadata-modules/page-layout-widget/utils/validate-widget-configuration-input.util';
@@ -15,7 +16,7 @@ export type FromCreatePageLayoutWidgetInputToFlatPageLayoutWidgetToCreateArgs =
flatApplication: FlatApplication;
} & Pick<
AllFlatEntityMaps,
'flatPageLayoutTabMaps' | 'flatObjectMetadataMaps'
'flatPageLayoutTabMaps' | 'flatObjectMetadataMaps' | 'flatFieldMetadataMaps'
>;
export const fromCreatePageLayoutWidgetInputToFlatPageLayoutWidgetToCreate = ({
@@ -24,6 +25,7 @@ export const fromCreatePageLayoutWidgetInputToFlatPageLayoutWidgetToCreate = ({
flatApplication,
flatPageLayoutTabMaps,
flatObjectMetadataMaps,
flatFieldMetadataMaps,
}: FromCreatePageLayoutWidgetInputToFlatPageLayoutWidgetToCreateArgs): FlatPageLayoutWidget => {
const { pageLayoutTabId, ...createPageLayoutWidgetInput } =
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
@@ -69,5 +71,12 @@ export const fromCreatePageLayoutWidgetInputToFlatPageLayoutWidgetToCreate = ({
applicationId: flatApplication.id,
applicationUniversalIdentifier: flatApplication.universalIdentifier,
conditionalDisplay: null,
universalConfiguration:
fromPageLayoutWidgetConfigurationToUniversalConfiguration({
configuration: createPageLayoutWidgetInput.configuration,
fieldMetadataUniversalIdentifierById:
flatFieldMetadataMaps.universalIdentifierById,
shouldThrowOnMissingIdentifier: true,
}),
};
};
@@ -1,5 +1,9 @@
import { isDefined } from 'twenty-shared/utils';
import {
FlatEntityMapsException,
FlatEntityMapsExceptionCode,
} from 'src/engine/metadata-modules/flat-entity/exceptions/flat-entity-maps.exception';
import { type FlatPageLayoutWidget } from 'src/engine/metadata-modules/flat-page-layout-widget/types/flat-page-layout-widget.type';
import { type PageLayoutWidgetEntity } from 'src/engine/metadata-modules/page-layout-widget/entities/page-layout-widget.entity';
import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout-widget/enums/widget-configuration-type.type';
@@ -7,62 +11,87 @@ import { WidgetConfigurationType } from 'src/engine/metadata-modules/page-layout
type PageLayoutWidgetConfiguration = PageLayoutWidgetEntity['configuration'];
type UniversalPageLayoutWidgetConfiguration =
// @ts-expect-error Ignoring until the pageLayoutWidget has been universally migrated
NonNullable<FlatPageLayoutWidget>['universalConfiguration'];
// Field metadata IDs in widget configurations don't need to reference existing entities
const getFieldMetadataUniversalIdentifier = ({
fieldMetadataId,
fieldMetadataIdToUniversalIdentifierMap,
fieldMetadataUniversalIdentifierById,
shouldThrowOnMissingIdentifier,
}: {
fieldMetadataId: string;
fieldMetadataIdToUniversalIdentifierMap: Map<string, string>;
fieldMetadataUniversalIdentifierById: Partial<Record<string, string>>;
shouldThrowOnMissingIdentifier: boolean;
}): string | null => {
return fieldMetadataIdToUniversalIdentifierMap.get(fieldMetadataId) ?? null;
const universalIdentifier =
fieldMetadataUniversalIdentifierById[fieldMetadataId];
if (!isDefined(universalIdentifier)) {
if (shouldThrowOnMissingIdentifier) {
throw new FlatEntityMapsException(
`Field metadata universal identifier not found for id: ${fieldMetadataId}`,
FlatEntityMapsExceptionCode.RELATION_UNIVERSAL_IDENTIFIER_NOT_FOUND,
);
}
return null;
}
return universalIdentifier;
};
export const fromPageLayoutWidgetConfigurationToUniversalConfiguration = ({
configuration,
fieldMetadataIdToUniversalIdentifierMap,
fieldMetadataUniversalIdentifierById,
shouldThrowOnMissingIdentifier = false,
}: {
configuration: PageLayoutWidgetConfiguration;
fieldMetadataIdToUniversalIdentifierMap: Map<string, string>;
fieldMetadataUniversalIdentifierById: Partial<Record<string, string>>;
shouldThrowOnMissingIdentifier?: boolean;
}): UniversalPageLayoutWidgetConfiguration => {
switch (configuration.configurationType) {
case WidgetConfigurationType.AGGREGATE_CHART: {
const { aggregateFieldMetadataId, ratioAggregateConfig, ...rest } =
configuration;
return {
...rest,
aggregateFieldMetadataUniversalIdentifier:
getFieldMetadataUniversalIdentifier({
fieldMetadataId: aggregateFieldMetadataId,
fieldMetadataIdToUniversalIdentifierMap,
}),
...(isDefined(ratioAggregateConfig) && {
ratioAggregateConfig: {
const aggregateFieldMetadataUniversalIdentifier =
getFieldMetadataUniversalIdentifier({
fieldMetadataId: aggregateFieldMetadataId,
fieldMetadataUniversalIdentifierById,
shouldThrowOnMissingIdentifier,
});
const universalRatioAggregateConfig = isDefined(ratioAggregateConfig)
? {
optionValue: ratioAggregateConfig.optionValue,
fieldMetadataUniversalIdentifier:
getFieldMetadataUniversalIdentifier({
fieldMetadataId: ratioAggregateConfig.fieldMetadataId,
fieldMetadataIdToUniversalIdentifierMap,
fieldMetadataUniversalIdentifierById,
shouldThrowOnMissingIdentifier,
}),
},
}),
}
: undefined;
return {
...rest,
aggregateFieldMetadataUniversalIdentifier,
ratioAggregateConfig: universalRatioAggregateConfig,
};
}
case WidgetConfigurationType.GAUGE_CHART: {
const { aggregateFieldMetadataId, ...rest } = configuration;
const aggregateFieldMetadataUniversalIdentifier =
getFieldMetadataUniversalIdentifier({
fieldMetadataId: aggregateFieldMetadataId,
fieldMetadataUniversalIdentifierById,
shouldThrowOnMissingIdentifier,
});
return {
...rest,
aggregateFieldMetadataUniversalIdentifier:
getFieldMetadataUniversalIdentifier({
fieldMetadataId: aggregateFieldMetadataId,
fieldMetadataIdToUniversalIdentifierMap,
}),
aggregateFieldMetadataUniversalIdentifier,
};
}
@@ -70,18 +99,24 @@ export const fromPageLayoutWidgetConfigurationToUniversalConfiguration = ({
const { aggregateFieldMetadataId, groupByFieldMetadataId, ...rest } =
configuration;
const aggregateFieldMetadataUniversalIdentifier =
getFieldMetadataUniversalIdentifier({
fieldMetadataId: aggregateFieldMetadataId,
fieldMetadataUniversalIdentifierById,
shouldThrowOnMissingIdentifier,
});
const groupByFieldMetadataUniversalIdentifier =
getFieldMetadataUniversalIdentifier({
fieldMetadataId: groupByFieldMetadataId,
fieldMetadataUniversalIdentifierById,
shouldThrowOnMissingIdentifier,
});
return {
...rest,
aggregateFieldMetadataUniversalIdentifier:
getFieldMetadataUniversalIdentifier({
fieldMetadataId: aggregateFieldMetadataId,
fieldMetadataIdToUniversalIdentifierMap,
}),
groupByFieldMetadataUniversalIdentifier:
getFieldMetadataUniversalIdentifier({
fieldMetadataId: groupByFieldMetadataId,
fieldMetadataIdToUniversalIdentifierMap,
}),
aggregateFieldMetadataUniversalIdentifier,
groupByFieldMetadataUniversalIdentifier,
};
}
@@ -93,25 +128,35 @@ export const fromPageLayoutWidgetConfigurationToUniversalConfiguration = ({
...rest
} = configuration;
const aggregateFieldMetadataUniversalIdentifier =
getFieldMetadataUniversalIdentifier({
fieldMetadataId: aggregateFieldMetadataId,
fieldMetadataUniversalIdentifierById,
shouldThrowOnMissingIdentifier,
});
const primaryAxisGroupByFieldMetadataUniversalIdentifier =
getFieldMetadataUniversalIdentifier({
fieldMetadataId: primaryAxisGroupByFieldMetadataId,
fieldMetadataUniversalIdentifierById,
shouldThrowOnMissingIdentifier,
});
const secondaryAxisGroupByFieldMetadataUniversalIdentifier = isDefined(
secondaryAxisGroupByFieldMetadataId,
)
? getFieldMetadataUniversalIdentifier({
fieldMetadataId: secondaryAxisGroupByFieldMetadataId,
fieldMetadataUniversalIdentifierById,
shouldThrowOnMissingIdentifier,
})
: undefined;
return {
...rest,
aggregateFieldMetadataUniversalIdentifier:
getFieldMetadataUniversalIdentifier({
fieldMetadataId: aggregateFieldMetadataId,
fieldMetadataIdToUniversalIdentifierMap,
}),
primaryAxisGroupByFieldMetadataUniversalIdentifier:
getFieldMetadataUniversalIdentifier({
fieldMetadataId: primaryAxisGroupByFieldMetadataId,
fieldMetadataIdToUniversalIdentifierMap,
}),
...(isDefined(secondaryAxisGroupByFieldMetadataId) && {
secondaryAxisGroupByFieldMetadataUniversalIdentifier:
getFieldMetadataUniversalIdentifier({
fieldMetadataId: secondaryAxisGroupByFieldMetadataId,
fieldMetadataIdToUniversalIdentifierMap,
}),
}),
aggregateFieldMetadataUniversalIdentifier,
primaryAxisGroupByFieldMetadataUniversalIdentifier,
secondaryAxisGroupByFieldMetadataUniversalIdentifier,
};
}
@@ -123,25 +168,35 @@ export const fromPageLayoutWidgetConfigurationToUniversalConfiguration = ({
...rest
} = configuration;
const aggregateFieldMetadataUniversalIdentifier =
getFieldMetadataUniversalIdentifier({
fieldMetadataId: aggregateFieldMetadataId,
fieldMetadataUniversalIdentifierById,
shouldThrowOnMissingIdentifier,
});
const primaryAxisGroupByFieldMetadataUniversalIdentifier =
getFieldMetadataUniversalIdentifier({
fieldMetadataId: primaryAxisGroupByFieldMetadataId,
fieldMetadataUniversalIdentifierById,
shouldThrowOnMissingIdentifier,
});
const secondaryAxisGroupByFieldMetadataUniversalIdentifier = isDefined(
secondaryAxisGroupByFieldMetadataId,
)
? getFieldMetadataUniversalIdentifier({
fieldMetadataId: secondaryAxisGroupByFieldMetadataId,
fieldMetadataUniversalIdentifierById,
shouldThrowOnMissingIdentifier,
})
: undefined;
return {
...rest,
aggregateFieldMetadataUniversalIdentifier:
getFieldMetadataUniversalIdentifier({
fieldMetadataId: aggregateFieldMetadataId,
fieldMetadataIdToUniversalIdentifierMap,
}),
primaryAxisGroupByFieldMetadataUniversalIdentifier:
getFieldMetadataUniversalIdentifier({
fieldMetadataId: primaryAxisGroupByFieldMetadataId,
fieldMetadataIdToUniversalIdentifierMap,
}),
...(isDefined(secondaryAxisGroupByFieldMetadataId) && {
secondaryAxisGroupByFieldMetadataUniversalIdentifier:
getFieldMetadataUniversalIdentifier({
fieldMetadataId: secondaryAxisGroupByFieldMetadataId,
fieldMetadataIdToUniversalIdentifierMap,
}),
}),
aggregateFieldMetadataUniversalIdentifier,
primaryAxisGroupByFieldMetadataUniversalIdentifier,
secondaryAxisGroupByFieldMetadataUniversalIdentifier,
};
}

Some files were not shown because too many files have changed in this diff Show More