[REQUIRES_CACHE_FLUSH_FOR_FIELD_AND_OBJECT]FlatFieldMetadata and FlatObjectMetadata required universal (#17557)
# Introduction
In this PR we're migrating both the `field` and `object` metadata to be
using the new `FlatEntityFromV2` that requires all the
`UniversalFlatEntityExtraProperties` to be spread at the flat entity
root.
This means that we have to update all of their flat declaration
This type swap allows to isole a specific entity migration into his own
type scope and avoid to have everything handled at once
```ts
/**
* Currently under migration but aims to replace FlatEntity afterwards
*/
export type FlatEntityFromV2<
TEntity,
TMetadataName extends AllMetadataName | undefined = undefined,
TInnerFlatEntity extends { __universal?: unknown } = FlatEntityFrom<
TEntity,
TMetadataName
>,
> = Omit<TInnerFlatEntity, '__universal'> & TInnerFlatEntity['__universal'];
```
## Impact
Both object and field:
- Create input transpilation utils
- from entity to flat tools
- mocks
## Note
Removed from the universal extra properties the jsonb properties that do
not contain a serialized
## Next
Next step is to incrementally make the builder and runner expect
`UniversalFlatEntity` for both of these metadata
This way we will be able to fully migrate an entity e2e typesafely
This commit is contained in:
+3
@@ -14,6 +14,7 @@ export const FieldMetadataExceptionCode = appendCommonExceptionCode({
|
||||
FIELD_MUTATION_NOT_ALLOWED: 'FIELD_MUTATION_NOT_ALLOWED',
|
||||
FIELD_ALREADY_EXISTS: 'FIELD_ALREADY_EXISTS',
|
||||
OBJECT_METADATA_NOT_FOUND: 'OBJECT_METADATA_NOT_FOUND',
|
||||
APPLICATION_NOT_FOUND: 'APPLICATION_NOT_FOUND',
|
||||
FIELD_METADATA_RELATION_NOT_ENABLED: 'FIELD_METADATA_RELATION_NOT_ENABLED',
|
||||
FIELD_METADATA_RELATION_MALFORMED: 'FIELD_METADATA_RELATION_MALFORMED',
|
||||
LABEL_IDENTIFIER_FIELD_METADATA_ID_NOT_FOUND:
|
||||
@@ -43,6 +44,8 @@ const getFieldMetadataExceptionUserFriendlyMessage = (
|
||||
return msg`A field with this name already exists.`;
|
||||
case FieldMetadataExceptionCode.OBJECT_METADATA_NOT_FOUND:
|
||||
return msg`Object not found.`;
|
||||
case FieldMetadataExceptionCode.APPLICATION_NOT_FOUND:
|
||||
return msg`Application not found.`;
|
||||
case FieldMetadataExceptionCode.FIELD_METADATA_RELATION_NOT_ENABLED:
|
||||
return msg`Relation is not enabled for this field.`;
|
||||
case FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED:
|
||||
|
||||
+2
@@ -31,6 +31,7 @@ import { ViewModule } from 'src/engine/metadata-modules/view/view.module';
|
||||
import { WorkspaceMetadataVersionModule } from 'src/engine/metadata-modules/workspace-metadata-version/workspace-metadata-version.module';
|
||||
import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module';
|
||||
import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module';
|
||||
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
||||
|
||||
import { FieldMetadataEntity } from './field-metadata.entity';
|
||||
|
||||
@@ -62,6 +63,7 @@ import { UpdateFieldInput } from './dtos/update-field.input';
|
||||
FlatFieldMetadataModule,
|
||||
IndexMetadataModule,
|
||||
WorkspaceManyOrAllFlatEntityMapsCacheModule,
|
||||
WorkspaceCacheModule,
|
||||
],
|
||||
services: [FieldMetadataService],
|
||||
resolvers: [
|
||||
|
||||
+24
-9
@@ -22,6 +22,7 @@ import { fromCreateFieldInputToFlatFieldMetadatasToCreate } from 'src/engine/met
|
||||
import { fromDeleteFieldInputToFlatFieldMetadatasToDelete } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-delete-field-input-to-flat-field-metadatas-to-delete.util';
|
||||
import { fromUpdateFieldInputToFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-update-field-input-to-flat-field-metadata.util';
|
||||
import { throwOnFieldInputTranspilationsError } from 'src/engine/metadata-modules/flat-field-metadata/utils/throw-on-field-input-transpilations-error.util';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { EMPTY_ORCHESTRATOR_FAILURE_REPORT } from 'src/engine/workspace-manager/workspace-migration/constant/empty-orchestrator-failure-report.constant';
|
||||
import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
@@ -34,6 +35,7 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
|
||||
private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
|
||||
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||
) {
|
||||
super(fieldMetadataRepository);
|
||||
}
|
||||
@@ -180,7 +182,7 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
|
||||
flatViewGroupMaps: existingFlatViewGroupMaps,
|
||||
flatViewMaps: existingFlatViewMaps,
|
||||
flatViewFieldMaps: existingFlatViewFieldMaps,
|
||||
workspaceCustomApplicationId: workspaceCustomFlatApplication.id,
|
||||
flatApplication: workspaceCustomFlatApplication,
|
||||
isSystemBuild,
|
||||
});
|
||||
|
||||
@@ -309,13 +311,26 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
|
||||
},
|
||||
);
|
||||
|
||||
const { flatObjectMetadataMaps: existingFlatObjectMetadataMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatObjectMetadataMaps'],
|
||||
},
|
||||
const {
|
||||
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
|
||||
flatApplicationMaps,
|
||||
} = await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatObjectMetadataMaps',
|
||||
'flatFieldMetadataMaps',
|
||||
'flatApplicationMaps',
|
||||
]);
|
||||
|
||||
const ownerFlatApplication = isDefined(applicationId)
|
||||
? flatApplicationMaps.byId[applicationId]
|
||||
: workspaceCustomFlatApplication;
|
||||
|
||||
if (!isDefined(ownerFlatApplication)) {
|
||||
throw new FieldMetadataException(
|
||||
`Could not find related application ${applicationId}`,
|
||||
FieldMetadataExceptionCode.APPLICATION_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const allTranspiledTranspilationInputs: Awaited<
|
||||
ReturnType<typeof fromCreateFieldInputToFlatFieldMetadatasToCreate>
|
||||
@@ -325,10 +340,10 @@ export class FieldMetadataService extends TypeOrmQueryService<FieldMetadataEntit
|
||||
allTranspiledTranspilationInputs.push(
|
||||
await fromCreateFieldInputToFlatFieldMetadatasToCreate({
|
||||
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
|
||||
createFieldInput,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId:
|
||||
applicationId ?? workspaceCustomFlatApplication.id,
|
||||
flatApplication: ownerFlatApplication,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
+1
@@ -38,6 +38,7 @@ export const fieldMetadataGraphqlApiExceptionHandler = (
|
||||
case FieldMetadataExceptionCode.FIELD_ALREADY_EXISTS:
|
||||
throw new ConflictError(error);
|
||||
case FieldMetadataExceptionCode.OBJECT_METADATA_NOT_FOUND:
|
||||
case FieldMetadataExceptionCode.APPLICATION_NOT_FOUND:
|
||||
case FieldMetadataExceptionCode.INTERNAL_SERVER_ERROR:
|
||||
case FieldMetadataExceptionCode.FIELD_METADATA_RELATION_NOT_ENABLED:
|
||||
case FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED:
|
||||
|
||||
-2
@@ -43,8 +43,6 @@ export const transformAgentEntityToFlatAgent = ({
|
||||
__universal: {
|
||||
universalIdentifier: agentEntity.universalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
responseFormat: agentEntity.responseFormat,
|
||||
modelConfiguration: agentEntity.modelConfiguration,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
+2
@@ -4,6 +4,7 @@ import { type Expect } from 'twenty-shared/testing';
|
||||
import { type AllFlatEntityTypesByMetadataName } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-types-by-metadata-name';
|
||||
import { type SyncableFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';
|
||||
import { type WorkspaceMigrationActionType } from 'src/engine/metadata-modules/flat-entity/types/metadata-workspace-migration-action.type';
|
||||
import { type UniversalSyncableFlatEntity } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-entity-from.type';
|
||||
import { type WorkspaceMigrationAction } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-builder/types/workspace-migration-action-common';
|
||||
|
||||
type ExpectedGenericFlatEntityInformation = {
|
||||
@@ -13,6 +14,7 @@ type ExpectedGenericFlatEntityInformation = {
|
||||
| WorkspaceMigrationAction[];
|
||||
};
|
||||
flatEntity: SyncableFlatEntity;
|
||||
universalFlatEntity: UniversalSyncableFlatEntity;
|
||||
};
|
||||
|
||||
type ExpectedGenericAllFlatEntityInformationByMetadataEngine = {
|
||||
|
||||
+52
-2
@@ -1,10 +1,12 @@
|
||||
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 FlatAgent } from 'src/engine/metadata-modules/flat-agent/types/flat-agent.type';
|
||||
import { type FlatCommandMenuItem } from 'src/engine/metadata-modules/flat-command-menu-item/types/flat-command-menu-item.type';
|
||||
import { type MetadataEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-entity.type';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { type FlatFrontComponent } from 'src/engine/metadata-modules/flat-front-component/types/flat-front-component.type';
|
||||
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
|
||||
import { type FlatWebhook } from 'src/engine/metadata-modules/flat-webhook/types/flat-webhook.type';
|
||||
import { type FlatNavigationMenuItem } from 'src/engine/metadata-modules/flat-navigation-menu-item/types/flat-navigation-menu-item.type';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { type FlatPageLayoutTab } from 'src/engine/metadata-modules/flat-page-layout-tab/types/flat-page-layout-tab.type';
|
||||
@@ -18,10 +20,30 @@ import { type FlatViewFilterGroup } from 'src/engine/metadata-modules/flat-view-
|
||||
import { type FlatViewFilter } from 'src/engine/metadata-modules/flat-view-filter/types/flat-view-filter.type';
|
||||
import { type FlatViewGroup } from 'src/engine/metadata-modules/flat-view-group/types/flat-view-group.type';
|
||||
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.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 FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
|
||||
import { type LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity';
|
||||
import { type NavigationMenuItemEntity } from 'src/engine/metadata-modules/navigation-menu-item/entities/navigation-menu-item.entity';
|
||||
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
import { type PageLayoutEntity } from 'src/engine/metadata-modules/page-layout/entities/page-layout.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 RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
|
||||
import { type RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity';
|
||||
import { type FlatRowLevelPermissionPredicateGroup } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate-group.type';
|
||||
import { type FlatRowLevelPermissionPredicate } from 'src/engine/metadata-modules/row-level-permission-predicate/types/flat-row-level-permission-predicate.type';
|
||||
import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type';
|
||||
import { type RowLevelPermissionPredicateEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate.entity';
|
||||
import { type RowLevelPermissionPredicateGroupEntity } from 'src/engine/metadata-modules/row-level-permission-predicate/entities/row-level-permission-predicate-group.entity';
|
||||
import { type SkillEntity } from 'src/engine/metadata-modules/skill/entities/skill.entity';
|
||||
import { type ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { type ViewFieldEntity } from 'src/engine/metadata-modules/view-field/entities/view-field.entity';
|
||||
import { type ViewFilterEntity } from 'src/engine/metadata-modules/view-filter/entities/view-filter.entity';
|
||||
import { type ViewFilterGroupEntity } from 'src/engine/metadata-modules/view-filter-group/entities/view-filter-group.entity';
|
||||
import { type ViewGroupEntity } from 'src/engine/metadata-modules/view-group/entities/view-group.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 CreateAgentAction,
|
||||
type DeleteAgentAction,
|
||||
@@ -141,6 +163,10 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteFieldAction;
|
||||
};
|
||||
flatEntity: FlatFieldMetadata;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<
|
||||
FieldMetadataEntity,
|
||||
'fieldMetadata'
|
||||
>;
|
||||
entity: MetadataEntity<'fieldMetadata'>;
|
||||
};
|
||||
objectMetadata: {
|
||||
@@ -150,6 +176,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteObjectAction;
|
||||
};
|
||||
flatEntity: FlatObjectMetadata;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<ObjectMetadataEntity>;
|
||||
entity: MetadataEntity<'objectMetadata'>;
|
||||
};
|
||||
view: {
|
||||
@@ -159,6 +186,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteViewAction;
|
||||
};
|
||||
flatEntity: FlatView;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<ViewEntity>;
|
||||
entity: MetadataEntity<'view'>;
|
||||
};
|
||||
viewField: {
|
||||
@@ -168,6 +196,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteViewFieldAction;
|
||||
};
|
||||
flatEntity: FlatViewField;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<ViewFieldEntity>;
|
||||
entity: MetadataEntity<'viewField'>;
|
||||
};
|
||||
viewGroup: {
|
||||
@@ -177,6 +206,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteViewGroupAction;
|
||||
};
|
||||
flatEntity: FlatViewGroup;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<ViewGroupEntity>;
|
||||
entity: MetadataEntity<'viewGroup'>;
|
||||
};
|
||||
rowLevelPermissionPredicate: {
|
||||
@@ -186,6 +216,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteRowLevelPermissionPredicateAction;
|
||||
};
|
||||
flatEntity: FlatRowLevelPermissionPredicate;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<RowLevelPermissionPredicateEntity>;
|
||||
entity: MetadataEntity<'rowLevelPermissionPredicate'>;
|
||||
};
|
||||
rowLevelPermissionPredicateGroup: {
|
||||
@@ -195,6 +226,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteRowLevelPermissionPredicateGroupAction;
|
||||
};
|
||||
flatEntity: FlatRowLevelPermissionPredicateGroup;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<RowLevelPermissionPredicateGroupEntity>;
|
||||
entity: MetadataEntity<'rowLevelPermissionPredicateGroup'>;
|
||||
};
|
||||
viewFilterGroup: {
|
||||
@@ -204,6 +236,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteViewFilterGroupAction;
|
||||
};
|
||||
flatEntity: FlatViewFilterGroup;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<ViewFilterGroupEntity>;
|
||||
entity: MetadataEntity<'viewFilterGroup'>;
|
||||
};
|
||||
index: {
|
||||
@@ -213,6 +246,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteIndexAction;
|
||||
};
|
||||
flatEntity: FlatIndexMetadata;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<IndexMetadataEntity>;
|
||||
entity: MetadataEntity<'index'>;
|
||||
};
|
||||
logicFunction: {
|
||||
@@ -222,6 +256,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteLogicFunctionAction;
|
||||
};
|
||||
flatEntity: FlatLogicFunction;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<LogicFunctionEntity>;
|
||||
entity: MetadataEntity<'logicFunction'>;
|
||||
};
|
||||
viewFilter: {
|
||||
@@ -231,6 +266,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteViewFilterAction;
|
||||
};
|
||||
flatEntity: FlatViewFilter;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<ViewFilterEntity>;
|
||||
entity: MetadataEntity<'viewFilter'>;
|
||||
};
|
||||
role: {
|
||||
@@ -240,6 +276,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteRoleAction;
|
||||
};
|
||||
flatEntity: FlatRole;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<RoleEntity>;
|
||||
entity: MetadataEntity<'role'>;
|
||||
};
|
||||
roleTarget: {
|
||||
@@ -249,6 +286,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteRoleTargetAction;
|
||||
};
|
||||
flatEntity: FlatRoleTarget;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<RoleTargetEntity>;
|
||||
entity: MetadataEntity<'roleTarget'>;
|
||||
};
|
||||
agent: {
|
||||
@@ -258,6 +296,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteAgentAction;
|
||||
};
|
||||
flatEntity: FlatAgent;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<AgentEntity>;
|
||||
entity: MetadataEntity<'agent'>;
|
||||
};
|
||||
skill: {
|
||||
@@ -267,6 +306,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteSkillAction;
|
||||
};
|
||||
flatEntity: FlatSkill;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<SkillEntity>;
|
||||
entity: MetadataEntity<'skill'>;
|
||||
};
|
||||
commandMenuItem: {
|
||||
@@ -276,6 +316,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteCommandMenuItemAction;
|
||||
};
|
||||
flatEntity: FlatCommandMenuItem;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<CommandMenuItemEntity>;
|
||||
entity: MetadataEntity<'commandMenuItem'>;
|
||||
};
|
||||
navigationMenuItem: {
|
||||
@@ -285,6 +326,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteNavigationMenuItemAction;
|
||||
};
|
||||
flatEntity: FlatNavigationMenuItem;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<NavigationMenuItemEntity>;
|
||||
entity: NavigationMenuItemEntity;
|
||||
};
|
||||
pageLayout: {
|
||||
@@ -294,6 +336,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeletePageLayoutAction;
|
||||
};
|
||||
flatEntity: FlatPageLayout;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<PageLayoutEntity>;
|
||||
entity: MetadataEntity<'pageLayout'>;
|
||||
};
|
||||
pageLayoutWidget: {
|
||||
@@ -303,6 +346,10 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeletePageLayoutWidgetAction;
|
||||
};
|
||||
flatEntity: FlatPageLayoutWidget;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<
|
||||
PageLayoutWidgetEntity,
|
||||
'pageLayoutWidget'
|
||||
>;
|
||||
entity: MetadataEntity<'pageLayoutWidget'>;
|
||||
};
|
||||
pageLayoutTab: {
|
||||
@@ -312,6 +359,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeletePageLayoutTabAction;
|
||||
};
|
||||
flatEntity: FlatPageLayoutTab;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<PageLayoutTabEntity>;
|
||||
entity: MetadataEntity<'pageLayoutTab'>;
|
||||
};
|
||||
frontComponent: {
|
||||
@@ -321,6 +369,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteFrontComponentAction;
|
||||
};
|
||||
flatEntity: FlatFrontComponent;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<FrontComponentEntity>;
|
||||
entity: MetadataEntity<'frontComponent'>;
|
||||
};
|
||||
webhook: {
|
||||
@@ -330,6 +379,7 @@ export type AllFlatEntityTypesByMetadataName = {
|
||||
delete: DeleteWebhookAction;
|
||||
};
|
||||
flatEntity: FlatWebhook;
|
||||
universalFlatEntity: UniversalFlatEntityFrom<WebhookEntity>;
|
||||
entity: MetadataEntity<'webhook'>;
|
||||
};
|
||||
};
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import { type AllMetadataName } from 'twenty-shared/metadata';
|
||||
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';
|
||||
|
||||
/**
|
||||
* Currently under migration but aims to replace FlatEntity afterwards
|
||||
*/
|
||||
export type FlatEntityFromV2<
|
||||
TEntity,
|
||||
TMetadataName extends AllMetadataName | undefined = undefined,
|
||||
TInnerFlatEntity extends { __universal?: unknown } = FlatEntityFrom<
|
||||
TEntity,
|
||||
TMetadataName
|
||||
>,
|
||||
> = Omit<TInnerFlatEntity, '__universal'> & TInnerFlatEntity['__universal'];
|
||||
+1
@@ -16,6 +16,7 @@ export type SyncableFlatEntity = Omit<
|
||||
|
||||
export type FlatEntityFrom<
|
||||
TEntity,
|
||||
// Required to be passed for narrowed type
|
||||
TMetadataName extends AllMetadataName | undefined = undefined,
|
||||
> = Omit<
|
||||
TEntity,
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import { type AllMetadataName } from 'twenty-shared/metadata';
|
||||
|
||||
import { type AllFlatEntityTypesByMetadataName } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-types-by-metadata-name';
|
||||
|
||||
export type MetadataUniversalFlatEntity<T extends AllMetadataName> =
|
||||
AllFlatEntityTypesByMetadataName[T]['universalFlatEntity'];
|
||||
+10
-2
@@ -45,8 +45,16 @@ export const getFlatFieldMetadataMock = <T extends FieldMetadataType>(
|
||||
applicationId: faker.string.uuid(),
|
||||
relationTargetFieldMetadataId: null,
|
||||
relationTargetObjectMetadataId: null,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
__universal: {} as any,
|
||||
applicationUniversalIdentifier: faker.string.uuid(),
|
||||
objectMetadataUniversalIdentifier: faker.string.uuid(),
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
relationTargetFieldMetadataUniversalIdentifier: null,
|
||||
viewFilterUniversalIdentifiers: [],
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
kanbanAggregateOperationViewUniversalIdentifiers: [],
|
||||
calendarViewUniversalIdentifiers: [],
|
||||
mainGroupByFieldMetadataViewUniversalIdentifiers: [],
|
||||
universalSettings: null,
|
||||
...overrides,
|
||||
};
|
||||
};
|
||||
|
||||
+10
-1
@@ -65,6 +65,15 @@ export const getRelationTargetFlatFieldMetadataMock = ({
|
||||
defaultValue: null,
|
||||
options: null,
|
||||
applicationId: faker.string.uuid(),
|
||||
__universal: undefined,
|
||||
applicationUniversalIdentifier: faker.string.uuid(),
|
||||
objectMetadataUniversalIdentifier: faker.string.uuid(),
|
||||
relationTargetObjectMetadataUniversalIdentifier: faker.string.uuid(),
|
||||
relationTargetFieldMetadataUniversalIdentifier: faker.string.uuid(),
|
||||
viewFilterUniversalIdentifiers: [],
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
kanbanAggregateOperationViewUniversalIdentifiers: [],
|
||||
calendarViewUniversalIdentifiers: [],
|
||||
mainGroupByFieldMetadataViewUniversalIdentifiers: [],
|
||||
universalSettings: settings,
|
||||
};
|
||||
};
|
||||
|
||||
+53
-1
@@ -1,4 +1,4 @@
|
||||
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test suite Failure cases should fail when morphRelationsCreationPayload has different relation types 1`] = `
|
||||
{
|
||||
@@ -117,7 +117,9 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"flatFieldMetadatas": [
|
||||
{
|
||||
"applicationId": Any<String>,
|
||||
"applicationUniversalIdentifier": Any<String>,
|
||||
"calendarViewIds": [],
|
||||
"calendarViewUniversalIdentifiers": [],
|
||||
"createdAt": Any<String>,
|
||||
"defaultValue": null,
|
||||
"description": "new field description",
|
||||
@@ -131,14 +133,19 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"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",
|
||||
},
|
||||
@@ -146,14 +153,21 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"standardOverrides": null,
|
||||
"type": "MORPH_RELATION",
|
||||
"universalIdentifier": Any<String>,
|
||||
"universalSettings": {
|
||||
"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",
|
||||
@@ -167,14 +181,19 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"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",
|
||||
@@ -184,14 +203,23 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"standardOverrides": null,
|
||||
"type": "RELATION",
|
||||
"universalIdentifier": Any<String>,
|
||||
"universalSettings": {
|
||||
"joinColumnName": "petId",
|
||||
"onDelete": "SET_NULL",
|
||||
"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",
|
||||
@@ -205,14 +233,19 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"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",
|
||||
},
|
||||
@@ -220,14 +253,21 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"standardOverrides": null,
|
||||
"type": "MORPH_RELATION",
|
||||
"universalIdentifier": Any<String>,
|
||||
"universalSettings": {
|
||||
"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",
|
||||
@@ -241,14 +281,19 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"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",
|
||||
@@ -258,9 +303,16 @@ exports[`fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test su
|
||||
"standardOverrides": null,
|
||||
"type": "RELATION",
|
||||
"universalIdentifier": Any<String>,
|
||||
"universalSettings": {
|
||||
"joinColumnName": "companyId",
|
||||
"onDelete": "SET_NULL",
|
||||
"relationType": "MANY_TO_ONE",
|
||||
},
|
||||
"updatedAt": Any<String>,
|
||||
"viewFieldIds": [],
|
||||
"viewFieldUniversalIdentifiers": [],
|
||||
"viewFilterIds": [],
|
||||
"viewFilterUniversalIdentifiers": [],
|
||||
"workspaceId": Any<String>,
|
||||
},
|
||||
],
|
||||
|
||||
+38
-14
@@ -5,8 +5,11 @@ import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { createEmptyFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-flat-entity-maps.constant';
|
||||
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
|
||||
import { addFlatEntityToFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/add-flat-entity-to-flat-entity-maps-or-throw.util';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import {
|
||||
fromCreateFieldInputToFlatFieldMetadatasToCreate,
|
||||
type FromCreateFieldInputToFlatObjectMetadataArgs,
|
||||
@@ -16,6 +19,24 @@ import { FLAT_OBJECT_METADATA_MAPS_MOCKS } from 'src/engine/metadata-modules/fla
|
||||
import { PET_FLAT_OBJECT_MOCK } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/pet-flat-object.mock';
|
||||
import { ROCKET_FLAT_OBJECT_MOCK } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/rocket-flat-object.mock';
|
||||
|
||||
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,
|
||||
version: null,
|
||||
sourceType: 'local',
|
||||
sourcePath: '',
|
||||
logicFunctionLayerId: null,
|
||||
defaultLogicFunctionRoleId: null,
|
||||
defaultLogicFunctionRole: null,
|
||||
canBeUninstalled: false,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
deletedAt: null,
|
||||
};
|
||||
|
||||
const flatObjectMetadataMaps = [
|
||||
COMPANY_FLAT_OBJECT_MOCK,
|
||||
ROCKET_FLAT_OBJECT_MOCK,
|
||||
@@ -27,6 +48,9 @@ const flatObjectMetadataMaps = [
|
||||
});
|
||||
}, createEmptyFlatEntityMaps());
|
||||
|
||||
const emptyFlatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata> =
|
||||
createEmptyFlatEntityMaps();
|
||||
|
||||
type TestCase = EachTestingContext<{
|
||||
input: FromCreateFieldInputToFlatObjectMetadataArgs;
|
||||
expected: 'success' | 'fail';
|
||||
@@ -42,8 +66,7 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
'should create morph relation field metadata with valid input on rocket object to pet object',
|
||||
context: {
|
||||
input: {
|
||||
workspaceCustomApplicationId:
|
||||
'20202020-81ee-42da-a281-668632f32fe7',
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
createFieldInput: {
|
||||
name: 'newField',
|
||||
label: 'newFieldLabel',
|
||||
@@ -67,6 +90,7 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
},
|
||||
workspaceId: mockWorkspaceId,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps: emptyFlatFieldMetadataMaps,
|
||||
},
|
||||
expected: 'success',
|
||||
},
|
||||
@@ -102,8 +126,7 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
title: 'should fail when morphRelationsCreationPayload is missing',
|
||||
context: {
|
||||
input: {
|
||||
workspaceCustomApplicationId:
|
||||
'20202020-81ee-42da-a281-668632f32fe7',
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
createFieldInput: {
|
||||
name: 'newField',
|
||||
label: 'newFieldLabel',
|
||||
@@ -114,6 +137,7 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
},
|
||||
workspaceId: mockWorkspaceId,
|
||||
flatObjectMetadataMaps: FLAT_OBJECT_METADATA_MAPS_MOCKS,
|
||||
flatFieldMetadataMaps: emptyFlatFieldMetadataMaps,
|
||||
},
|
||||
expected: 'fail',
|
||||
},
|
||||
@@ -122,8 +146,7 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
title: 'should fail when morphRelationsCreationPayload is empty array',
|
||||
context: {
|
||||
input: {
|
||||
workspaceCustomApplicationId:
|
||||
'20202020-81ee-42da-a281-668632f32fe7',
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
createFieldInput: {
|
||||
name: 'newField',
|
||||
label: 'newFieldLabel',
|
||||
@@ -134,6 +157,7 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
},
|
||||
workspaceId: mockWorkspaceId,
|
||||
flatObjectMetadataMaps: FLAT_OBJECT_METADATA_MAPS_MOCKS,
|
||||
flatFieldMetadataMaps: emptyFlatFieldMetadataMaps,
|
||||
},
|
||||
expected: 'fail',
|
||||
},
|
||||
@@ -143,8 +167,7 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
'should fail when morphRelationsCreationPayload has different relation types',
|
||||
context: {
|
||||
input: {
|
||||
workspaceCustomApplicationId:
|
||||
'20202020-81ee-42da-a281-668632f32fe7',
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
createFieldInput: {
|
||||
name: 'newField',
|
||||
label: 'newFieldLabel',
|
||||
@@ -168,6 +191,7 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
},
|
||||
workspaceId: mockWorkspaceId,
|
||||
flatObjectMetadataMaps: FLAT_OBJECT_METADATA_MAPS_MOCKS,
|
||||
flatFieldMetadataMaps: emptyFlatFieldMetadataMaps,
|
||||
},
|
||||
expected: 'fail',
|
||||
},
|
||||
@@ -177,8 +201,7 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
'should fail when morphRelationsCreationPayload has several references to same object metadata',
|
||||
context: {
|
||||
input: {
|
||||
workspaceCustomApplicationId:
|
||||
'20202020-81ee-42da-a281-668632f32fe7',
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
createFieldInput: {
|
||||
name: 'newField',
|
||||
label: 'newFieldLabel',
|
||||
@@ -202,6 +225,7 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
},
|
||||
workspaceId: mockWorkspaceId,
|
||||
flatObjectMetadataMaps: FLAT_OBJECT_METADATA_MAPS_MOCKS,
|
||||
flatFieldMetadataMaps: emptyFlatFieldMetadataMaps,
|
||||
},
|
||||
expected: 'fail',
|
||||
},
|
||||
@@ -211,8 +235,7 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
'should fail when morphRelationsCreationPayload has invalid relation payload',
|
||||
context: {
|
||||
input: {
|
||||
workspaceCustomApplicationId:
|
||||
'20202020-81ee-42da-a281-668632f32fe7',
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
createFieldInput: {
|
||||
name: 'newField',
|
||||
label: 'newFieldLabel',
|
||||
@@ -229,6 +252,7 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
},
|
||||
workspaceId: mockWorkspaceId,
|
||||
flatObjectMetadataMaps: FLAT_OBJECT_METADATA_MAPS_MOCKS,
|
||||
flatFieldMetadataMaps: emptyFlatFieldMetadataMaps,
|
||||
},
|
||||
expected: 'fail',
|
||||
},
|
||||
@@ -237,8 +261,7 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
title: 'should fail when target object metadata is not found',
|
||||
context: {
|
||||
input: {
|
||||
workspaceCustomApplicationId:
|
||||
'20202020-81ee-42da-a281-668632f32fe7',
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
createFieldInput: {
|
||||
name: 'newField',
|
||||
label: 'newFieldLabel',
|
||||
@@ -256,6 +279,7 @@ describe('fromCreateFieldInputToFlatFieldMetadatasToCreate MORPH_RELATION test s
|
||||
},
|
||||
workspaceId: mockWorkspaceId,
|
||||
flatObjectMetadataMaps: FLAT_OBJECT_METADATA_MAPS_MOCKS,
|
||||
flatFieldMetadataMaps: emptyFlatFieldMetadataMaps,
|
||||
},
|
||||
expected: 'fail',
|
||||
},
|
||||
|
||||
+45
@@ -71,3 +71,48 @@ type FlatTransformationAssertions = [
|
||||
Expect<HasAllProperties<FlatFieldMetadata, DatePropertiesCastToString>>,
|
||||
Expect<HasAllProperties<FlatFieldMetadata, OneToManyRelationIdArrays>>,
|
||||
];
|
||||
|
||||
// Any narrowed flatFieldMetadata type should be assignable to non narrowed flatFieldMetadata
|
||||
type AbstractFlatFieldMetadata = FlatFieldMetadata<FieldMetadataType>;
|
||||
|
||||
const _assertion: Record<string, AbstractFlatFieldMetadata> = {
|
||||
// Primitive types
|
||||
uuid: {} as FlatFieldMetadata<FieldMetadataType.UUID>,
|
||||
text: {} as FlatFieldMetadata<FieldMetadataType.TEXT>,
|
||||
number: {} as FlatFieldMetadata<FieldMetadataType.NUMBER>,
|
||||
boolean: {} as FlatFieldMetadata<FieldMetadataType.BOOLEAN>,
|
||||
numeric: {} as FlatFieldMetadata<FieldMetadataType.NUMERIC>,
|
||||
position: {} as FlatFieldMetadata<FieldMetadataType.POSITION>,
|
||||
|
||||
// Date types
|
||||
date: {} as FlatFieldMetadata<FieldMetadataType.DATE>,
|
||||
dateTime: {} as FlatFieldMetadata<FieldMetadataType.DATE_TIME>,
|
||||
|
||||
// Complex types
|
||||
currency: {} as FlatFieldMetadata<FieldMetadataType.CURRENCY>,
|
||||
fullName: {} as FlatFieldMetadata<FieldMetadataType.FULL_NAME>,
|
||||
address: {} as FlatFieldMetadata<FieldMetadataType.ADDRESS>,
|
||||
links: {} as FlatFieldMetadata<FieldMetadataType.LINKS>,
|
||||
emails: {} as FlatFieldMetadata<FieldMetadataType.EMAILS>,
|
||||
phones: {} as FlatFieldMetadata<FieldMetadataType.PHONES>,
|
||||
actor: {} as FlatFieldMetadata<FieldMetadataType.ACTOR>,
|
||||
|
||||
// Select types
|
||||
rating: {} as FlatFieldMetadata<FieldMetadataType.RATING>,
|
||||
select: {} as FlatFieldMetadata<FieldMetadataType.SELECT>,
|
||||
multiSelect: {} as FlatFieldMetadata<FieldMetadataType.MULTI_SELECT>,
|
||||
|
||||
// JSON/Array types
|
||||
rawJson: {} as FlatFieldMetadata<FieldMetadataType.RAW_JSON>,
|
||||
array: {} as FlatFieldMetadata<FieldMetadataType.ARRAY>,
|
||||
richText: {} as FlatFieldMetadata<FieldMetadataType.RICH_TEXT>,
|
||||
richTextV2: {} as FlatFieldMetadata<FieldMetadataType.RICH_TEXT_V2>,
|
||||
|
||||
// Relation types
|
||||
relation: {} as FlatFieldMetadata<FieldMetadataType.RELATION>,
|
||||
morphRelation: {} as FlatFieldMetadata<FieldMetadataType.MORPH_RELATION>,
|
||||
|
||||
// Special types
|
||||
files: {} as FlatFieldMetadata<FieldMetadataType.FILES>,
|
||||
tsVector: {} as FlatFieldMetadata<FieldMetadataType.TS_VECTOR>,
|
||||
};
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
import { type FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
import { type FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';
|
||||
import { type FlatEntityFromV2 } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from-v2.type';
|
||||
|
||||
export type FlatFieldMetadata<T extends FieldMetadataType = FieldMetadataType> =
|
||||
FlatEntityFrom<
|
||||
FlatEntityFromV2<
|
||||
Omit<
|
||||
FieldMetadataEntity<T>,
|
||||
'relationTargetFieldMetadata' | 'relationTargetObjectMetadata'
|
||||
|
||||
+25
-8
@@ -6,6 +6,7 @@ import {
|
||||
RelationType,
|
||||
} from 'twenty-shared/types';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import {
|
||||
generateMorphOrRelationFlatFieldMetadataPair,
|
||||
type SourceTargetMorphOrRelationFlatFieldAndFlatIndex,
|
||||
@@ -13,6 +14,24 @@ import {
|
||||
import { COMPANY_FLAT_OBJECT_MOCK } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/company-flat-object.mock';
|
||||
import { PET_FLAT_OBJECT_MOCK } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/pet-flat-object.mock';
|
||||
|
||||
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,
|
||||
sourceType: 'local',
|
||||
sourcePath: '',
|
||||
logicFunctionLayerId: null,
|
||||
defaultLogicFunctionRoleId: null,
|
||||
defaultLogicFunctionRole: null,
|
||||
canBeUninstalled: false,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
deletedAt: null,
|
||||
};
|
||||
|
||||
type GenerateMorphOrRelationFlatFieldMetadataPairTestInput = Parameters<
|
||||
typeof generateMorphOrRelationFlatFieldMetadataPair
|
||||
>[0];
|
||||
@@ -28,8 +47,6 @@ type TestCase = EachTestingContext<{
|
||||
|
||||
describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () => {
|
||||
const mockWorkspaceId = '20202020-1c25-4d02-bf25-6aeccf7ea419';
|
||||
const mockWorkspaceCustomApplicationId =
|
||||
'20202020-81ee-42da-a281-668632f32fe7';
|
||||
|
||||
describe('Success cases', () => {
|
||||
const testCases: TestCase[] = [
|
||||
@@ -43,7 +60,7 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
|
||||
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
|
||||
sourceFlatObjectMetadataJoinColumnName: 'petId',
|
||||
workspaceId: mockWorkspaceId,
|
||||
workspaceCustomApplicationId: mockWorkspaceCustomApplicationId,
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
createFieldInput: {
|
||||
name: 'pets',
|
||||
label: 'Pets',
|
||||
@@ -79,7 +96,7 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
|
||||
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
|
||||
sourceFlatObjectMetadataJoinColumnName: 'petId',
|
||||
workspaceId: mockWorkspaceId,
|
||||
workspaceCustomApplicationId: mockWorkspaceCustomApplicationId,
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
createFieldInput: {
|
||||
name: 'pets',
|
||||
label: 'Pets',
|
||||
@@ -115,7 +132,7 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
|
||||
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
|
||||
sourceFlatObjectMetadataJoinColumnName: 'petId',
|
||||
workspaceId: mockWorkspaceId,
|
||||
workspaceCustomApplicationId: mockWorkspaceCustomApplicationId,
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
createFieldInput: {
|
||||
name: 'pets',
|
||||
label: 'Pets',
|
||||
@@ -151,7 +168,7 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
|
||||
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
|
||||
sourceFlatObjectMetadataJoinColumnName: 'targetPetId',
|
||||
workspaceId: mockWorkspaceId,
|
||||
workspaceCustomApplicationId: mockWorkspaceCustomApplicationId,
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
morphId: '20202020-9a2b-4c3d-a4e5-f6a7b8c9d0e1',
|
||||
createFieldInput: {
|
||||
name: 'targetPet',
|
||||
@@ -188,7 +205,7 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
|
||||
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
|
||||
sourceFlatObjectMetadataJoinColumnName: 'targetPetId',
|
||||
workspaceId: mockWorkspaceId,
|
||||
workspaceCustomApplicationId: mockWorkspaceCustomApplicationId,
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
morphId: '20202020-9a2b-4c3d-a4e5-f6a7b8c9d0e1',
|
||||
createFieldInput: {
|
||||
name: 'targetPet',
|
||||
@@ -225,7 +242,7 @@ describe('generate Morph Or Relation Flat Field Metadata Pair test suite', () =>
|
||||
targetFlatFieldMetadataType: FieldMetadataType.MORPH_RELATION,
|
||||
sourceFlatObjectMetadataJoinColumnName: 'targetPetId',
|
||||
workspaceId: mockWorkspaceId,
|
||||
workspaceCustomApplicationId: mockWorkspaceCustomApplicationId,
|
||||
flatApplication: MOCK_FLAT_APPLICATION,
|
||||
morphId: '20202020-9a2b-4c3d-a4e5-f6a7b8c9d0e1',
|
||||
createFieldInput: {
|
||||
name: 'targetPet',
|
||||
|
||||
+13
-3
@@ -4,17 +4,19 @@ import {
|
||||
} from 'twenty-shared/types';
|
||||
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 { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-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 { 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';
|
||||
|
||||
type ComputeFlatFieldToUpdateFromMorphRelationUpdatePayloadArgs = {
|
||||
workspaceCustomApplicationId: string;
|
||||
flatApplication: FlatApplication;
|
||||
flatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
|
||||
morphRelationsUpdatePayload?: RelationUpdatePayload[];
|
||||
fieldMetadataToUpdate: FlatFieldMetadata<FieldMetadataType.MORPH_RELATION>;
|
||||
@@ -22,7 +24,7 @@ type ComputeFlatFieldToUpdateFromMorphRelationUpdatePayloadArgs = {
|
||||
};
|
||||
|
||||
export const computeFlatFieldToUpdateFromMorphRelationUpdatePayload = ({
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
flatFieldMetadataMaps,
|
||||
morphRelationsUpdatePayload,
|
||||
fieldMetadataToUpdate,
|
||||
@@ -68,6 +70,13 @@ export const computeFlatFieldToUpdateFromMorphRelationUpdatePayload = ({
|
||||
const commonTargetFieldName = initialTargetFieldMetadata.name;
|
||||
const commonObjectMetadataId = initialTargetFieldMetadata.objectMetadataId;
|
||||
|
||||
const { junctionTargetFieldId } = extractJunctionTargetSettingsFromSettings(
|
||||
fieldMetadataToUpdate.settings,
|
||||
);
|
||||
const junctionTargetFlatFieldMetadata = isDefined(junctionTargetFieldId)
|
||||
? flatFieldMetadataMaps.byId[junctionTargetFieldId]
|
||||
: undefined;
|
||||
|
||||
morphRelationsUpdatePayload.forEach((morphRelationUpdatePayload) => {
|
||||
const { targetObjectMetadataId } = morphRelationUpdatePayload;
|
||||
|
||||
@@ -101,13 +110,14 @@ export const computeFlatFieldToUpdateFromMorphRelationUpdatePayload = ({
|
||||
targetFlatObjectMetadata: newTargetObjectMetadata,
|
||||
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
|
||||
workspaceId: fieldMetadataToUpdate.workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
sourceFlatObjectMetadataJoinColumnName:
|
||||
computeMorphOrRelationFieldJoinColumnName({
|
||||
name: computedMorphName,
|
||||
}),
|
||||
morphId: fieldMetadataToUpdate.morphId,
|
||||
targetFieldName: commonTargetFieldName,
|
||||
junctionTargetFlatFieldMetadata,
|
||||
});
|
||||
|
||||
flatFieldMetadatasToCreate.push(...flatFieldMetadatas);
|
||||
|
||||
+1
@@ -5,6 +5,7 @@ type JunctionTargetSettings = {
|
||||
junctionTargetFieldId?: string;
|
||||
};
|
||||
|
||||
// TODO refactor using either type predicate or FieldMetadataType discriminating union
|
||||
// Extracts junction target settings from untyped settings input
|
||||
// This function handles the boundary where settings come from external API input
|
||||
export const extractJunctionTargetSettingsFromSettings = (
|
||||
|
||||
+12
-6
@@ -10,6 +10,7 @@ import {
|
||||
} from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
|
||||
import { generateRatingOptions } from 'src/engine/metadata-modules/field-metadata/utils/generate-rating-optionts.util';
|
||||
@@ -25,14 +26,15 @@ import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-m
|
||||
export type FromCreateFieldInputToFlatObjectMetadataArgs = {
|
||||
createFieldInput: Omit<CreateFieldInput, 'workspaceId'>;
|
||||
workspaceId: string;
|
||||
workspaceCustomApplicationId: string;
|
||||
} & Pick<AllFlatEntityMaps, 'flatObjectMetadataMaps'>;
|
||||
flatApplication: FlatApplication;
|
||||
} & Pick<AllFlatEntityMaps, 'flatObjectMetadataMaps' | 'flatFieldMetadataMaps'>;
|
||||
|
||||
export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
|
||||
createFieldInput: rawCreateFieldInput,
|
||||
workspaceId,
|
||||
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
workspaceCustomApplicationId,
|
||||
flatFieldMetadataMaps: existingFlatFieldMetadataMaps,
|
||||
flatApplication,
|
||||
}: FromCreateFieldInputToFlatObjectMetadataArgs): Promise<
|
||||
FieldInputTranspilationResult<{
|
||||
flatFieldMetadatas: FlatFieldMetadata[];
|
||||
@@ -77,7 +79,9 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
|
||||
createFieldInput,
|
||||
workspaceId,
|
||||
fieldMetadataId,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
objectMetadataUniversalIdentifier:
|
||||
parentFlatObjectMetadata.universalIdentifier,
|
||||
});
|
||||
|
||||
switch (createFieldInput.type) {
|
||||
@@ -88,21 +92,23 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
|
||||
type: createFieldInput.type,
|
||||
},
|
||||
existingFlatObjectMetadataMaps,
|
||||
existingFlatFieldMetadataMaps,
|
||||
sourceFlatObjectMetadata: parentFlatObjectMetadata,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
});
|
||||
}
|
||||
case FieldMetadataType.RELATION: {
|
||||
return await fromRelationCreateFieldInputToFlatFieldMetadatas({
|
||||
existingFlatObjectMetadataMaps,
|
||||
existingFlatFieldMetadataMaps,
|
||||
sourceFlatObjectMetadata: parentFlatObjectMetadata,
|
||||
createFieldInput: {
|
||||
...createFieldInput,
|
||||
type: createFieldInput.type,
|
||||
},
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
});
|
||||
}
|
||||
case FieldMetadataType.RATING: {
|
||||
|
||||
+19
-25
@@ -106,33 +106,27 @@ export const fromFieldMetadataEntityToFlatFieldMetadata = ({
|
||||
[],
|
||||
viewFieldIds: fieldMetadataEntity.viewFields.map(({ id }) => id),
|
||||
viewFilterIds: fieldMetadataEntity.viewFilters.map(({ id }) => id),
|
||||
__universal: {
|
||||
universalIdentifier: fieldMetadataWithoutRelations.universalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier,
|
||||
relationTargetFieldMetadataUniversalIdentifier,
|
||||
viewFieldUniversalIdentifiers: fieldMetadataEntity.viewFields.map(
|
||||
applicationUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier,
|
||||
relationTargetFieldMetadataUniversalIdentifier,
|
||||
viewFieldUniversalIdentifiers: fieldMetadataEntity.viewFields.map(
|
||||
({ universalIdentifier }) => universalIdentifier,
|
||||
),
|
||||
viewFilterUniversalIdentifiers: fieldMetadataEntity.viewFilters.map(
|
||||
({ universalIdentifier }) => universalIdentifier,
|
||||
),
|
||||
kanbanAggregateOperationViewUniversalIdentifiers:
|
||||
fieldMetadataEntity.kanbanAggregateOperationViews.map(
|
||||
({ universalIdentifier }) => universalIdentifier,
|
||||
),
|
||||
viewFilterUniversalIdentifiers: fieldMetadataEntity.viewFilters.map(
|
||||
calendarViewUniversalIdentifiers: fieldMetadataEntity.calendarViews.map(
|
||||
({ universalIdentifier }) => universalIdentifier,
|
||||
),
|
||||
mainGroupByFieldMetadataViewUniversalIdentifiers:
|
||||
fieldMetadataEntity.mainGroupByFieldMetadataViews?.map(
|
||||
({ universalIdentifier }) => universalIdentifier,
|
||||
),
|
||||
kanbanAggregateOperationViewUniversalIdentifiers:
|
||||
fieldMetadataEntity.kanbanAggregateOperationViews.map(
|
||||
({ universalIdentifier }) => universalIdentifier,
|
||||
),
|
||||
calendarViewUniversalIdentifiers: fieldMetadataEntity.calendarViews.map(
|
||||
({ universalIdentifier }) => universalIdentifier,
|
||||
),
|
||||
mainGroupByFieldMetadataViewUniversalIdentifiers:
|
||||
fieldMetadataEntity.mainGroupByFieldMetadataViews?.map(
|
||||
({ universalIdentifier }) => universalIdentifier,
|
||||
) ?? [],
|
||||
settings: settingsWithUniversalIdentifiers,
|
||||
defaultValue: fieldMetadataWithoutRelations.defaultValue,
|
||||
options: fieldMetadataWithoutRelations.options,
|
||||
standardOverrides: fieldMetadataWithoutRelations.standardOverrides,
|
||||
},
|
||||
) ?? [],
|
||||
universalSettings: settingsWithUniversalIdentifiers,
|
||||
};
|
||||
};
|
||||
|
||||
+15
-3
@@ -3,12 +3,14 @@ import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { computeMorphRelationFieldName, isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
|
||||
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 { 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 } 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';
|
||||
@@ -19,16 +21,18 @@ type FromMorphRelationCreateFieldInputToFlatFieldMetadatasArgs = {
|
||||
type: FieldMetadataType.MORPH_RELATION;
|
||||
};
|
||||
existingFlatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
|
||||
existingFlatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
|
||||
sourceFlatObjectMetadata: FlatObjectMetadata;
|
||||
workspaceId: string;
|
||||
workspaceCustomApplicationId: string;
|
||||
flatApplication: FlatApplication;
|
||||
};
|
||||
export const fromMorphRelationCreateFieldInputToFlatFieldMetadatas = async ({
|
||||
createFieldInput,
|
||||
existingFlatObjectMetadataMaps,
|
||||
existingFlatFieldMetadataMaps,
|
||||
sourceFlatObjectMetadata,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
}: FromMorphRelationCreateFieldInputToFlatFieldMetadatasArgs): Promise<
|
||||
FieldInputTranspilationResult<{
|
||||
flatFieldMetadatas: FlatFieldMetadata[];
|
||||
@@ -66,6 +70,13 @@ export const fromMorphRelationCreateFieldInputToFlatFieldMetadatas = async ({
|
||||
return morphRelationCreationPayloadValidation;
|
||||
}
|
||||
|
||||
const { junctionTargetFieldId } = extractJunctionTargetSettingsFromSettings(
|
||||
createFieldInput.settings,
|
||||
);
|
||||
const junctionTargetFlatFieldMetadata = isDefined(junctionTargetFieldId)
|
||||
? existingFlatFieldMetadataMaps.byId[junctionTargetFieldId]
|
||||
: undefined;
|
||||
|
||||
const morphRelationCreationPayload =
|
||||
morphRelationCreationPayloadValidation.result;
|
||||
const morphId = v4();
|
||||
@@ -95,7 +106,8 @@ export const fromMorphRelationCreateFieldInputToFlatFieldMetadatas = async ({
|
||||
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
|
||||
workspaceId,
|
||||
morphId,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
junctionTargetFlatFieldMetadata,
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
+16
-3
@@ -2,11 +2,14 @@ import { msg } from '@lingui/core/macro';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
import { FieldMetadataExceptionCode } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
|
||||
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 { 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,
|
||||
@@ -19,16 +22,18 @@ type FromRelationCreateFieldInputToFlatFieldMetadataArgs = {
|
||||
type: FieldMetadataType.RELATION;
|
||||
};
|
||||
existingFlatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
|
||||
existingFlatFieldMetadataMaps: FlatEntityMaps<FlatFieldMetadata>;
|
||||
sourceFlatObjectMetadata: FlatObjectMetadata;
|
||||
workspaceId: string;
|
||||
workspaceCustomApplicationId: string;
|
||||
flatApplication: FlatApplication;
|
||||
};
|
||||
export const fromRelationCreateFieldInputToFlatFieldMetadatas = async ({
|
||||
existingFlatObjectMetadataMaps,
|
||||
existingFlatFieldMetadataMaps,
|
||||
sourceFlatObjectMetadata,
|
||||
createFieldInput,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
}: FromRelationCreateFieldInputToFlatFieldMetadataArgs): Promise<
|
||||
FieldInputTranspilationResult<SourceTargetMorphOrRelationFlatFieldAndFlatIndex>
|
||||
> => {
|
||||
@@ -59,6 +64,13 @@ export const fromRelationCreateFieldInputToFlatFieldMetadatas = async ({
|
||||
const { relationCreationPayload, targetFlatObjectMetadata } =
|
||||
relationValidationResult.result;
|
||||
|
||||
const { junctionTargetFieldId } = extractJunctionTargetSettingsFromSettings(
|
||||
createFieldInput.settings,
|
||||
);
|
||||
const junctionTargetFlatFieldMetadata = isDefined(junctionTargetFieldId)
|
||||
? existingFlatFieldMetadataMaps.byId[junctionTargetFieldId]
|
||||
: undefined;
|
||||
|
||||
const generateResult = generateMorphOrRelationFlatFieldMetadataPair({
|
||||
createFieldInput: {
|
||||
...createFieldInput,
|
||||
@@ -72,7 +84,8 @@ export const fromRelationCreateFieldInputToFlatFieldMetadatas = async ({
|
||||
targetFlatObjectMetadata,
|
||||
targetFlatFieldMetadataType: FieldMetadataType.RELATION,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
junctionTargetFlatFieldMetadata,
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
+5
-4
@@ -5,6 +5,7 @@ import {
|
||||
isDefined,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type UpdateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input';
|
||||
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';
|
||||
@@ -23,7 +24,7 @@ import { isFlatFieldMetadataOfType } from 'src/engine/metadata-modules/flat-fiel
|
||||
|
||||
type FromUpdateFieldInputToFlatFieldMetadataArgs = {
|
||||
updateFieldInput: UpdateFieldInput;
|
||||
workspaceCustomApplicationId: string;
|
||||
flatApplication: FlatApplication;
|
||||
isSystemBuild: boolean;
|
||||
} & Pick<
|
||||
AllFlatEntityMaps,
|
||||
@@ -41,7 +42,7 @@ type FlatFieldMetadataAndIndexToUpdate = {
|
||||
flatFieldMetadatasToCreate: FlatFieldMetadata[];
|
||||
} & FlatFieldMetadataUpdateSideEffects;
|
||||
export const fromUpdateFieldInputToFlatFieldMetadata = ({
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
flatIndexMaps,
|
||||
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
@@ -109,7 +110,7 @@ export const fromUpdateFieldInputToFlatFieldMetadata = ({
|
||||
FieldMetadataType.MORPH_RELATION,
|
||||
)
|
||||
? computeFlatFieldToUpdateFromMorphRelationUpdatePayload({
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
morphRelationsUpdatePayload:
|
||||
rawUpdateFieldInput?.morphRelationsUpdatePayload,
|
||||
flatFieldMetadataMaps: flatFieldMetadataMaps,
|
||||
@@ -149,7 +150,7 @@ export const fromUpdateFieldInputToFlatFieldMetadata = ({
|
||||
toFlatFieldMetadata,
|
||||
flatViewMaps,
|
||||
flatViewFieldMaps,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
});
|
||||
|
||||
if (sideEffectResult.status === 'fail') {
|
||||
|
||||
+73
-31
@@ -6,11 +6,11 @@ import {
|
||||
} from 'twenty-shared/types';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { type CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
import { type MorphOrRelationFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/morph-or-relation-field-metadata-type.type';
|
||||
import { computeMorphOrRelationFieldJoinColumnName } from 'src/engine/metadata-modules/field-metadata/utils/compute-morph-or-relation-field-join-column-name.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 { 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';
|
||||
@@ -22,23 +22,39 @@ type ComputeFieldMetadataRelationSettingsForRelationTypeArgs = {
|
||||
relationType: RelationType;
|
||||
joinColumnName: string;
|
||||
junctionTargetFieldId?: string;
|
||||
junctionTargetFieldUniversalIdentifier?: string;
|
||||
};
|
||||
|
||||
const computeFieldMetadataRelationSettingsForRelationType = ({
|
||||
relationType,
|
||||
joinColumnName,
|
||||
junctionTargetFieldId,
|
||||
}: ComputeFieldMetadataRelationSettingsForRelationTypeArgs) => {
|
||||
junctionTargetFieldUniversalIdentifier,
|
||||
}: ComputeFieldMetadataRelationSettingsForRelationTypeArgs): Pick<
|
||||
FlatFieldMetadata<MorphOrRelationFieldMetadataType>,
|
||||
'settings' | 'universalSettings'
|
||||
> => {
|
||||
if (relationType === RelationType.MANY_TO_ONE) {
|
||||
return {
|
||||
const settings = {
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
joinColumnName,
|
||||
};
|
||||
|
||||
return { settings, universalSettings: settings };
|
||||
}
|
||||
|
||||
return {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
...(junctionTargetFieldId && { junctionTargetFieldId }),
|
||||
settings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
...(junctionTargetFieldId && { junctionTargetFieldId }),
|
||||
},
|
||||
universalSettings: {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
...(junctionTargetFieldUniversalIdentifier && {
|
||||
junctionTargetFieldUniversalIdentifier,
|
||||
}),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -53,8 +69,9 @@ type GenerateMorphOrRelationFlatFieldMetadataPairArgs = {
|
||||
> & { type: MorphOrRelationFieldMetadataType };
|
||||
workspaceId: string;
|
||||
morphId?: string | null;
|
||||
workspaceCustomApplicationId: string;
|
||||
flatApplication: FlatApplication;
|
||||
targetFieldName?: string;
|
||||
junctionTargetFlatFieldMetadata?: FlatFieldMetadata;
|
||||
};
|
||||
|
||||
export type SourceTargetMorphOrRelationFlatFieldAndFlatIndex = {
|
||||
@@ -68,27 +85,30 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({
|
||||
targetFlatObjectMetadata,
|
||||
targetFlatFieldMetadataType,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
sourceFlatObjectMetadataJoinColumnName,
|
||||
morphId = null,
|
||||
targetFieldName,
|
||||
junctionTargetFlatFieldMetadata,
|
||||
}: GenerateMorphOrRelationFlatFieldMetadataPairArgs): SourceTargetMorphOrRelationFlatFieldAndFlatIndex => {
|
||||
const sourceFlatFieldMetadataType = createFieldInput.type;
|
||||
|
||||
const { relationCreationPayload } = createFieldInput;
|
||||
|
||||
const { junctionTargetFieldId } = extractJunctionTargetSettingsFromSettings(
|
||||
createFieldInput.settings,
|
||||
);
|
||||
|
||||
const sourceFlatFieldMetadataSettings =
|
||||
computeFieldMetadataRelationSettingsForRelationType({
|
||||
joinColumnName: sourceFlatObjectMetadataJoinColumnName,
|
||||
relationType: relationCreationPayload.type,
|
||||
junctionTargetFieldId,
|
||||
});
|
||||
const {
|
||||
settings: sourceFlatFieldMetadataSettings,
|
||||
universalSettings: sourceFlatFieldMetadataUniversalSettings,
|
||||
} = computeFieldMetadataRelationSettingsForRelationType({
|
||||
joinColumnName: sourceFlatObjectMetadataJoinColumnName,
|
||||
relationType: relationCreationPayload.type,
|
||||
junctionTargetFieldId: junctionTargetFlatFieldMetadata?.id,
|
||||
junctionTargetFieldUniversalIdentifier:
|
||||
junctionTargetFlatFieldMetadata?.universalIdentifier,
|
||||
});
|
||||
const targetRelationTargetFieldMetadataId = v4();
|
||||
const sourceRelationTargetFieldMetadataId = v4();
|
||||
const sourceFieldUniversalIdentifier = v4();
|
||||
const targetFieldUniversalIdentifier = v4();
|
||||
|
||||
const defaultDescriptionFromField =
|
||||
buildDescriptionForRelationFieldMetadataOnFromField({
|
||||
@@ -105,10 +125,15 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({
|
||||
'flatRelationTargetFieldMetadata'
|
||||
> = {
|
||||
...getDefaultFlatFieldMetadata({
|
||||
createFieldInput,
|
||||
createFieldInput: {
|
||||
...createFieldInput,
|
||||
universalIdentifier: sourceFieldUniversalIdentifier,
|
||||
},
|
||||
workspaceId,
|
||||
fieldMetadataId: sourceRelationTargetFieldMetadataId,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
objectMetadataUniversalIdentifier:
|
||||
sourceFlatObjectMetadata.universalIdentifier,
|
||||
}),
|
||||
morphId:
|
||||
sourceFlatFieldMetadataType === FieldMetadataType.MORPH_RELATION
|
||||
@@ -121,9 +146,14 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({
|
||||
createFieldInput.description ?? defaultDescriptionFromField.description,
|
||||
defaultValue: null,
|
||||
settings: sourceFlatFieldMetadataSettings,
|
||||
universalSettings: sourceFlatFieldMetadataUniversalSettings,
|
||||
options: null,
|
||||
relationTargetFieldMetadataId: targetRelationTargetFieldMetadataId,
|
||||
relationTargetObjectMetadataId: targetFlatObjectMetadata.id,
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
targetFlatObjectMetadata.universalIdentifier,
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
targetFieldUniversalIdentifier,
|
||||
};
|
||||
|
||||
const targetCreateFieldInput: CreateFieldInput = {
|
||||
@@ -141,25 +171,32 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({
|
||||
workspaceId,
|
||||
isSystem: createFieldInput.isSystem ?? false,
|
||||
};
|
||||
const targetFlatFieldMetadataSettings =
|
||||
computeFieldMetadataRelationSettingsForRelationType({
|
||||
joinColumnName: computeMorphOrRelationFieldJoinColumnName({
|
||||
name: targetCreateFieldInput.name,
|
||||
}),
|
||||
relationType:
|
||||
relationCreationPayload.type === RelationType.ONE_TO_MANY
|
||||
? RelationType.MANY_TO_ONE
|
||||
: RelationType.ONE_TO_MANY,
|
||||
});
|
||||
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 targetFlatFieldMetadata: FlatFieldMetadata<
|
||||
typeof targetFlatFieldMetadataType
|
||||
> = {
|
||||
...getDefaultFlatFieldMetadata({
|
||||
createFieldInput: targetCreateFieldInput,
|
||||
createFieldInput: {
|
||||
...targetCreateFieldInput,
|
||||
universalIdentifier: targetFieldUniversalIdentifier,
|
||||
},
|
||||
workspaceId,
|
||||
fieldMetadataId: targetRelationTargetFieldMetadataId,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
objectMetadataUniversalIdentifier:
|
||||
targetFlatObjectMetadata.universalIdentifier,
|
||||
}),
|
||||
morphId:
|
||||
targetFlatFieldMetadataType === FieldMetadataType.MORPH_RELATION
|
||||
@@ -168,9 +205,14 @@ export const generateMorphOrRelationFlatFieldMetadataPair = ({
|
||||
type: targetFlatFieldMetadataType,
|
||||
defaultValue: null,
|
||||
settings: targetFlatFieldMetadataSettings,
|
||||
universalSettings: targetFlatFieldMetadataUniversalSettings,
|
||||
options: null,
|
||||
relationTargetFieldMetadataId: sourceRelationTargetFieldMetadataId,
|
||||
relationTargetObjectMetadataId: sourceFlatObjectMetadata.id,
|
||||
relationTargetObjectMetadataUniversalIdentifier:
|
||||
sourceFlatObjectMetadata.universalIdentifier,
|
||||
relationTargetFieldMetadataUniversalIdentifier:
|
||||
sourceFieldUniversalIdentifier,
|
||||
};
|
||||
|
||||
const indexMetadata: FlatIndexMetadata = generateIndexForFlatFieldMetadata({
|
||||
|
||||
+16
-4
@@ -1,6 +1,7 @@
|
||||
import { extractAndSanitizeObjectStringFields } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
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';
|
||||
@@ -10,13 +11,15 @@ type GetDefaultFlatFieldMetadataArgs = {
|
||||
fieldMetadataId: string;
|
||||
createFieldInput: Omit<CreateFieldInput, 'workspaceId'>;
|
||||
workspaceId: string;
|
||||
workspaceCustomApplicationId: string;
|
||||
flatApplication: FlatApplication;
|
||||
objectMetadataUniversalIdentifier: string;
|
||||
};
|
||||
export const getDefaultFlatFieldMetadata = ({
|
||||
createFieldInput,
|
||||
fieldMetadataId,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
objectMetadataUniversalIdentifier,
|
||||
}: GetDefaultFlatFieldMetadataArgs) => {
|
||||
const { defaultValue, settings } = extractAndSanitizeObjectStringFields(
|
||||
createFieldInput,
|
||||
@@ -58,9 +61,18 @@ export const getDefaultFlatFieldMetadata = ({
|
||||
updatedAt: createdAt,
|
||||
isUIReadOnly: createFieldInput.isUIReadOnly ?? false,
|
||||
morphId: null,
|
||||
applicationId:
|
||||
createFieldInput.applicationId ?? workspaceCustomApplicationId,
|
||||
applicationId: flatApplication.id,
|
||||
viewFilterIds: [],
|
||||
kanbanAggregateOperationViewIds: [],
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
relationTargetFieldMetadataUniversalIdentifier: null,
|
||||
viewFilterUniversalIdentifiers: [],
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
kanbanAggregateOperationViewUniversalIdentifiers: [],
|
||||
calendarViewUniversalIdentifiers: [],
|
||||
mainGroupByFieldMetadataViewUniversalIdentifiers: [],
|
||||
universalSettings: null,
|
||||
} as const satisfies FlatFieldMetadata;
|
||||
};
|
||||
|
||||
+4
-3
@@ -1,6 +1,7 @@
|
||||
import { type FromTo } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
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 { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { type FieldInputTranspilationResult } from 'src/engine/metadata-modules/flat-field-metadata/types/field-input-transpilation-result.type';
|
||||
@@ -41,7 +42,7 @@ type HandleFlatFieldMetadataUpdateSideEffectArgs = FromTo<
|
||||
| 'flatViewMaps'
|
||||
| 'flatViewFieldMaps'
|
||||
> & {
|
||||
workspaceCustomApplicationId: string;
|
||||
flatApplication: FlatApplication;
|
||||
};
|
||||
|
||||
export const FLAT_FIELD_METADATA_UPDATE_EMPTY_SIDE_EFFECTS: FlatFieldMetadataUpdateSideEffects =
|
||||
@@ -70,7 +71,7 @@ export const handleFlatFieldMetadataUpdateSideEffect = ({
|
||||
flatViewGroupMaps,
|
||||
flatViewMaps,
|
||||
flatViewFieldMaps,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
}: HandleFlatFieldMetadataUpdateSideEffectArgs): FieldInputTranspilationResult<FlatFieldMetadataUpdateSideEffects> => {
|
||||
const sideEffectResult = structuredClone(
|
||||
FLAT_FIELD_METADATA_UPDATE_EMPTY_SIDE_EFFECTS,
|
||||
@@ -130,7 +131,7 @@ export const handleFlatFieldMetadataUpdateSideEffect = ({
|
||||
flatIndexMaps,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
});
|
||||
|
||||
if (indexChangesSideEffectResult.status === 'fail') {
|
||||
|
||||
+7
-6
@@ -2,6 +2,7 @@ import { msg } from '@lingui/core/macro';
|
||||
import { type FromTo } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
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';
|
||||
@@ -28,7 +29,7 @@ type FromToFlatFieldMetadataAndFlatEntityMaps = FromTo<
|
||||
AllFlatEntityMaps,
|
||||
'flatObjectMetadataMaps' | 'flatFieldMetadataMaps' | 'flatIndexMaps'
|
||||
> & {
|
||||
workspaceCustomApplicationId: string;
|
||||
flatApplication: FlatApplication;
|
||||
};
|
||||
const FIELD_METADATA_UPDATE_INDEX_SIDE_EFFECT: FieldMetadataUpdateIndexSideEffect =
|
||||
{
|
||||
@@ -43,7 +44,7 @@ export const handleIndexChangesDuringFieldUpdate = ({
|
||||
flatIndexMaps,
|
||||
flatObjectMetadataMaps,
|
||||
flatFieldMetadataMaps,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
}: FromToFlatFieldMetadataAndFlatEntityMaps): FieldInputTranspilationResult<FieldMetadataUpdateIndexSideEffect> => {
|
||||
if (
|
||||
!hasIndexRelevantChanges({
|
||||
@@ -81,7 +82,7 @@ export const handleIndexChangesDuringFieldUpdate = ({
|
||||
relatedIndexes,
|
||||
flatObjectMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -127,13 +128,13 @@ const handleExistingIndexes = ({
|
||||
relatedIndexes,
|
||||
flatObjectMetadata,
|
||||
flatFieldMetadataMaps,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
}: {
|
||||
relatedIndexes: FlatIndexMetadata[];
|
||||
flatObjectMetadata: FlatObjectMetadata;
|
||||
flatFieldMetadataMaps: AllFlatEntityMaps['flatFieldMetadataMaps'];
|
||||
} & FromTo<FlatFieldMetadata, 'flatFieldMetadata'> & {
|
||||
workspaceCustomApplicationId: string;
|
||||
flatApplication: FlatApplication;
|
||||
}): FieldInputTranspilationResult<FieldMetadataUpdateIndexSideEffect> => {
|
||||
if (
|
||||
toFlatFieldMetadata.isUnique === false &&
|
||||
@@ -155,7 +156,7 @@ const handleExistingIndexes = ({
|
||||
if (
|
||||
isDefined(uniqueIndexToDelete) &&
|
||||
((isDefined(uniqueIndexToDelete.applicationId) &&
|
||||
uniqueIndexToDelete.applicationId !== workspaceCustomApplicationId) ||
|
||||
uniqueIndexToDelete.applicationId !== flatApplication.id) ||
|
||||
!uniqueIndexToDelete.isCustom)
|
||||
) {
|
||||
return {
|
||||
|
||||
+16
-3
@@ -10,6 +10,11 @@ export const getFlatObjectMetadataMock = (
|
||||
overrides: FlatObjectMetadataOverrides,
|
||||
): FlatObjectMetadata => {
|
||||
const createdAt = '2024-01-01T00:00:00.000Z';
|
||||
const applicationId = overrides.applicationId ?? faker.string.uuid();
|
||||
const labelIdentifierFieldMetadataId =
|
||||
overrides.labelIdentifierFieldMetadataId ?? faker.string.uuid();
|
||||
const imageIdentifierFieldMetadataId =
|
||||
overrides.imageIdentifierFieldMetadataId ?? faker.string.uuid();
|
||||
|
||||
return {
|
||||
viewIds: [],
|
||||
@@ -18,7 +23,7 @@ export const getFlatObjectMetadataMock = (
|
||||
description: 'default flat object metadata description',
|
||||
icon: 'icon',
|
||||
id: faker.string.uuid(),
|
||||
imageIdentifierFieldMetadataId: faker.string.uuid(),
|
||||
imageIdentifierFieldMetadataId,
|
||||
isActive: true,
|
||||
isAuditLogged: true,
|
||||
isCustom: true,
|
||||
@@ -27,20 +32,28 @@ export const getFlatObjectMetadataMock = (
|
||||
isSearchable: true,
|
||||
isSystem: false,
|
||||
isUIReadOnly: false,
|
||||
labelIdentifierFieldMetadataId: faker.string.uuid(),
|
||||
labelIdentifierFieldMetadataId,
|
||||
labelPlural: 'default flat object metadata label plural',
|
||||
labelSingular: 'default flat object metadata label singular',
|
||||
namePlural: 'defaultflatObjectMetadataNamePlural',
|
||||
nameSingular: 'defaultflatObjectMetadataNameSingular',
|
||||
shortcut: 'shortcut',
|
||||
standardId: null,
|
||||
applicationId: faker.string.uuid(),
|
||||
applicationId,
|
||||
standardOverrides: null,
|
||||
targetTableName: '',
|
||||
workspaceId: faker.string.uuid(),
|
||||
createdAt,
|
||||
updatedAt: createdAt,
|
||||
duplicateCriteria: null,
|
||||
applicationUniversalIdentifier: applicationId,
|
||||
fieldUniversalIdentifiers: [],
|
||||
viewUniversalIdentifiers: [],
|
||||
indexMetadataUniversalIdentifiers: [],
|
||||
labelIdentifierFieldMetadataUniversalIdentifier:
|
||||
labelIdentifierFieldMetadataId,
|
||||
imageIdentifierFieldMetadataUniversalIdentifier:
|
||||
imageIdentifierFieldMetadataId,
|
||||
...overrides,
|
||||
};
|
||||
};
|
||||
|
||||
+7
-8
@@ -1,13 +1,12 @@
|
||||
import { type FlatEntityFrom } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from.type';
|
||||
import { type FlatEntityFromV2 } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-from-v2.type';
|
||||
import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';
|
||||
|
||||
type BaseFlatObjectMetadata = FlatEntityFrom<
|
||||
type BaseFlatObjectMetadata = FlatEntityFromV2<
|
||||
Omit<ObjectMetadataEntity, 'targetRelationFields' | 'dataSourceId'>
|
||||
>;
|
||||
export type FlatObjectMetadata = Omit<BaseFlatObjectMetadata, '__universal'> & {
|
||||
__universal?: BaseFlatObjectMetadata['__universal'] & {
|
||||
// TODO remove once https://github.com/twentyhq/core-team-issues/issues/2172 has been resolved
|
||||
labelIdentifierFieldMetadataUniversalIdentifier: string | null;
|
||||
imageIdentifierFieldMetadataUniversalIdentifier: string | null;
|
||||
};
|
||||
export type FlatObjectMetadata = BaseFlatObjectMetadata & {
|
||||
// NOTE: below fields are not reflected on the final UniversalFlatEntity either they should we should define a common source
|
||||
// TODO remove once https://github.com/twentyhq/core-team-issues/issues/2172 has been resolved
|
||||
labelIdentifierFieldMetadataUniversalIdentifier: string | null;
|
||||
imageIdentifierFieldMetadataUniversalIdentifier: string | null;
|
||||
};
|
||||
|
||||
+20
-9
@@ -6,6 +6,7 @@ import { v4 } from 'uuid';
|
||||
|
||||
import { type FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface';
|
||||
|
||||
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';
|
||||
@@ -19,14 +20,14 @@ type FromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCreateArgs
|
||||
{
|
||||
createObjectInput: CreateObjectInput;
|
||||
workspaceId: string;
|
||||
workspaceCustomApplicationId: string;
|
||||
flatApplication: FlatApplication;
|
||||
existingFeatureFlagsMap: FeatureFlagMap;
|
||||
} & Pick<AllFlatEntityMaps, 'flatObjectMetadataMaps'>;
|
||||
export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCreate =
|
||||
({
|
||||
createObjectInput: rawCreateObjectInput,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
existingFeatureFlagsMap,
|
||||
}: FromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCreateArgs): {
|
||||
@@ -50,11 +51,14 @@ export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCre
|
||||
);
|
||||
|
||||
const objectMetadataId = v4();
|
||||
const universalIdentifier = createObjectInput.universalIdentifier ?? v4();
|
||||
const defaultFlatFieldForCustomObjectMaps =
|
||||
buildDefaultFlatFieldMetadatasForCustomObject({
|
||||
flatObjectMetadata: {
|
||||
id: objectMetadataId,
|
||||
applicationId: workspaceCustomApplicationId,
|
||||
applicationId: flatApplication.id,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
universalIdentifier,
|
||||
},
|
||||
workspaceId,
|
||||
skipNameField: createObjectInput.skipNameField,
|
||||
@@ -62,11 +66,12 @@ export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCre
|
||||
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 as
|
||||
| FlatFieldMetadata
|
||||
| undefined;
|
||||
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: [],
|
||||
@@ -95,10 +100,16 @@ export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCre
|
||||
shortcut: createObjectInput.shortcut ?? null,
|
||||
standardId: createObjectInput.standardId ?? null,
|
||||
standardOverrides: null,
|
||||
applicationId: workspaceCustomApplicationId,
|
||||
universalIdentifier: createObjectInput.universalIdentifier ?? v4(),
|
||||
applicationId: flatApplication.id,
|
||||
universalIdentifier,
|
||||
targetTableName: 'DEPRECATED',
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier: flatApplication.universalIdentifier,
|
||||
fieldUniversalIdentifiers: [],
|
||||
viewUniversalIdentifiers: [],
|
||||
indexMetadataUniversalIdentifiers: [],
|
||||
labelIdentifierFieldMetadataUniversalIdentifier,
|
||||
imageIdentifierFieldMetadataUniversalIdentifier: null,
|
||||
};
|
||||
|
||||
const {
|
||||
@@ -108,7 +119,7 @@ export const fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCre
|
||||
existingFlatObjectMetadataMaps,
|
||||
sourceFlatObjectMetadata: flatObjectMetadataToCreate,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
existingFeatureFlagsMap,
|
||||
});
|
||||
|
||||
|
||||
+12
-19
@@ -76,24 +76,17 @@ export const fromObjectMetadataEntityToFlatObjectMetadata = ({
|
||||
viewIds: objectMetadataEntity.views.map(({ id }) => id),
|
||||
indexMetadataIds: objectMetadataEntity.indexMetadatas.map(({ id }) => id),
|
||||
fieldIds: objectMetadataEntity.fields.map(({ id }) => id),
|
||||
__universal: {
|
||||
universalIdentifier:
|
||||
objectMetadataEntityWithoutRelations.universalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
labelIdentifierFieldMetadataUniversalIdentifier,
|
||||
imageIdentifierFieldMetadataUniversalIdentifier,
|
||||
fieldUniversalIdentifiers: objectMetadataEntity.fields.map(
|
||||
({ universalIdentifier }) => universalIdentifier,
|
||||
),
|
||||
indexMetadataUniversalIdentifiers:
|
||||
objectMetadataEntity.indexMetadatas.map(
|
||||
({ universalIdentifier }) => universalIdentifier,
|
||||
),
|
||||
viewUniversalIdentifiers: objectMetadataEntity.views.map(
|
||||
({ universalIdentifier }) => universalIdentifier,
|
||||
),
|
||||
standardOverrides: objectMetadataEntityWithoutRelations.standardOverrides,
|
||||
duplicateCriteria: objectMetadataEntityWithoutRelations.duplicateCriteria,
|
||||
},
|
||||
applicationUniversalIdentifier,
|
||||
labelIdentifierFieldMetadataUniversalIdentifier,
|
||||
imageIdentifierFieldMetadataUniversalIdentifier,
|
||||
fieldUniversalIdentifiers: objectMetadataEntity.fields.map(
|
||||
({ universalIdentifier }) => universalIdentifier,
|
||||
),
|
||||
indexMetadataUniversalIdentifiers: objectMetadataEntity.indexMetadatas.map(
|
||||
({ universalIdentifier }) => universalIdentifier,
|
||||
),
|
||||
viewUniversalIdentifiers: objectMetadataEntity.views.map(
|
||||
({ universalIdentifier }) => universalIdentifier,
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ type PageLayoutWidgetConfiguration = PageLayoutWidgetEntity['configuration'];
|
||||
|
||||
type UniversalPageLayoutWidgetConfiguration = NonNullable<
|
||||
FlatPageLayoutWidget['__universal']
|
||||
>['configuration'];
|
||||
>['universalConfiguration'];
|
||||
|
||||
// Field metadata IDs in widget configurations don't need to reference existing entities
|
||||
const getFieldMetadataUniversalIdentifier = ({
|
||||
|
||||
+1
-4
@@ -85,10 +85,7 @@ export const fromPageLayoutWidgetEntityToFlatPageLayoutWidget = ({
|
||||
applicationUniversalIdentifier,
|
||||
pageLayoutTabUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
gridPosition: pageLayoutWidgetEntityWithoutRelations.gridPosition,
|
||||
configuration: configurationWithUniversalIdentifiers,
|
||||
conditionalDisplay:
|
||||
pageLayoutWidgetEntityWithoutRelations.conditionalDisplay,
|
||||
universalConfiguration: configurationWithUniversalIdentifiers,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
-1
@@ -129,7 +129,6 @@ export const fromRowLevelPermissionPredicateEntityToFlatRowLevelPermissionPredic
|
||||
roleUniversalIdentifier,
|
||||
workspaceMemberFieldMetadataUniversalIdentifier,
|
||||
rowLevelPermissionPredicateGroupUniversalIdentifier,
|
||||
value: rowLevelPermissionPredicateEntityWithoutRelations.value,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
-1
@@ -81,7 +81,6 @@ export const fromViewFilterEntityToFlatViewFilter = ({
|
||||
fieldMetadataUniversalIdentifier,
|
||||
viewFilterGroupUniversalIdentifier,
|
||||
viewUniversalIdentifier,
|
||||
value: viewFilterEntityWithoutRelations.value,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
-6
@@ -37,12 +37,6 @@ export const fromLogicFunctionEntityToFlatLogicFunction = ({
|
||||
__universal: {
|
||||
universalIdentifier: logicFunctionEntity.universalIdentifier,
|
||||
applicationUniversalIdentifier,
|
||||
publishedVersions: logicFunctionEntity.publishedVersions,
|
||||
toolInputSchema: logicFunctionEntity.toolInputSchema,
|
||||
cronTriggerSettings: logicFunctionEntity.cronTriggerSettings,
|
||||
databaseEventTriggerSettings:
|
||||
logicFunctionEntity.databaseEventTriggerSettings,
|
||||
httpRouteTriggerSettings: logicFunctionEntity.httpRouteTriggerSettings,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
+3
@@ -10,6 +10,7 @@ export enum ObjectMetadataExceptionCode {
|
||||
INVALID_OBJECT_INPUT = 'INVALID_OBJECT_INPUT',
|
||||
OBJECT_MUTATION_NOT_ALLOWED = 'OBJECT_MUTATION_NOT_ALLOWED',
|
||||
OBJECT_ALREADY_EXISTS = 'OBJECT_ALREADY_EXISTS',
|
||||
APPLICATION_NOT_FOUND = 'APPLICATION_NOT_FOUND',
|
||||
MISSING_CUSTOM_OBJECT_DEFAULT_LABEL_IDENTIFIER_FIELD = 'MISSING_CUSTOM_OBJECT_DEFAULT_LABEL_IDENTIFIER_FIELD',
|
||||
INVALID_ORM_OUTPUT = 'INVALID_ORM_OUTPUT',
|
||||
INTERNAL_SERVER_ERROR = 'INTERNAL_SERVER_ERROR',
|
||||
@@ -28,6 +29,8 @@ const getObjectMetadataExceptionUserFriendlyMessage = (
|
||||
return msg`This object cannot be modified.`;
|
||||
case ObjectMetadataExceptionCode.OBJECT_ALREADY_EXISTS:
|
||||
return msg`An object with this name already exists.`;
|
||||
case ObjectMetadataExceptionCode.APPLICATION_NOT_FOUND:
|
||||
return msg`Application not found.`;
|
||||
case ObjectMetadataExceptionCode.MISSING_CUSTOM_OBJECT_DEFAULT_LABEL_IDENTIFIER_FIELD:
|
||||
return msg`Custom object is missing a label identifier field.`;
|
||||
case ObjectMetadataExceptionCode.INVALID_ORM_OUTPUT:
|
||||
|
||||
+14
-2
@@ -331,11 +331,24 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
const {
|
||||
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
featureFlagsMap: existingFeatureFlagsMap,
|
||||
flatApplicationMaps,
|
||||
} = await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatObjectMetadataMaps',
|
||||
'featureFlagsMap',
|
||||
'flatApplicationMaps',
|
||||
]);
|
||||
|
||||
const ownerFlatApplication = isDefined(applicationId)
|
||||
? flatApplicationMaps.byId[applicationId]
|
||||
: workspaceCustomFlatApplication;
|
||||
|
||||
if (!isDefined(ownerFlatApplication)) {
|
||||
throw new ObjectMetadataException(
|
||||
`Could not find related application ${applicationId}`,
|
||||
ObjectMetadataExceptionCode.APPLICATION_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const {
|
||||
flatObjectMetadataToCreate,
|
||||
flatIndexMetadataToCreate,
|
||||
@@ -344,8 +357,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
} = fromCreateObjectInputToFlatObjectMetadataAndFlatFieldMetadatasToCreate({
|
||||
createObjectInput,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId:
|
||||
applicationId ?? workspaceCustomFlatApplication.id,
|
||||
flatApplication: ownerFlatApplication,
|
||||
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
existingFeatureFlagsMap,
|
||||
});
|
||||
|
||||
+103
-2
@@ -15,7 +15,13 @@ import {
|
||||
type BuildDefaultFlatFieldMetadataForCustomObjectArgs = {
|
||||
workspaceId: string;
|
||||
flatObjectMetadata: NonNullableRequired<
|
||||
Pick<FlatObjectMetadata, 'id' | 'applicationId'>
|
||||
Pick<
|
||||
FlatObjectMetadata,
|
||||
| 'id'
|
||||
| 'applicationId'
|
||||
| 'universalIdentifier'
|
||||
| 'applicationUniversalIdentifier'
|
||||
>
|
||||
>;
|
||||
skipNameField?: boolean;
|
||||
};
|
||||
@@ -26,7 +32,12 @@ export type DefaultFlatFieldForCustomObjectMaps = ReturnType<
|
||||
// This could be replaced totally by an import schema + its transpilation when it's ready
|
||||
export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
workspaceId,
|
||||
flatObjectMetadata: { id: objectMetadataId, applicationId },
|
||||
flatObjectMetadata: {
|
||||
id: objectMetadataId,
|
||||
applicationId,
|
||||
applicationUniversalIdentifier,
|
||||
universalIdentifier: objectMetadataUniversalIdentifier,
|
||||
},
|
||||
skipNameField = false,
|
||||
}: BuildDefaultFlatFieldMetadataForCustomObjectArgs) => {
|
||||
const createdAt = new Date().toISOString();
|
||||
@@ -65,6 +76,16 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
settings: null,
|
||||
morphId: null,
|
||||
applicationId,
|
||||
applicationUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
relationTargetFieldMetadataUniversalIdentifier: null,
|
||||
viewFilterUniversalIdentifiers: [],
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
kanbanAggregateOperationViewUniversalIdentifiers: [],
|
||||
calendarViewUniversalIdentifiers: [],
|
||||
mainGroupByFieldMetadataViewUniversalIdentifiers: [],
|
||||
universalSettings: null,
|
||||
};
|
||||
|
||||
const nameFieldId = skipNameField ? null : v4();
|
||||
@@ -105,6 +126,16 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
settings: null,
|
||||
morphId: null,
|
||||
applicationId,
|
||||
applicationUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
relationTargetFieldMetadataUniversalIdentifier: null,
|
||||
viewFilterUniversalIdentifiers: [],
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
kanbanAggregateOperationViewUniversalIdentifiers: [],
|
||||
calendarViewUniversalIdentifiers: [],
|
||||
mainGroupByFieldMetadataViewUniversalIdentifiers: [],
|
||||
universalSettings: null,
|
||||
};
|
||||
|
||||
const createdAtFieldId = v4();
|
||||
@@ -142,6 +173,16 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
settings: null,
|
||||
morphId: null,
|
||||
applicationId,
|
||||
applicationUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
relationTargetFieldMetadataUniversalIdentifier: null,
|
||||
viewFilterUniversalIdentifiers: [],
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
kanbanAggregateOperationViewUniversalIdentifiers: [],
|
||||
calendarViewUniversalIdentifiers: [],
|
||||
mainGroupByFieldMetadataViewUniversalIdentifiers: [],
|
||||
universalSettings: null,
|
||||
};
|
||||
|
||||
const updatedAtFieldId = v4();
|
||||
@@ -179,6 +220,16 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
settings: null,
|
||||
morphId: null,
|
||||
applicationId,
|
||||
applicationUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
relationTargetFieldMetadataUniversalIdentifier: null,
|
||||
viewFilterUniversalIdentifiers: [],
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
kanbanAggregateOperationViewUniversalIdentifiers: [],
|
||||
calendarViewUniversalIdentifiers: [],
|
||||
mainGroupByFieldMetadataViewUniversalIdentifiers: [],
|
||||
universalSettings: null,
|
||||
};
|
||||
|
||||
const deletedAtFieldId = v4();
|
||||
@@ -216,6 +267,16 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
settings: null,
|
||||
morphId: null,
|
||||
applicationId,
|
||||
applicationUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
relationTargetFieldMetadataUniversalIdentifier: null,
|
||||
viewFilterUniversalIdentifiers: [],
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
kanbanAggregateOperationViewUniversalIdentifiers: [],
|
||||
calendarViewUniversalIdentifiers: [],
|
||||
mainGroupByFieldMetadataViewUniversalIdentifiers: [],
|
||||
universalSettings: null,
|
||||
};
|
||||
|
||||
const createdByFieldId = v4();
|
||||
@@ -252,6 +313,16 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
settings: null,
|
||||
morphId: null,
|
||||
applicationId,
|
||||
applicationUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
relationTargetFieldMetadataUniversalIdentifier: null,
|
||||
viewFilterUniversalIdentifiers: [],
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
kanbanAggregateOperationViewUniversalIdentifiers: [],
|
||||
calendarViewUniversalIdentifiers: [],
|
||||
mainGroupByFieldMetadataViewUniversalIdentifiers: [],
|
||||
universalSettings: null,
|
||||
};
|
||||
|
||||
const updatedByFieldId = v4();
|
||||
@@ -288,6 +359,16 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
settings: null,
|
||||
morphId: null,
|
||||
applicationId,
|
||||
applicationUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
relationTargetFieldMetadataUniversalIdentifier: null,
|
||||
viewFilterUniversalIdentifiers: [],
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
kanbanAggregateOperationViewUniversalIdentifiers: [],
|
||||
calendarViewUniversalIdentifiers: [],
|
||||
mainGroupByFieldMetadataViewUniversalIdentifiers: [],
|
||||
universalSettings: null,
|
||||
};
|
||||
|
||||
const positionFieldId = v4();
|
||||
@@ -325,6 +406,16 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
settings: null,
|
||||
morphId: null,
|
||||
applicationId,
|
||||
applicationUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
relationTargetFieldMetadataUniversalIdentifier: null,
|
||||
viewFilterUniversalIdentifiers: [],
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
kanbanAggregateOperationViewUniversalIdentifiers: [],
|
||||
calendarViewUniversalIdentifiers: [],
|
||||
mainGroupByFieldMetadataViewUniversalIdentifiers: [],
|
||||
universalSettings: null,
|
||||
};
|
||||
|
||||
const searchVectorFieldId = v4();
|
||||
@@ -367,6 +458,16 @@ export const buildDefaultFlatFieldMetadatasForCustomObject = ({
|
||||
},
|
||||
morphId: null,
|
||||
applicationId,
|
||||
applicationUniversalIdentifier,
|
||||
objectMetadataUniversalIdentifier,
|
||||
relationTargetObjectMetadataUniversalIdentifier: null,
|
||||
relationTargetFieldMetadataUniversalIdentifier: null,
|
||||
viewFilterUniversalIdentifiers: [],
|
||||
viewFieldUniversalIdentifiers: [],
|
||||
kanbanAggregateOperationViewUniversalIdentifiers: [],
|
||||
calendarViewUniversalIdentifiers: [],
|
||||
mainGroupByFieldMetadataViewUniversalIdentifiers: [],
|
||||
universalSettings: null,
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
+4
-3
@@ -5,6 +5,7 @@ import { capitalize, isDefined } from 'twenty-shared/utils';
|
||||
import { type FeatureFlagMap } from 'src/engine/core-modules/feature-flag/interfaces/feature-flag-map.interface';
|
||||
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
|
||||
|
||||
import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
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';
|
||||
@@ -53,7 +54,7 @@ export type BuildDefaultRelationFieldsForCustomObjectArgs = {
|
||||
existingFlatObjectMetadataMaps: FlatEntityMaps<FlatObjectMetadata>;
|
||||
workspaceId: string;
|
||||
sourceFlatObjectMetadata: FlatObjectMetadata;
|
||||
workspaceCustomApplicationId: string;
|
||||
flatApplication: FlatApplication;
|
||||
};
|
||||
|
||||
type SourceAndTargetFlatFieldMetadatasRecord = {
|
||||
@@ -71,7 +72,7 @@ export const buildDefaultRelationFlatFieldMetadatasForCustomObject = ({
|
||||
existingFlatObjectMetadataMaps,
|
||||
sourceFlatObjectMetadata,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
}: BuildDefaultRelationFieldsForCustomObjectArgs): SourceAndTargetFlatFieldMetadatasRecord => {
|
||||
const objectIdByNameSingular = Object.values(
|
||||
existingFlatObjectMetadataMaps.byId,
|
||||
@@ -156,7 +157,7 @@ export const buildDefaultRelationFlatFieldMetadatasForCustomObject = ({
|
||||
? FieldMetadataType.MORPH_RELATION
|
||||
: FieldMetadataType.RELATION,
|
||||
workspaceId,
|
||||
workspaceCustomApplicationId,
|
||||
flatApplication,
|
||||
sourceFlatObjectMetadataJoinColumnName: joinColumnName,
|
||||
morphId,
|
||||
targetFieldName: fieldName,
|
||||
|
||||
+1
@@ -43,6 +43,7 @@ export const objectMetadataGraphqlApiExceptionHandler = (
|
||||
case ObjectMetadataExceptionCode.INVALID_ORM_OUTPUT:
|
||||
throw new InternalServerError(error);
|
||||
case ObjectMetadataExceptionCode.MISSING_CUSTOM_OBJECT_DEFAULT_LABEL_IDENTIFIER_FIELD:
|
||||
case ObjectMetadataExceptionCode.APPLICATION_NOT_FOUND:
|
||||
throw error;
|
||||
default: {
|
||||
return assertUnreachable(error.code);
|
||||
|
||||
Reference in New Issue
Block a user