Field metadata v2 relation (#13562)
# Introduction - deferrable constraint on foreignKey definition - fix relation creation input transpilation to flat field metadata - fix validation to allow contextual validation on not already created field metadata ( usefull for relation, and will be necessary for the import )
This commit is contained in:
+15
-32
@@ -24,19 +24,11 @@ type FromCreateFieldInputToFlatObjectMetadata = {
|
||||
rawCreateFieldInput: CreateFieldInput;
|
||||
existingFlatObjectMetadatas: FlatObjectMetadata[];
|
||||
};
|
||||
export type FlatFieldAndItsFlatObjectMetadata<
|
||||
T extends FieldMetadataType = FieldMetadataType,
|
||||
> = {
|
||||
flatFieldMetadata: FlatFieldMetadata<T>;
|
||||
parentFlatObjectMetadata: FlatObjectMetadata;
|
||||
};
|
||||
|
||||
export const fromCreateFieldInputToFlatFieldAndItsFlatObjectMetadata = async ({
|
||||
existingFlatObjectMetadatas,
|
||||
rawCreateFieldInput,
|
||||
}: FromCreateFieldInputToFlatObjectMetadata): Promise<
|
||||
FlatFieldAndItsFlatObjectMetadata[]
|
||||
> => {
|
||||
}: FromCreateFieldInputToFlatObjectMetadata): Promise<FlatFieldMetadata[]> => {
|
||||
if (rawCreateFieldInput.isRemoteCreation) {
|
||||
throw new FieldMetadataException(
|
||||
"Remote fields aren't supported",
|
||||
@@ -86,15 +78,12 @@ export const fromCreateFieldInputToFlatFieldAndItsFlatObjectMetadata = async ({
|
||||
case FieldMetadataType.RATING: {
|
||||
return [
|
||||
{
|
||||
flatFieldMetadata: {
|
||||
...commonFlatFieldMetadata,
|
||||
type: createFieldInput.type,
|
||||
settings: null,
|
||||
defaultValue: commonFlatFieldMetadata.defaultValue as string, // Could this be improved ?
|
||||
options: generateRatingOptions(),
|
||||
} satisfies FlatFieldMetadata<typeof createFieldInput.type>,
|
||||
parentFlatObjectMetadata,
|
||||
},
|
||||
...commonFlatFieldMetadata,
|
||||
type: createFieldInput.type,
|
||||
settings: null,
|
||||
defaultValue: commonFlatFieldMetadata.defaultValue as string, // Could this be improved ?
|
||||
options: generateRatingOptions(),
|
||||
} satisfies FlatFieldMetadata<typeof createFieldInput.type>,
|
||||
];
|
||||
}
|
||||
case FieldMetadataType.SELECT:
|
||||
@@ -110,15 +99,12 @@ export const fromCreateFieldInputToFlatFieldAndItsFlatObjectMetadata = async ({
|
||||
|
||||
return [
|
||||
{
|
||||
flatFieldMetadata: {
|
||||
...commonFlatFieldMetadata,
|
||||
type: createFieldInput.type,
|
||||
options,
|
||||
defaultValue: commonFlatFieldMetadata.defaultValue as string, // Could this be improved ?
|
||||
settings: null,
|
||||
} satisfies FlatFieldMetadata<typeof createFieldInput.type>,
|
||||
parentFlatObjectMetadata,
|
||||
},
|
||||
...commonFlatFieldMetadata,
|
||||
type: createFieldInput.type,
|
||||
options,
|
||||
defaultValue: commonFlatFieldMetadata.defaultValue as string, // Could this be improved ?
|
||||
settings: null,
|
||||
} satisfies FlatFieldMetadata<typeof createFieldInput.type>,
|
||||
];
|
||||
}
|
||||
case FieldMetadataType.UUID:
|
||||
@@ -143,11 +129,8 @@ export const fromCreateFieldInputToFlatFieldAndItsFlatObjectMetadata = async ({
|
||||
case FieldMetadataType.TS_VECTOR: {
|
||||
return [
|
||||
{
|
||||
flatFieldMetadata: {
|
||||
...commonFlatFieldMetadata,
|
||||
type: createFieldInput.type,
|
||||
},
|
||||
parentFlatObjectMetadata,
|
||||
...commonFlatFieldMetadata,
|
||||
type: createFieldInput.type,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
+56
-24
@@ -2,6 +2,8 @@ import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
|
||||
|
||||
import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input';
|
||||
import {
|
||||
FieldMetadataException,
|
||||
@@ -9,11 +11,32 @@ import {
|
||||
} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
|
||||
import { validateRelationCreationPayloadOrThrow } from 'src/engine/metadata-modules/field-metadata/utils/validate-relation-creation-payload.util';
|
||||
import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { FlatFieldAndItsFlatObjectMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-create-field-input-to-flat-field-and-its-flat-object-metadata.util';
|
||||
import { getDefaultFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/get-default-flat-field-metadata-from-create-field-input.util';
|
||||
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { RelationOnDeleteAction } from 'src/engine/metadata-modules/relation-metadata/relation-on-delete-action.type';
|
||||
import { computeMetadataNameFromLabel } from 'src/engine/metadata-modules/utils/validate-name-and-label-are-sync-or-throw.util';
|
||||
|
||||
type ComputeFieldMetadataRelationSettingsForRelationTypeArgs = {
|
||||
relationType: RelationType;
|
||||
fieldMetadataName: string;
|
||||
};
|
||||
const computeFieldMetadataRelationSettingsForRelationType = ({
|
||||
fieldMetadataName,
|
||||
relationType,
|
||||
}: ComputeFieldMetadataRelationSettingsForRelationTypeArgs) => {
|
||||
if (relationType === RelationType.MANY_TO_ONE) {
|
||||
return {
|
||||
relationType: RelationType.MANY_TO_ONE,
|
||||
onDelete: RelationOnDeleteAction.SET_NULL,
|
||||
joinColumnName: fieldMetadataName,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
relationType: RelationType.ONE_TO_MANY,
|
||||
};
|
||||
};
|
||||
|
||||
type FromRelationCreateFieldInputToFlatFieldMetadataArgs = {
|
||||
createFieldInput: CreateFieldInput;
|
||||
existingFlatObjectMetadatas: FlatObjectMetadata[];
|
||||
@@ -24,7 +47,7 @@ export const fromRelationCreateFieldInputToFlatFieldMetadata = async ({
|
||||
sourceParentFlatObjectMetadata,
|
||||
createFieldInput,
|
||||
}: FromRelationCreateFieldInputToFlatFieldMetadataArgs): Promise<
|
||||
FlatFieldAndItsFlatObjectMetadata[]
|
||||
FlatFieldMetadata[]
|
||||
> => {
|
||||
const { relationCreationPayload } = createFieldInput;
|
||||
|
||||
@@ -48,6 +71,11 @@ export const fromRelationCreateFieldInputToFlatFieldMetadata = async ({
|
||||
);
|
||||
}
|
||||
|
||||
const sourceFlatFieldMetadataSettings =
|
||||
computeFieldMetadataRelationSettingsForRelationType({
|
||||
fieldMetadataName: createFieldInput.name,
|
||||
relationType: relationCreationPayload.type,
|
||||
});
|
||||
const targetRelationTargetFieldMetadataId = v4();
|
||||
const sourceRelationTargetFieldMetadataId = v4();
|
||||
const sourceFlatFieldMetadata: Omit<
|
||||
@@ -58,33 +86,43 @@ export const fromRelationCreateFieldInputToFlatFieldMetadata = async ({
|
||||
createFieldInput,
|
||||
fieldMetadataId: sourceRelationTargetFieldMetadataId,
|
||||
}),
|
||||
icon: createFieldInput.icon ?? 'IconRelationOneToMany',
|
||||
type: FieldMetadataType.RELATION,
|
||||
defaultValue: null,
|
||||
settings: null,
|
||||
settings: sourceFlatFieldMetadataSettings,
|
||||
options: null,
|
||||
relationTargetFieldMetadataId: targetRelationTargetFieldMetadataId, // Note: this won't work until we enable deferred transaction
|
||||
relationTargetObjectMetadataId: targetParentFlatObjectMetadata.id,
|
||||
flatRelationTargetObjectMetadata: targetParentFlatObjectMetadata,
|
||||
};
|
||||
|
||||
const targetCreateFieldInput: CreateFieldInput = {
|
||||
icon: relationCreationPayload.targetFieldIcon ?? 'Icon123',
|
||||
label: relationCreationPayload.targetFieldLabel,
|
||||
name: `${computeMetadataNameFromLabel(
|
||||
relationCreationPayload.targetFieldLabel,
|
||||
)}Id`,
|
||||
objectMetadataId: targetParentFlatObjectMetadata.id,
|
||||
type: FieldMetadataType.RELATION,
|
||||
workspaceId: createFieldInput.workspaceId,
|
||||
};
|
||||
const targetFlatFieldMetadataSettings =
|
||||
computeFieldMetadataRelationSettingsForRelationType({
|
||||
fieldMetadataName: targetCreateFieldInput.name,
|
||||
relationType:
|
||||
relationCreationPayload.type === RelationType.ONE_TO_MANY
|
||||
? RelationType.MANY_TO_ONE
|
||||
: RelationType.ONE_TO_MANY,
|
||||
});
|
||||
const targetFlatFieldMetadata: FlatFieldMetadata<FieldMetadataType.RELATION> =
|
||||
{
|
||||
...getDefaultFlatFieldMetadata({
|
||||
createFieldInput: {
|
||||
icon: relationCreationPayload.targetFieldIcon,
|
||||
label: relationCreationPayload.targetFieldLabel,
|
||||
name: `${computeMetadataNameFromLabel(
|
||||
relationCreationPayload.targetFieldLabel,
|
||||
)}Id`,
|
||||
objectMetadataId: targetParentFlatObjectMetadata.id,
|
||||
type: FieldMetadataType.RELATION,
|
||||
workspaceId: createFieldInput.workspaceId,
|
||||
},
|
||||
createFieldInput: targetCreateFieldInput,
|
||||
fieldMetadataId: targetRelationTargetFieldMetadataId,
|
||||
}),
|
||||
type: FieldMetadataType.RELATION,
|
||||
defaultValue: null,
|
||||
settings: null,
|
||||
settings: targetFlatFieldMetadataSettings,
|
||||
options: null,
|
||||
relationTargetFieldMetadataId: sourceRelationTargetFieldMetadataId,
|
||||
relationTargetObjectMetadataId: sourceParentFlatObjectMetadata.id,
|
||||
@@ -94,15 +132,9 @@ export const fromRelationCreateFieldInputToFlatFieldMetadata = async ({
|
||||
|
||||
return [
|
||||
{
|
||||
flatFieldMetadata: {
|
||||
...sourceFlatFieldMetadata,
|
||||
flatRelationTargetFieldMetadata: targetFlatFieldMetadata,
|
||||
},
|
||||
parentFlatObjectMetadata: sourceParentFlatObjectMetadata,
|
||||
...sourceFlatFieldMetadata,
|
||||
flatRelationTargetFieldMetadata: targetFlatFieldMetadata,
|
||||
},
|
||||
{
|
||||
flatFieldMetadata: targetFlatFieldMetadata,
|
||||
parentFlatObjectMetadata: targetParentFlatObjectMetadata,
|
||||
},
|
||||
] satisfies FlatFieldAndItsFlatObjectMetadata<FieldMetadataType.RELATION>[];
|
||||
targetFlatFieldMetadata,
|
||||
] satisfies FlatFieldMetadata<FieldMetadataType.RELATION>[];
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user