Multiple errors on field input transpilation improvement (#13774)
# Introduction - ~~returning deleted field on deleteOneField~~ postponed for later cannot build dto from flat atm - refactor createFieldInput transpilation to handle multiple errors instead of throwing - renamed extract function
This commit is contained in:
+57
-39
@@ -15,12 +15,13 @@ 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';
|
||||
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 { fromRelationCreateFieldInputToFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-relation-create-field-input-to-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 FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
|
||||
|
||||
type FromCreateFieldInputToFlatObjectMetadata = {
|
||||
type FromCreateFieldInputToFlatObjectMetadataArgs = {
|
||||
rawCreateFieldInput: Omit<CreateFieldInput, 'workspaceId'>;
|
||||
existingFlatObjectMetadataMaps: FlatObjectMetadataMaps;
|
||||
workspaceId: string;
|
||||
@@ -30,12 +31,17 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
|
||||
rawCreateFieldInput,
|
||||
workspaceId,
|
||||
existingFlatObjectMetadataMaps,
|
||||
}: FromCreateFieldInputToFlatObjectMetadata): Promise<FlatFieldMetadata[]> => {
|
||||
}: FromCreateFieldInputToFlatObjectMetadataArgs): Promise<
|
||||
FieldInputTranspilationResult<FlatFieldMetadata[]>
|
||||
> => {
|
||||
if (rawCreateFieldInput.isRemoteCreation) {
|
||||
throw new FieldMetadataException(
|
||||
"Remote fields aren't supported",
|
||||
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
|
||||
);
|
||||
return {
|
||||
status: 'fail',
|
||||
error: new FieldMetadataException(
|
||||
"Remote fields aren't supported",
|
||||
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
|
||||
),
|
||||
};
|
||||
}
|
||||
const createFieldInput =
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
|
||||
@@ -46,14 +52,17 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
|
||||
existingFlatObjectMetadataMaps.byId[createFieldInput.objectMetadataId];
|
||||
|
||||
if (!isDefined(parentFlatObjectMetadata)) {
|
||||
throw new FieldMetadataException(
|
||||
'Provided object metadata id does not exist',
|
||||
FieldMetadataExceptionCode.OBJECT_METADATA_NOT_FOUND,
|
||||
{
|
||||
userFriendlyMessage:
|
||||
'Created field metadata, parent object metadata not found',
|
||||
},
|
||||
);
|
||||
return {
|
||||
status: 'fail',
|
||||
error: new FieldMetadataException(
|
||||
'Provided object metadata id does not exist',
|
||||
FieldMetadataExceptionCode.OBJECT_METADATA_NOT_FOUND,
|
||||
{
|
||||
userFriendlyMessage:
|
||||
'Created field metadata, parent object metadata not found',
|
||||
},
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
const fieldMetadataId = v4();
|
||||
@@ -71,7 +80,7 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
|
||||
);
|
||||
}
|
||||
case FieldMetadataType.RELATION: {
|
||||
return fromRelationCreateFieldInputToFlatFieldMetadata({
|
||||
return await fromRelationCreateFieldInputToFlatFieldMetadata({
|
||||
existingFlatObjectMetadataMaps,
|
||||
sourceParentFlatObjectMetadata: parentFlatObjectMetadata,
|
||||
createFieldInput,
|
||||
@@ -79,15 +88,18 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
|
||||
});
|
||||
}
|
||||
case FieldMetadataType.RATING: {
|
||||
return [
|
||||
{
|
||||
...commonFlatFieldMetadata,
|
||||
type: createFieldInput.type,
|
||||
settings: null,
|
||||
defaultValue: commonFlatFieldMetadata.defaultValue as string, // Could this be improved ?
|
||||
options: generateRatingOptions(),
|
||||
} satisfies FlatFieldMetadata<typeof createFieldInput.type>,
|
||||
];
|
||||
return {
|
||||
status: 'success',
|
||||
result: [
|
||||
{
|
||||
...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:
|
||||
case FieldMetadataType.MULTI_SELECT: {
|
||||
@@ -100,15 +112,18 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
|
||||
),
|
||||
}));
|
||||
|
||||
return [
|
||||
{
|
||||
...commonFlatFieldMetadata,
|
||||
type: createFieldInput.type,
|
||||
options,
|
||||
defaultValue: commonFlatFieldMetadata.defaultValue as string, // Could this be improved ?
|
||||
settings: null,
|
||||
} satisfies FlatFieldMetadata<typeof createFieldInput.type>,
|
||||
];
|
||||
return {
|
||||
status: 'success',
|
||||
result: [
|
||||
{
|
||||
...commonFlatFieldMetadata,
|
||||
type: createFieldInput.type,
|
||||
options,
|
||||
defaultValue: commonFlatFieldMetadata.defaultValue as string, // Could this be improved ?
|
||||
settings: null,
|
||||
} satisfies FlatFieldMetadata<typeof createFieldInput.type>,
|
||||
],
|
||||
};
|
||||
}
|
||||
case FieldMetadataType.UUID:
|
||||
case FieldMetadataType.TEXT:
|
||||
@@ -130,12 +145,15 @@ export const fromCreateFieldInputToFlatFieldMetadatasToCreate = async ({
|
||||
case FieldMetadataType.ACTOR:
|
||||
case FieldMetadataType.ARRAY:
|
||||
case FieldMetadataType.TS_VECTOR: {
|
||||
return [
|
||||
{
|
||||
...commonFlatFieldMetadata,
|
||||
type: createFieldInput.type,
|
||||
},
|
||||
];
|
||||
return {
|
||||
status: 'success',
|
||||
result: [
|
||||
{
|
||||
...commonFlatFieldMetadata,
|
||||
type: createFieldInput.type,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
default: {
|
||||
assertUnreachable(createFieldInput.type, 'Encountered an uncovered');
|
||||
|
||||
+52
-21
@@ -1,5 +1,8 @@
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
isDefined,
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties,
|
||||
} from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
|
||||
@@ -9,7 +12,8 @@ import {
|
||||
FieldMetadataException,
|
||||
FieldMetadataExceptionCode,
|
||||
} 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 { validateRelationCreationPayloadOrThrow } from 'src/engine/metadata-modules/field-metadata/utils/validate-relation-creation-payload-or-throw.util';
|
||||
import { type FieldInputTranspilationResult } from 'src/engine/metadata-modules/flat-field-metadata/types/field-input-transpilation-result.type';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { getDefaultFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/get-default-flat-field-metadata-from-create-field-input.util';
|
||||
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
|
||||
@@ -50,17 +54,38 @@ export const fromRelationCreateFieldInputToFlatFieldMetadata = async ({
|
||||
createFieldInput,
|
||||
workspaceId,
|
||||
}: FromRelationCreateFieldInputToFlatFieldMetadataArgs): Promise<
|
||||
FlatFieldMetadata[]
|
||||
FieldInputTranspilationResult<FlatFieldMetadata[]>
|
||||
> => {
|
||||
const { relationCreationPayload } = createFieldInput;
|
||||
const rawCreationPayload = createFieldInput.relationCreationPayload;
|
||||
|
||||
if (!isDefined(relationCreationPayload)) {
|
||||
throw new FieldMetadataException(
|
||||
`Relation creation payload is required`,
|
||||
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
|
||||
);
|
||||
if (!isDefined(rawCreationPayload)) {
|
||||
return {
|
||||
status: 'fail',
|
||||
error: new FieldMetadataException(
|
||||
`Relation creation payload is required`,
|
||||
FieldMetadataExceptionCode.INVALID_FIELD_INPUT,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
const relationCreationPayload =
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
|
||||
rawCreationPayload,
|
||||
['targetFieldIcon', 'targetFieldLabel', 'targetObjectMetadataId', 'type'],
|
||||
);
|
||||
|
||||
try {
|
||||
await validateRelationCreationPayloadOrThrow(relationCreationPayload);
|
||||
} catch (error) {
|
||||
if (error instanceof FieldMetadataException) {
|
||||
return {
|
||||
status: 'fail',
|
||||
error,
|
||||
};
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
await validateRelationCreationPayloadOrThrow(relationCreationPayload);
|
||||
|
||||
const targetParentFlatObjectMetadata =
|
||||
existingFlatObjectMetadataMaps.byId[
|
||||
@@ -68,10 +93,13 @@ export const fromRelationCreateFieldInputToFlatFieldMetadata = async ({
|
||||
];
|
||||
|
||||
if (!isDefined(targetParentFlatObjectMetadata)) {
|
||||
throw new FieldMetadataException(
|
||||
`Object metadata relation target not found for relation creation payload`,
|
||||
FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED,
|
||||
);
|
||||
return {
|
||||
status: 'fail',
|
||||
error: new FieldMetadataException(
|
||||
`Object metadata relation target not found for relation creation payload`,
|
||||
FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
const sourceFlatFieldMetadataSettings =
|
||||
@@ -135,11 +163,14 @@ export const fromRelationCreateFieldInputToFlatFieldMetadata = async ({
|
||||
flatRelationTargetObjectMetadata: sourceParentFlatObjectMetadata,
|
||||
};
|
||||
|
||||
return [
|
||||
{
|
||||
...sourceFlatFieldMetadata,
|
||||
flatRelationTargetFieldMetadata: targetFlatFieldMetadata,
|
||||
},
|
||||
targetFlatFieldMetadata,
|
||||
] satisfies FlatFieldMetadata<FieldMetadataType.RELATION>[];
|
||||
return {
|
||||
status: 'success',
|
||||
result: [
|
||||
{
|
||||
...sourceFlatFieldMetadata,
|
||||
flatRelationTargetFieldMetadata: targetFlatFieldMetadata,
|
||||
},
|
||||
targetFlatFieldMetadata,
|
||||
] satisfies FlatFieldMetadata<FieldMetadataType.RELATION>[],
|
||||
};
|
||||
};
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
import { MultipleMetadataValidationErrors } from 'src/engine/core-modules/error/multiple-metadata-validation-errors';
|
||||
import {
|
||||
type FieldInputTranspilationResult,
|
||||
type SuccessfulFieldInputTranspilation,
|
||||
} from 'src/engine/metadata-modules/flat-field-metadata/types/field-input-transpilation-result.type';
|
||||
|
||||
type ThrowOnFieldInputTranspilationsErrorArgs = <T>(
|
||||
inputTranspilationResults: FieldInputTranspilationResult<T>[],
|
||||
errorLabel: string,
|
||||
) => asserts inputTranspilationResults is SuccessfulFieldInputTranspilation<T>[];
|
||||
export const throwOnFieldInputTranspilationsError: ThrowOnFieldInputTranspilationsErrorArgs =
|
||||
<T>(
|
||||
inputTranspilationResults: FieldInputTranspilationResult<T>[],
|
||||
errorLabel: string,
|
||||
) => {
|
||||
const failedInputTranspilationErrors = inputTranspilationResults.flatMap(
|
||||
(transpilationResult) =>
|
||||
transpilationResult.status === 'fail' ? transpilationResult.error : [],
|
||||
);
|
||||
|
||||
if (failedInputTranspilationErrors.length > 0) {
|
||||
throw new MultipleMetadataValidationErrors(
|
||||
failedInputTranspilationErrors,
|
||||
errorLabel,
|
||||
);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user