ObjectMetadataServiceV2.updateOne (#13891)
# Introduction Last service to get migrated, `updateOne` object metadata service v2
This commit is contained in:
+7
@@ -0,0 +1,7 @@
|
||||
import { type FlatFieldMetadataPropertiesToCompare } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-properties-to-compare.type';
|
||||
|
||||
export const FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES = [
|
||||
'label',
|
||||
'description',
|
||||
'icon',
|
||||
] as const satisfies FlatFieldMetadataPropertiesToCompare[];
|
||||
+1
-9
@@ -4,16 +4,8 @@ import { IsJSON, IsOptional, IsString } from 'class-validator';
|
||||
import { GraphQLJSON } from 'graphql-type-json';
|
||||
import { type APP_LOCALES } from 'twenty-shared/translations';
|
||||
|
||||
import { FlatFieldMetadataPropertiesToCompare } from 'src/engine/metadata-modules/flat-field-metadata/utils/compare-two-flat-field-metadata.util';
|
||||
import { FieldMetadataStandardOverridesProperties } from 'src/engine/metadata-modules/field-metadata/types/field-metadata-standard-overrides-properties.type';
|
||||
|
||||
export const fieldMetadataStandardOverridesProperties = [
|
||||
'label',
|
||||
'description',
|
||||
'icon',
|
||||
] as const satisfies FlatFieldMetadataPropertiesToCompare[];
|
||||
|
||||
export type FieldMetadataStandardOverridesProperties =
|
||||
(typeof fieldMetadataStandardOverridesProperties)[number];
|
||||
@ObjectType('StandardOverrides')
|
||||
export class FieldStandardOverridesDTO
|
||||
implements Partial<Record<FieldMetadataStandardOverridesProperties, unknown>>
|
||||
|
||||
+5
-6
@@ -24,7 +24,7 @@ import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-m
|
||||
import { fromCreateFieldInputToFlatFieldMetadatasToCreate } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-create-field-input-to-flat-field-metadatas-to-create.util';
|
||||
import { fromDeleteFieldInputToFlatFieldMetadatasToDelete } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-delete-field-input-to-flat-field-metadatas-to-delete.util';
|
||||
import { fromFlatFieldMetadataToFieldMetadataDto } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-flat-field-metadata-to-field-metadata-dto.util';
|
||||
import { fromUpdateFieldInputToFlatFieldMetadataToUpdate } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-update-field-input-to-flat-field-metadata-to-update.util';
|
||||
import { fromUpdateFieldInputToFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/from-update-field-input-to-flat-field-metadata.util';
|
||||
import { isFlatFieldMetadataEntityOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
|
||||
import { throwOnFieldInputTranspilationsError } from 'src/engine/metadata-modules/flat-field-metadata/utils/throw-on-field-input-transpilations-error.util';
|
||||
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
|
||||
@@ -213,11 +213,10 @@ export class FieldMetadataServiceV2 {
|
||||
{ workspaceId },
|
||||
);
|
||||
|
||||
const inputTranspilationResult =
|
||||
fromUpdateFieldInputToFlatFieldMetadataToUpdate({
|
||||
existingFlatObjectMetadataMaps,
|
||||
updateFieldInput,
|
||||
});
|
||||
const inputTranspilationResult = fromUpdateFieldInputToFlatFieldMetadata({
|
||||
existingFlatObjectMetadataMaps,
|
||||
updateFieldInput,
|
||||
});
|
||||
|
||||
if (inputTranspilationResult.status === 'fail') {
|
||||
throw inputTranspilationResult.error;
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import { type FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES } from 'src/engine/metadata-modules/field-metadata/constants/field-metadata-standard-overrides-properties.constant';
|
||||
|
||||
export type FieldMetadataStandardOverridesProperties =
|
||||
(typeof FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES)[number];
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
|
||||
export const FLAT_FIELD_METADATA_JSONB_PROPERTIES = [
|
||||
'defaultValue',
|
||||
'options',
|
||||
'settings',
|
||||
'standardOverrides',
|
||||
] as const satisfies (keyof FlatFieldMetadata)[];
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
|
||||
export const FLAT_FIELD_METADATA_PROPERTIES_TO_COMPARE = [
|
||||
'defaultValue',
|
||||
'description',
|
||||
'icon',
|
||||
'isActive',
|
||||
'isLabelSyncedWithName',
|
||||
'isUnique',
|
||||
'label',
|
||||
'name',
|
||||
'options',
|
||||
'standardOverrides',
|
||||
'settings',
|
||||
] as const satisfies (keyof FlatFieldMetadata)[];
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
import { type FlatFieldMetadataPropertiesToCompare } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-properties-to-compare.type';
|
||||
|
||||
export const FLAT_FIELD_METADATA_RELATION_PROPERTIES_TO_COMPARE = [
|
||||
'label',
|
||||
'description',
|
||||
'isActive',
|
||||
] as const satisfies FlatFieldMetadataPropertiesToCompare[];
|
||||
+2
-2
@@ -13,8 +13,8 @@ import { ValidateOneFieldMetadataArgs } from 'src/engine/metadata-modules/flat-f
|
||||
import { FailedFlatFieldMetadataValidationExceptions } from 'src/engine/metadata-modules/flat-field-metadata/types/failed-flat-field-metadata-validation.type';
|
||||
import { type FlatFieldMetadataTypeValidator } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-type-validator.type';
|
||||
import { isEnumValidateOneFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-enum-validate-one-field-metadata-args.util';
|
||||
import { validateEnumSelectFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/validators/validate-enum-flat-field-metadata.validator';
|
||||
import { validateRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/validators/validate-relation-flat-field-metadata.validator';
|
||||
import { validateEnumSelectFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-enum-flat-field-metadata.util';
|
||||
import { validateRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-relation-flat-field-metadata.util';
|
||||
@Injectable()
|
||||
export class FlatFieldMetadataTypeValidatorService {
|
||||
constructor(private readonly featureFlagService: FeatureFlagService) {}
|
||||
|
||||
+26
-38
@@ -8,16 +8,16 @@ import {
|
||||
FieldMetadataException,
|
||||
FieldMetadataExceptionCode,
|
||||
} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
|
||||
import { FLAT_FIELD_METADATA_RELATION_PROPERTIES_TO_COMPARE } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-relation-properties-to-compare.constant';
|
||||
import { FlatFieldMetadataTypeValidatorService } from 'src/engine/metadata-modules/flat-field-metadata/services/flat-field-metadata-type-validator.service';
|
||||
import { type FailedFlatFieldMetadataValidationExceptions } from 'src/engine/metadata-modules/flat-field-metadata/types/failed-flat-field-metadata-validation.type';
|
||||
import { FlatFieldMetadataRelationPropertiesToCompare } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-relation-properties-to-compare.type';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import {
|
||||
compareTwoFlatFieldMetadata,
|
||||
type FlatFieldMetadataPropertiesToCompare,
|
||||
} from 'src/engine/metadata-modules/flat-field-metadata/utils/compare-two-flat-field-metadata.util';
|
||||
import { compareTwoFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/compare-two-flat-field-metadata.util';
|
||||
import { isFlatFieldMetadataNameSyncedWithLabel } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-name-synced-with-label.util';
|
||||
import { isFlatFieldMetadataEntityOfType } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-flat-field-metadata-of-type.util';
|
||||
import { validateFlatFieldMetadataNameAvailability } from 'src/engine/metadata-modules/flat-field-metadata/validators/validate-flat-field-metadata-name-availability.validator';
|
||||
import { validateFlatFieldMetadataName } from 'src/engine/metadata-modules/flat-field-metadata/validators/validate-flat-field-metadata-name.validator';
|
||||
import { validateFlatFieldMetadataNameAvailability } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name-availability.util';
|
||||
import { validateFlatFieldMetadataName } from 'src/engine/metadata-modules/flat-field-metadata/validators/utils/validate-flat-field-metadata-name.util';
|
||||
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
|
||||
import { fromFlatObjectMetadataWithFlatFieldMapsToFlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-flat-object-metadata-with-flat-field-maps-to-flat-object-metadatas.util';
|
||||
import {
|
||||
@@ -28,7 +28,6 @@ import {
|
||||
InvalidMetadataException,
|
||||
InvalidMetadataExceptionCode,
|
||||
} from 'src/engine/metadata-modules/utils/exceptions/invalid-metadata.exception';
|
||||
import { computeMetadataNameFromLabel } from 'src/engine/metadata-modules/utils/validate-name-and-label-are-sync-or-throw.util';
|
||||
|
||||
export type ValidateOneFieldMetadataArgs<
|
||||
T extends FieldMetadataType = FieldMetadataType,
|
||||
@@ -110,15 +109,10 @@ export class FlatFieldMetadataValidatorService {
|
||||
FieldMetadataType.MORPH_RELATION,
|
||||
)
|
||||
) {
|
||||
const relationEditableFields = [
|
||||
'label',
|
||||
'description',
|
||||
'isActive',
|
||||
] as const satisfies FlatFieldMetadataPropertiesToCompare[];
|
||||
const relationNonEditableUpdatedProperties = updates.flatMap(
|
||||
({ property }) =>
|
||||
!relationEditableFields.includes(
|
||||
property as (typeof relationEditableFields)[number],
|
||||
!FLAT_FIELD_METADATA_RELATION_PROPERTIES_TO_COMPARE.includes(
|
||||
property as FlatFieldMetadataRelationPropertiesToCompare,
|
||||
)
|
||||
? property
|
||||
: [],
|
||||
@@ -155,19 +149,16 @@ export class FlatFieldMetadataValidatorService {
|
||||
}
|
||||
}
|
||||
|
||||
if (updatedFlatFieldMetadata.isLabelSyncedWithName) {
|
||||
const computedName = computeMetadataNameFromLabel(
|
||||
updatedFlatFieldMetadata.label,
|
||||
if (
|
||||
updatedFlatFieldMetadata.isLabelSyncedWithName &&
|
||||
!isFlatFieldMetadataNameSyncedWithLabel(updatedFlatFieldMetadata)
|
||||
) {
|
||||
errors.push(
|
||||
new InvalidMetadataException(
|
||||
t`Name is not synced with label.`,
|
||||
InvalidMetadataExceptionCode.NAME_NOT_SYNCED_WITH_LABEL,
|
||||
),
|
||||
);
|
||||
|
||||
if (updatedFlatFieldMetadata.name !== computedName) {
|
||||
errors.push(
|
||||
new InvalidMetadataException(
|
||||
`Name is not synced with label. Expected name: "${computedName}", got ${updatedFlatFieldMetadata.name}`,
|
||||
InvalidMetadataExceptionCode.NAME_NOT_SYNCED_WITH_LABEL,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const fieldMetadataTypeValidationErrors =
|
||||
@@ -295,19 +286,16 @@ export class FlatFieldMetadataValidatorService {
|
||||
}
|
||||
}
|
||||
|
||||
if (flatFieldMetadataToValidate.isLabelSyncedWithName) {
|
||||
const computedName = computeMetadataNameFromLabel(
|
||||
flatFieldMetadataToValidate.label,
|
||||
if (
|
||||
flatFieldMetadataToValidate.isLabelSyncedWithName &&
|
||||
!isFlatFieldMetadataNameSyncedWithLabel(flatFieldMetadataToValidate)
|
||||
) {
|
||||
errors.push(
|
||||
new InvalidMetadataException(
|
||||
t`Name is not synced with label.`,
|
||||
InvalidMetadataExceptionCode.NAME_NOT_SYNCED_WITH_LABEL,
|
||||
),
|
||||
);
|
||||
|
||||
if (flatFieldMetadataToValidate.name !== computedName) {
|
||||
errors.push(
|
||||
new InvalidMetadataException(
|
||||
`Name is not synced with label. Expected name: "${computedName}", got ${flatFieldMetadataToValidate.name}`,
|
||||
InvalidMetadataExceptionCode.NAME_NOT_SYNCED_WITH_LABEL,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
errors.push(
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import { type FLAT_FIELD_METADATA_JSONB_PROPERTIES } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-jsonb-properties.constant';
|
||||
|
||||
export type FlatFieldMetadataEntityJsonbProperties =
|
||||
(typeof FLAT_FIELD_METADATA_JSONB_PROPERTIES)[number];
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import { type FLAT_FIELD_METADATA_PROPERTIES_TO_COMPARE } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-properties-to-compare.constant';
|
||||
|
||||
export type FlatFieldMetadataPropertiesToCompare =
|
||||
(typeof FLAT_FIELD_METADATA_PROPERTIES_TO_COMPARE)[number];
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import { type FLAT_FIELD_METADATA_RELATION_PROPERTIES_TO_COMPARE } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-relation-properties-to-compare.constant';
|
||||
|
||||
export type FlatFieldMetadataRelationPropertiesToCompare =
|
||||
(typeof FLAT_FIELD_METADATA_RELATION_PROPERTIES_TO_COMPARE)[number];
|
||||
+28
-35
@@ -2,36 +2,17 @@ import diff from 'microdiff';
|
||||
import { FieldMetadataType, type FromTo } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { FLAT_FIELD_METADATA_JSONB_PROPERTIES } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-jsonb-properties.constant';
|
||||
import { FLAT_FIELD_METADATA_PROPERTIES_TO_COMPARE } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-properties-to-compare.constant';
|
||||
import { FLAT_FIELD_METADATA_RELATION_PROPERTIES_TO_COMPARE } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-relation-properties-to-compare.constant';
|
||||
import { type FlatFieldMetadataEntityJsonbProperties } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-jsonb-properties.type';
|
||||
import { type FlatFieldMetadataPropertiesToCompare } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-properties-to-compare.type';
|
||||
import { type FlatFieldMetadataRelationPropertiesToCompare } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-relation-properties-to-compare.type';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { isStandardMetadata } from 'src/engine/metadata-modules/utils/is-standard-metadata.util';
|
||||
import { type UpdateFieldAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-field-action-v2';
|
||||
import { transformMetadataForComparison } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util';
|
||||
|
||||
export const flatFieldMetadataPropertiesToCompare = [
|
||||
'defaultValue',
|
||||
'description',
|
||||
'icon',
|
||||
'isActive',
|
||||
'isLabelSyncedWithName',
|
||||
'isUnique',
|
||||
'label',
|
||||
'name',
|
||||
'options',
|
||||
'standardOverrides',
|
||||
'settings',
|
||||
] as const satisfies (keyof FlatFieldMetadata)[];
|
||||
|
||||
export type FlatFieldMetadataPropertiesToCompare =
|
||||
(typeof flatFieldMetadataPropertiesToCompare)[number];
|
||||
|
||||
export const flatFieldMetadataEntityJsonbProperties = [
|
||||
'defaultValue',
|
||||
'options',
|
||||
'settings',
|
||||
'standardOverrides',
|
||||
] as const satisfies (keyof FlatFieldMetadata)[];
|
||||
export type FlatFieldMetadataEntityJsonbProperties =
|
||||
(typeof flatFieldMetadataEntityJsonbProperties)[number];
|
||||
|
||||
const shouldNotOverrideDefaultValue = (type: FieldMetadataType) => {
|
||||
return [
|
||||
FieldMetadataType.BOOLEAN,
|
||||
@@ -51,13 +32,13 @@ export const compareTwoFlatFieldMetadata = ({
|
||||
from,
|
||||
to,
|
||||
}: GetWorkspaceMigrationUpdateFieldActionArgs) => {
|
||||
const compareFieldMetadataOptions = {
|
||||
const transformMetadataForComparisonParameters = {
|
||||
shouldIgnoreProperty: (
|
||||
property: string,
|
||||
fieldMetadata: FlatFieldMetadata,
|
||||
) => {
|
||||
if (
|
||||
!flatFieldMetadataPropertiesToCompare.includes(
|
||||
!FLAT_FIELD_METADATA_PROPERTIES_TO_COMPARE.includes(
|
||||
property as FlatFieldMetadataPropertiesToCompare,
|
||||
)
|
||||
) {
|
||||
@@ -73,26 +54,38 @@ export const compareTwoFlatFieldMetadata = ({
|
||||
}
|
||||
|
||||
// Remove below assertion when we authorize relation edition, see https://github.com/twentyhq/twenty/commit/39f6f3c4bb101272a9014e142a842d0801a3c33b
|
||||
if (
|
||||
const isRelationFieldType =
|
||||
isDefined(fieldMetadata.type) &&
|
||||
(fieldMetadata.type === FieldMetadataType.RELATION ||
|
||||
fieldMetadata.type === FieldMetadataType.MORPH_RELATION) &&
|
||||
!['label', 'description', 'isActive'].includes(property)
|
||||
fieldMetadata.type === FieldMetadataType.MORPH_RELATION);
|
||||
|
||||
if (
|
||||
isRelationFieldType &&
|
||||
!FLAT_FIELD_METADATA_RELATION_PROPERTIES_TO_COMPARE.includes(
|
||||
property as FlatFieldMetadataRelationPropertiesToCompare,
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
isStandardMetadata(fieldMetadata) &&
|
||||
property !== 'standardOverrides'
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
propertiesToStringify: flatFieldMetadataEntityJsonbProperties,
|
||||
propertiesToStringify: FLAT_FIELD_METADATA_JSONB_PROPERTIES,
|
||||
};
|
||||
const fromCompare = transformMetadataForComparison(
|
||||
from,
|
||||
compareFieldMetadataOptions,
|
||||
transformMetadataForComparisonParameters,
|
||||
);
|
||||
const toCompare = transformMetadataForComparison(
|
||||
to,
|
||||
compareFieldMetadataOptions,
|
||||
transformMetadataForComparisonParameters,
|
||||
);
|
||||
|
||||
const flatFieldMetadataDifferences = diff(fromCompare, toCompare);
|
||||
@@ -104,7 +97,7 @@ export const compareTwoFlatFieldMetadata = ({
|
||||
case 'CHANGE': {
|
||||
const { oldValue, path, value } = difference;
|
||||
const property = path[0] as FlatFieldMetadataPropertiesToCompare;
|
||||
const isJsonb = flatFieldMetadataEntityJsonbProperties.includes(
|
||||
const isJsonb = FLAT_FIELD_METADATA_JSONB_PROPERTIES.includes(
|
||||
property as FlatFieldMetadataEntityJsonbProperties,
|
||||
);
|
||||
|
||||
|
||||
+25
-27
@@ -4,30 +4,28 @@ import {
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import {
|
||||
fieldMetadataStandardOverridesProperties,
|
||||
type FieldMetadataStandardOverridesProperties,
|
||||
} from 'src/engine/metadata-modules/field-metadata/dtos/field-standard-overrides.dto';
|
||||
import { FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES } from 'src/engine/metadata-modules/field-metadata/constants/field-metadata-standard-overrides-properties.constant';
|
||||
import { type UpdateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/update-field.input';
|
||||
import {
|
||||
FieldMetadataException,
|
||||
FieldMetadataExceptionCode,
|
||||
} from 'src/engine/metadata-modules/field-metadata/field-metadata.exception';
|
||||
import { type FieldMetadataStandardOverridesProperties } from 'src/engine/metadata-modules/field-metadata/types/field-metadata-standard-overrides-properties.type';
|
||||
import { FLAT_FIELD_METADATA_PROPERTIES_TO_COMPARE } from 'src/engine/metadata-modules/flat-field-metadata/constants/flat-field-metadata-properties-to-compare.constant';
|
||||
import { type FieldInputTranspilationResult } from 'src/engine/metadata-modules/flat-field-metadata/types/field-input-transpilation-result.type';
|
||||
import { type FlatFieldMetadataPropertiesToCompare } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata-properties-to-compare.type';
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import {
|
||||
flatFieldMetadataPropertiesToCompare,
|
||||
type FlatFieldMetadataPropertiesToCompare,
|
||||
} from 'src/engine/metadata-modules/flat-field-metadata/utils/compare-two-flat-field-metadata.util';
|
||||
import {} from 'src/engine/metadata-modules/flat-field-metadata/utils/compare-two-flat-field-metadata.util';
|
||||
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
|
||||
import { findFlatFieldMetadataInFlatObjectMetadataMapsWithOnlyFieldId } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-field-metadata-in-flat-object-metadata-maps-with-field-id-only.util';
|
||||
import {
|
||||
ObjectMetadataException,
|
||||
ObjectMetadataExceptionCode,
|
||||
} from 'src/engine/metadata-modules/object-metadata/object-metadata.exception';
|
||||
import { isStandardMetadata } from 'src/engine/metadata-modules/utils/is-standard-metadata.util';
|
||||
|
||||
const fieldMetadataEditableProperties =
|
||||
flatFieldMetadataPropertiesToCompare.filter(
|
||||
FLAT_FIELD_METADATA_PROPERTIES_TO_COMPARE.filter(
|
||||
(
|
||||
property,
|
||||
): property is Exclude<
|
||||
@@ -36,20 +34,20 @@ const fieldMetadataEditableProperties =
|
||||
> => property !== 'standardOverrides',
|
||||
);
|
||||
|
||||
type FromUpdateFieldInputToFlatFieldMetadataToUpdateArgs = {
|
||||
type FromUpdateFieldInputToFlatFieldMetadataArgs = {
|
||||
existingFlatObjectMetadataMaps: FlatObjectMetadataMaps;
|
||||
updateFieldInput: UpdateFieldInput;
|
||||
};
|
||||
export const fromUpdateFieldInputToFlatFieldMetadataToUpdate = ({
|
||||
export const fromUpdateFieldInputToFlatFieldMetadata = ({
|
||||
existingFlatObjectMetadataMaps,
|
||||
updateFieldInput: rawUpdateFieldInput,
|
||||
}: FromUpdateFieldInputToFlatFieldMetadataToUpdateArgs): FieldInputTranspilationResult<FlatFieldMetadata> => {
|
||||
}: FromUpdateFieldInputToFlatFieldMetadataArgs): FieldInputTranspilationResult<FlatFieldMetadata> => {
|
||||
const updateFieldInputInformalProperties =
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
|
||||
rawUpdateFieldInput,
|
||||
['objectMetadataId', 'id'],
|
||||
);
|
||||
const updatedEditableFields = extractAndSanitizeObjectStringFields(
|
||||
const updatedEditableFieldProperties = extractAndSanitizeObjectStringFields(
|
||||
rawUpdateFieldInput,
|
||||
fieldMetadataEditableProperties,
|
||||
);
|
||||
@@ -94,16 +92,14 @@ export const fromUpdateFieldInputToFlatFieldMetadataToUpdate = ({
|
||||
),
|
||||
};
|
||||
}
|
||||
const isStandardField =
|
||||
relatedFlatFieldMetadata.standardId !== null &&
|
||||
!relatedFlatFieldMetadata.isCustom;
|
||||
|
||||
if (isStandardField) {
|
||||
const invalidUpdatedProperties = Object.keys(updatedEditableFields).filter(
|
||||
(property) =>
|
||||
fieldMetadataStandardOverridesProperties.includes(
|
||||
property as FieldMetadataStandardOverridesProperties,
|
||||
),
|
||||
if (isStandardMetadata(relatedFlatFieldMetadata)) {
|
||||
const invalidUpdatedProperties = Object.keys(
|
||||
updatedEditableFieldProperties,
|
||||
).filter((property) =>
|
||||
FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES.includes(
|
||||
property as FieldMetadataStandardOverridesProperties,
|
||||
),
|
||||
);
|
||||
|
||||
if (invalidUpdatedProperties.length > 0) {
|
||||
@@ -117,15 +113,16 @@ export const fromUpdateFieldInputToFlatFieldMetadataToUpdate = ({
|
||||
}
|
||||
|
||||
const updatedStandardFlatFieldMetadata =
|
||||
fieldMetadataStandardOverridesProperties.reduce((acc, property) => {
|
||||
const isPropertyUpdated = updatedEditableFields[property] !== undefined;
|
||||
FIELD_METADATA_STANDARD_OVERRIDES_PROPERTIES.reduce((acc, property) => {
|
||||
const isPropertyUpdated =
|
||||
updatedEditableFieldProperties[property] !== undefined;
|
||||
|
||||
return {
|
||||
...acc,
|
||||
standardOverrides: {
|
||||
...acc.standardOverrides,
|
||||
...(isPropertyUpdated
|
||||
? { [property]: updatedEditableFields[property] }
|
||||
? { [property]: updatedEditableFieldProperties[property] }
|
||||
: {}),
|
||||
},
|
||||
};
|
||||
@@ -139,12 +136,13 @@ export const fromUpdateFieldInputToFlatFieldMetadataToUpdate = ({
|
||||
|
||||
const updatedFlatFieldMetadata = fieldMetadataEditableProperties.reduce(
|
||||
(acc, property) => {
|
||||
const isPropertyUpdated = updatedEditableFields[property] !== undefined;
|
||||
const isPropertyUpdated =
|
||||
updatedEditableFieldProperties[property] !== undefined;
|
||||
|
||||
return {
|
||||
...acc,
|
||||
...(isPropertyUpdated
|
||||
? { [property]: updatedEditableFields[property] }
|
||||
? { [property]: updatedEditableFieldProperties[property] }
|
||||
: {}),
|
||||
};
|
||||
},
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { computeMetadataNameFromLabel } from 'src/engine/metadata-modules/utils/validate-name-and-label-are-sync-or-throw.util';
|
||||
|
||||
export const isFlatFieldMetadataNameSyncedWithLabel = (
|
||||
flatFieldMetadata: Pick<
|
||||
FlatFieldMetadata,
|
||||
'name' | 'isLabelSyncedWithName' | 'label'
|
||||
>,
|
||||
) => {
|
||||
const computedName = computeMetadataNameFromLabel(flatFieldMetadata.label);
|
||||
|
||||
return flatFieldMetadata.name === computedName;
|
||||
};
|
||||
-2
@@ -8,8 +8,6 @@ import {
|
||||
import { type ValidateOneFieldMetadataArgs } from 'src/engine/metadata-modules/flat-field-metadata/services/flat-field-metadata-validator.service';
|
||||
import { type FailedFlatFieldMetadataValidationExceptions } from 'src/engine/metadata-modules/flat-field-metadata/types/failed-flat-field-metadata-validation.type';
|
||||
|
||||
// Remark: This is duplicated with api metadata transpilers exceptions handlers
|
||||
// We might wanna have an NotValidatedFlatFieldMetadata and NotValidatedFlatObjectMetadata, in order to avoid
|
||||
export const validateRelationFlatFieldMetadata = async ({
|
||||
existingFlatObjectMetadataMaps,
|
||||
flatFieldMetadataToValidate: {
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
|
||||
export const FLAT_OBJECT_METADATA_JSONB_PROPERTIES = [
|
||||
'standardOverrides',
|
||||
] as const satisfies (keyof FlatObjectMetadata)[];
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
|
||||
export const FLAT_OBJECT_METADATA_PROPERTIES_TO_COMPARE = [
|
||||
'description',
|
||||
'icon',
|
||||
'isActive',
|
||||
'isLabelSyncedWithName',
|
||||
'labelPlural',
|
||||
'labelSingular',
|
||||
'namePlural',
|
||||
'nameSingular',
|
||||
'standardOverrides', // Only if standard
|
||||
] as const satisfies (keyof FlatObjectMetadata)[];
|
||||
+102
-63
@@ -10,13 +10,14 @@ import { addFlatFieldMetadataInFlatObjectMetadataMapsOrThrow } from 'src/engine/
|
||||
import { addFlatObjectMetadataToFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/add-flat-object-metadata-to-flat-object-metadata-maps-or-throw.util';
|
||||
import { FailedFlatObjectMetadataValidationExceptions } from 'src/engine/metadata-modules/flat-object-metadata/types/failed-flat-object-metadata-validation.type';
|
||||
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { validateFlatObjectMetadataLabel } from 'src/engine/metadata-modules/flat-object-metadata/validators/validate-flat-object-metadata-label.validator';
|
||||
import { validateFlatObjectMetadataNames } from 'src/engine/metadata-modules/flat-object-metadata/validators/validate-flat-object-metadata-name.validator';
|
||||
import { areFlatObjectMetadataNamesSyncedWithLabels } from 'src/engine/metadata-modules/flat-object-metadata/utils/are-flat-object-metadata-names-synced-with-labels.util';
|
||||
import { validateFlatObjectMetadataIdentifiers } from 'src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-identifiers.util';
|
||||
import { validateFlatObjectMetadataLabel } from 'src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-label.util';
|
||||
import { validateFlatObjectMetadataNames } from 'src/engine/metadata-modules/flat-object-metadata/validators/utils/validate-flat-object-metadata-name.util';
|
||||
import {
|
||||
ObjectMetadataException,
|
||||
ObjectMetadataExceptionCode,
|
||||
} from 'src/engine/metadata-modules/object-metadata/object-metadata.exception';
|
||||
import { computeMetadataNameFromLabel } from 'src/engine/metadata-modules/utils/validate-name-and-label-are-sync-or-throw.util';
|
||||
import { doesOtherObjectWithSameNameExists } from 'src/engine/metadata-modules/utils/validate-no-other-object-with-same-name-exists-or-throw.util';
|
||||
|
||||
export type ValidateOneFlatObjectMetadataArgs = {
|
||||
@@ -32,6 +33,40 @@ export class FlatObjectMetadataValidatorService {
|
||||
private readonly flatFieldMetadataValidatorService: FlatFieldMetadataValidatorService,
|
||||
) {}
|
||||
|
||||
public validateFlatObjectMetadataUpdate({
|
||||
existingFlatObjectMetadataMaps,
|
||||
updatedFlatObjectMetadata,
|
||||
}: {
|
||||
existingFlatObjectMetadataMaps: FlatObjectMetadataMaps;
|
||||
updatedFlatObjectMetadata: FlatObjectMetadata;
|
||||
}) {
|
||||
const existingFlatObjectMetadata =
|
||||
existingFlatObjectMetadataMaps.byId[updatedFlatObjectMetadata.id];
|
||||
|
||||
if (!isDefined(existingFlatObjectMetadata)) {
|
||||
return [
|
||||
new ObjectMetadataException(
|
||||
t`Object to update not found`,
|
||||
ObjectMetadataExceptionCode.OBJECT_METADATA_NOT_FOUND,
|
||||
),
|
||||
];
|
||||
}
|
||||
const errors: FailedFlatObjectMetadataValidationExceptions[] = [];
|
||||
|
||||
errors.push(
|
||||
...this.validateFlatObjectMetadataNameAndLabels({
|
||||
existingFlatObjectMetadataMaps,
|
||||
flatObjectMetadataToValidate: updatedFlatObjectMetadata,
|
||||
}),
|
||||
);
|
||||
|
||||
errors.push(
|
||||
...validateFlatObjectMetadataIdentifiers(existingFlatObjectMetadata),
|
||||
);
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
public validateFlatObjectMetadataDeletion({
|
||||
existingFlatObjectMetadataMaps,
|
||||
objectMetadataToDeleteId,
|
||||
@@ -47,7 +82,7 @@ export class FlatObjectMetadataValidatorService {
|
||||
if (!isDefined(flatObjectMetadataToDelete)) {
|
||||
errors.push(
|
||||
new ObjectMetadataException(
|
||||
t`Object does not exist`,
|
||||
t`Object to delete not found`,
|
||||
ObjectMetadataExceptionCode.OBJECT_METADATA_NOT_FOUND,
|
||||
),
|
||||
);
|
||||
@@ -93,20 +128,6 @@ export class FlatObjectMetadataValidatorService {
|
||||
}: ValidateOneFlatObjectMetadataArgs) {
|
||||
const errors: FailedFlatObjectMetadataValidationExceptions[] = [];
|
||||
|
||||
errors.push(
|
||||
...validateFlatObjectMetadataNames({
|
||||
namePlural: flatObjectMetadataToValidate.namePlural,
|
||||
nameSingular: flatObjectMetadataToValidate.nameSingular,
|
||||
}),
|
||||
);
|
||||
|
||||
errors.push(
|
||||
...validateFlatObjectMetadataLabel({
|
||||
labelPlural: flatObjectMetadataToValidate.labelPlural,
|
||||
labelSingular: flatObjectMetadataToValidate.labelSingular,
|
||||
}),
|
||||
);
|
||||
|
||||
if (flatObjectMetadataToValidate.isRemote) {
|
||||
errors.push(
|
||||
new ObjectMetadataException(
|
||||
@@ -116,51 +137,12 @@ export class FlatObjectMetadataValidatorService {
|
||||
);
|
||||
}
|
||||
|
||||
if (flatObjectMetadataToValidate.isLabelSyncedWithName === true) {
|
||||
const computedNameSingular = computeMetadataNameFromLabel(
|
||||
flatObjectMetadataToValidate.labelSingular,
|
||||
);
|
||||
|
||||
if (computedNameSingular !== flatObjectMetadataToValidate.nameSingular) {
|
||||
errors.push(
|
||||
new ObjectMetadataException(
|
||||
t`Singular name is not synced with singular label`,
|
||||
ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
const computedNamePlural = computeMetadataNameFromLabel(
|
||||
flatObjectMetadataToValidate.labelPlural,
|
||||
);
|
||||
|
||||
if (computedNamePlural !== flatObjectMetadataToValidate.namePlural) {
|
||||
errors.push(
|
||||
new ObjectMetadataException(
|
||||
t`Plural name is not synced with plural label`,
|
||||
ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
doesOtherObjectWithSameNameExists({
|
||||
objectMetadataNamePlural: flatObjectMetadataToValidate.namePlural,
|
||||
objectMetadataNameSingular: flatObjectMetadataToValidate.nameSingular,
|
||||
objectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
})
|
||||
) {
|
||||
errors.push(
|
||||
new ObjectMetadataException(
|
||||
'Object already exists',
|
||||
ObjectMetadataExceptionCode.OBJECT_ALREADY_EXISTS,
|
||||
{
|
||||
userFriendlyMessage: t`Object already exists`,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
errors.push(
|
||||
...this.validateFlatObjectMetadataNameAndLabels({
|
||||
existingFlatObjectMetadataMaps,
|
||||
flatObjectMetadataToValidate,
|
||||
}),
|
||||
);
|
||||
|
||||
const allFlatFieldMetadatasValidationErrors: FailedFlatFieldMetadataValidationExceptions[] =
|
||||
[];
|
||||
@@ -206,4 +188,61 @@ export class FlatObjectMetadataValidatorService {
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
private validateFlatObjectMetadataNameAndLabels({
|
||||
existingFlatObjectMetadataMaps,
|
||||
flatObjectMetadataToValidate,
|
||||
}: {
|
||||
flatObjectMetadataToValidate: FlatObjectMetadata;
|
||||
existingFlatObjectMetadataMaps: FlatObjectMetadataMaps;
|
||||
}) {
|
||||
const errors: FailedFlatObjectMetadataValidationExceptions[] = [];
|
||||
|
||||
errors.push(
|
||||
...validateFlatObjectMetadataNames({
|
||||
namePlural: flatObjectMetadataToValidate.namePlural,
|
||||
nameSingular: flatObjectMetadataToValidate.nameSingular,
|
||||
}),
|
||||
);
|
||||
|
||||
errors.push(
|
||||
...validateFlatObjectMetadataLabel({
|
||||
labelPlural: flatObjectMetadataToValidate.labelPlural,
|
||||
labelSingular: flatObjectMetadataToValidate.labelSingular,
|
||||
}),
|
||||
);
|
||||
|
||||
if (
|
||||
flatObjectMetadataToValidate.isLabelSyncedWithName &&
|
||||
!areFlatObjectMetadataNamesSyncedWithLabels(flatObjectMetadataToValidate)
|
||||
) {
|
||||
errors.push(
|
||||
new ObjectMetadataException(
|
||||
t`Names are not synced with labels`,
|
||||
ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
doesOtherObjectWithSameNameExists({
|
||||
objectMetadataNamePlural: flatObjectMetadataToValidate.namePlural,
|
||||
objectMetadataNameSingular: flatObjectMetadataToValidate.nameSingular,
|
||||
objectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
existingObjectMetadataId: flatObjectMetadataToValidate.id,
|
||||
})
|
||||
) {
|
||||
errors.push(
|
||||
new ObjectMetadataException(
|
||||
'Object already exists',
|
||||
ObjectMetadataExceptionCode.OBJECT_ALREADY_EXISTS,
|
||||
{
|
||||
userFriendlyMessage: t`Object already exists`,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import { type FLAT_OBJECT_METADATA_JSONB_PROPERTIES } from 'src/engine/metadata-modules/flat-object-metadata/constants/flat-object-metadata-jsonb-properties.constant';
|
||||
|
||||
export type FlatObjectMetadataEntityJsonbProperties =
|
||||
(typeof FLAT_OBJECT_METADATA_JSONB_PROPERTIES)[number];
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import { type FLAT_OBJECT_METADATA_PROPERTIES_TO_COMPARE } from 'src/engine/metadata-modules/flat-object-metadata/constants/flat-object-metadata-properties-to-compare.constant';
|
||||
|
||||
export type FlatObjectMetadataPropertiesToCompare =
|
||||
(typeof FLAT_OBJECT_METADATA_PROPERTIES_TO_COMPARE)[number];
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { computeMetadataNameFromLabel } from 'src/engine/metadata-modules/utils/validate-name-and-label-are-sync-or-throw.util';
|
||||
|
||||
export const areFlatObjectMetadataNamesSyncedWithLabels = (
|
||||
flatObjectdMetadata: Pick<
|
||||
FlatObjectMetadata,
|
||||
'namePlural' | 'nameSingular' | 'labelPlural' | 'labelSingular'
|
||||
>,
|
||||
) => {
|
||||
const [computedSingularName, computedPluralName] = [
|
||||
flatObjectdMetadata.labelSingular,
|
||||
flatObjectdMetadata.labelPlural,
|
||||
].map(computeMetadataNameFromLabel);
|
||||
|
||||
return (
|
||||
flatObjectdMetadata.nameSingular === computedSingularName &&
|
||||
flatObjectdMetadata.namePlural === computedPluralName
|
||||
);
|
||||
};
|
||||
+52
-43
@@ -1,36 +1,53 @@
|
||||
import omit from 'lodash.omit';
|
||||
import diff from 'microdiff';
|
||||
import { type FromTo } from 'twenty-shared/types';
|
||||
import { assertUnreachable } from 'twenty-shared/utils';
|
||||
import { assertUnreachable, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { FLAT_OBJECT_METADATA_JSONB_PROPERTIES } from 'src/engine/metadata-modules/flat-object-metadata/constants/flat-object-metadata-jsonb-properties.constant';
|
||||
import { FLAT_OBJECT_METADATA_PROPERTIES_TO_COMPARE } from 'src/engine/metadata-modules/flat-object-metadata/constants/flat-object-metadata-properties-to-compare.constant';
|
||||
import { type FlatObjectMetadataEntityJsonbProperties } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata-jsonb-properties.type';
|
||||
import { type FlatObjectMetadataPropertiesToCompare } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata-properties-to-compare.type';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { isStandardMetadata } from 'src/engine/metadata-modules/utils/is-standard-metadata.util';
|
||||
import { type UpdateObjectAction } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-object-action-v2';
|
||||
import { transformMetadataForComparison } from 'src/engine/workspace-manager/workspace-sync-metadata/comparators/utils/transform-metadata-for-comparison.util';
|
||||
|
||||
const flatObjectMetadataPropertiesToCompare = [
|
||||
'description',
|
||||
'icon',
|
||||
'isActive',
|
||||
'isLabelSyncedWithName',
|
||||
'labelPlural',
|
||||
'labelSingular',
|
||||
'namePlural',
|
||||
'nameSingular',
|
||||
'standardOverrides', // Only if standard
|
||||
] as const satisfies (keyof FlatObjectMetadata)[];
|
||||
|
||||
export type FlatObjectMetadataPropertiesToCompare =
|
||||
(typeof flatObjectMetadataPropertiesToCompare)[number];
|
||||
|
||||
/**
|
||||
* This comparator handles update on colliding uniqueIdentifier flatObjectMetadata
|
||||
*/
|
||||
export const compareTwoFlatObjectMetadata = ({
|
||||
from,
|
||||
to,
|
||||
}: FromTo<FlatObjectMetadata>) => {
|
||||
const fromCompare = transformMetadataForComparison(from, {});
|
||||
const toCompare = transformMetadataForComparison(to, {});
|
||||
const transformMetadataForComparisonParameters = {
|
||||
propertiesToStringify: FLAT_OBJECT_METADATA_JSONB_PROPERTIES,
|
||||
shouldIgnoreProperty: (
|
||||
property: string,
|
||||
flatObjectMetadata: FlatObjectMetadata,
|
||||
) => {
|
||||
if (
|
||||
!FLAT_OBJECT_METADATA_PROPERTIES_TO_COMPARE.includes(
|
||||
property as FlatObjectMetadataPropertiesToCompare,
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
isStandardMetadata(flatObjectMetadata) &&
|
||||
property !== 'standardOverrides'
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
};
|
||||
const fromCompare = transformMetadataForComparison(
|
||||
from,
|
||||
transformMetadataForComparisonParameters,
|
||||
);
|
||||
const toCompare = transformMetadataForComparison(
|
||||
to,
|
||||
transformMetadataForComparisonParameters,
|
||||
);
|
||||
const objectMetadataDifference = diff(fromCompare, omit(toCompare, 'fields'));
|
||||
|
||||
return objectMetadataDifference.flatMap<
|
||||
@@ -38,32 +55,24 @@ export const compareTwoFlatObjectMetadata = ({
|
||||
>((difference) => {
|
||||
switch (difference.type) {
|
||||
case 'CHANGE': {
|
||||
if (
|
||||
difference.oldValue === null &&
|
||||
(difference.value === null || difference.value === undefined)
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
const property = difference.path[0];
|
||||
const { oldValue, path, value } = difference;
|
||||
const property = path[0] as FlatObjectMetadataPropertiesToCompare;
|
||||
const isJsonb = FLAT_OBJECT_METADATA_JSONB_PROPERTIES.includes(
|
||||
property as FlatObjectMetadataEntityJsonbProperties,
|
||||
);
|
||||
|
||||
// TODO investigate why it would be a number, in case of array I guess ?
|
||||
if (typeof property === 'number') {
|
||||
return [];
|
||||
}
|
||||
|
||||
// Could be handled directly from the diff we do above
|
||||
if (
|
||||
!flatObjectMetadataPropertiesToCompare.includes(
|
||||
property as FlatObjectMetadataPropertiesToCompare,
|
||||
)
|
||||
) {
|
||||
return [];
|
||||
if (isJsonb) {
|
||||
return {
|
||||
from: isDefined(oldValue) ? JSON.parse(oldValue) : oldValue,
|
||||
to: isDefined(value) ? JSON.parse(value) : value,
|
||||
property,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
property: property as FlatObjectMetadataPropertiesToCompare,
|
||||
from: difference.oldValue,
|
||||
to: difference.value,
|
||||
from: oldValue,
|
||||
to: value,
|
||||
property,
|
||||
};
|
||||
}
|
||||
case 'CREATE':
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
import {
|
||||
extractAndSanitizeObjectStringFields,
|
||||
isDefined,
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
|
||||
import { findFlatObjectMetadataInFlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/find-flat-object-metadata-in-flat-object-metadata-maps.util';
|
||||
import { FLAT_OBJECT_METADATA_PROPERTIES_TO_COMPARE } from 'src/engine/metadata-modules/flat-object-metadata/constants/flat-object-metadata-properties-to-compare.constant';
|
||||
import { type FlatObjectMetadataPropertiesToCompare } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata-properties-to-compare.type';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { OBJECT_METADATA_STANDARD_OVERRIDES_PROPERTIES } from 'src/engine/metadata-modules/object-metadata/constants/object-metadata-standard-overrides-properties.constant';
|
||||
import { type UpdateOneObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/update-object.input';
|
||||
import {
|
||||
ObjectMetadataException,
|
||||
ObjectMetadataExceptionCode,
|
||||
} from 'src/engine/metadata-modules/object-metadata/object-metadata.exception';
|
||||
import { type ObjectMetadataStandardOverridesProperties } from 'src/engine/metadata-modules/object-metadata/types/object-metadata-standard-overrides-properties.types';
|
||||
import { isStandardMetadata } from 'src/engine/metadata-modules/utils/is-standard-metadata.util';
|
||||
|
||||
type FromUpdateObjectInputToFlatObjectMetadataArgs = {
|
||||
existingFlatObjectMetadataMaps: FlatObjectMetadataMaps;
|
||||
updateObjectInput: UpdateOneObjectInput;
|
||||
};
|
||||
|
||||
const objectMetadataEditableProperties =
|
||||
FLAT_OBJECT_METADATA_PROPERTIES_TO_COMPARE.filter(
|
||||
(
|
||||
property,
|
||||
): property is Exclude<
|
||||
FlatObjectMetadataPropertiesToCompare,
|
||||
'standardOverrides'
|
||||
> => property !== 'standardOverrides',
|
||||
);
|
||||
|
||||
export const fromUpdateObjectInputToFlatObjectMetadata = ({
|
||||
existingFlatObjectMetadataMaps,
|
||||
updateObjectInput: rawUpdateObjectInput,
|
||||
}: FromUpdateObjectInputToFlatObjectMetadataArgs): FlatObjectMetadata => {
|
||||
const { id: objectMetadataIdToUpdate } =
|
||||
trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties(
|
||||
rawUpdateObjectInput,
|
||||
['id'],
|
||||
);
|
||||
const updatedEditableObjectProperties = extractAndSanitizeObjectStringFields(
|
||||
rawUpdateObjectInput.update,
|
||||
objectMetadataEditableProperties,
|
||||
);
|
||||
|
||||
const flatObjectMetadataToUpdate =
|
||||
findFlatObjectMetadataInFlatObjectMetadataMaps({
|
||||
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
objectMetadataId: objectMetadataIdToUpdate,
|
||||
});
|
||||
|
||||
if (!isDefined(flatObjectMetadataToUpdate)) {
|
||||
throw new ObjectMetadataException(
|
||||
'Object to update not found',
|
||||
ObjectMetadataExceptionCode.OBJECT_METADATA_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
if (isStandardMetadata(flatObjectMetadataToUpdate)) {
|
||||
const invalidUpdatedProperties = Object.keys(
|
||||
updatedEditableObjectProperties,
|
||||
).filter(
|
||||
(property) =>
|
||||
!OBJECT_METADATA_STANDARD_OVERRIDES_PROPERTIES.includes(
|
||||
property as ObjectMetadataStandardOverridesProperties,
|
||||
),
|
||||
);
|
||||
|
||||
if (invalidUpdatedProperties.length > 0) {
|
||||
throw new ObjectMetadataException(
|
||||
`Cannot edit standard object metadata properties: ${invalidUpdatedProperties.join(', ')}`,
|
||||
ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT,
|
||||
);
|
||||
}
|
||||
|
||||
const updatedStandardFlatObjectdMetadata =
|
||||
OBJECT_METADATA_STANDARD_OVERRIDES_PROPERTIES.reduce((acc, property) => {
|
||||
const isPropertyUpdated =
|
||||
updatedEditableObjectProperties[property] !== undefined;
|
||||
|
||||
return {
|
||||
...acc,
|
||||
standardOverrides: {
|
||||
...acc.standardOverrides,
|
||||
...(isPropertyUpdated
|
||||
? { [property]: updatedEditableObjectProperties[property] }
|
||||
: {}),
|
||||
},
|
||||
};
|
||||
}, flatObjectMetadataToUpdate);
|
||||
|
||||
return updatedStandardFlatObjectdMetadata;
|
||||
}
|
||||
|
||||
const updatedFlatObjectMetadata = objectMetadataEditableProperties.reduce(
|
||||
(acc, property) => {
|
||||
const isPropertyUpdated =
|
||||
updatedEditableObjectProperties[property] !== undefined;
|
||||
|
||||
return {
|
||||
...acc,
|
||||
...(isPropertyUpdated
|
||||
? { [property]: updatedEditableObjectProperties[property] }
|
||||
: {}),
|
||||
};
|
||||
},
|
||||
flatObjectMetadataToUpdate,
|
||||
);
|
||||
|
||||
return updatedFlatObjectMetadata;
|
||||
};
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
import { t } from '@lingui/core/macro';
|
||||
import {
|
||||
isDefined,
|
||||
isLabelIdentifierFieldMetadataTypes,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import {
|
||||
ObjectMetadataException,
|
||||
ObjectMetadataExceptionCode,
|
||||
} from 'src/engine/metadata-modules/object-metadata/object-metadata.exception';
|
||||
|
||||
export const validateFlatObjectMetadataIdentifiers = (
|
||||
flatObjectMetadata: FlatObjectMetadata,
|
||||
) => {
|
||||
const errors: ObjectMetadataException[] = [];
|
||||
|
||||
const { labelIdentifierFieldMetadataId, imageIdentifierFieldMetadataId } =
|
||||
flatObjectMetadata;
|
||||
|
||||
if (isDefined(labelIdentifierFieldMetadataId)) {
|
||||
const relatedFlatFieldMetadata = flatObjectMetadata.flatFieldMetadatas.find(
|
||||
(flatFieldMetadata) =>
|
||||
flatFieldMetadata.id === labelIdentifierFieldMetadataId,
|
||||
);
|
||||
|
||||
if (!isDefined(relatedFlatFieldMetadata)) {
|
||||
errors.push(
|
||||
new ObjectMetadataException(
|
||||
'labelIdentifierFieldMetadataId validation failed: related field metadata not found',
|
||||
ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT,
|
||||
{
|
||||
userFriendlyMessage: t`Field declared as label identifier not found`,
|
||||
},
|
||||
),
|
||||
);
|
||||
} else if (
|
||||
!isLabelIdentifierFieldMetadataTypes(relatedFlatFieldMetadata.type)
|
||||
) {
|
||||
errors.push(
|
||||
new ObjectMetadataException(
|
||||
'labelIdentifierFieldMetadataId validation failed: field type not compatible',
|
||||
ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT,
|
||||
{
|
||||
userFriendlyMessage: t`Field cannot be used as label identifier`,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (isDefined(imageIdentifierFieldMetadataId)) {
|
||||
const relatedFlatFieldMetadata = flatObjectMetadata.flatFieldMetadatas.find(
|
||||
(flatFieldMetadata) =>
|
||||
flatFieldMetadata.id === imageIdentifierFieldMetadataId,
|
||||
);
|
||||
|
||||
if (!isDefined(relatedFlatFieldMetadata)) {
|
||||
errors.push(
|
||||
new ObjectMetadataException(
|
||||
'imageIdentifierFieldMetadataId validation failed: related field metadata not found',
|
||||
ObjectMetadataExceptionCode.INVALID_OBJECT_INPUT,
|
||||
{
|
||||
userFriendlyMessage: t`Field declared as image identifier not found`,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
};
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
import { type FlatObjectMetadataPropertiesToCompare } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata-properties-to-compare.type';
|
||||
|
||||
export const OBJECT_METADATA_STANDARD_OVERRIDES_PROPERTIES = [
|
||||
'labelSingular',
|
||||
'labelPlural',
|
||||
'description',
|
||||
'icon',
|
||||
] as const satisfies FlatObjectMetadataPropertiesToCompare[];
|
||||
+84
-1
@@ -8,14 +8,17 @@ import { addFlatObjectMetadataToFlatObjectMetadataMapsOrThrow } from 'src/engine
|
||||
import { deleteFieldFromFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/delete-field-from-flat-object-metadata-maps-or-throw.util';
|
||||
import { deleteObjectFromFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/delete-object-from-flat-object-metadata-maps-or-throw.util';
|
||||
import { getSubFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/get-sub-flat-object-metadata-maps-or-throw.util';
|
||||
import { replaceFlatObjectMetadataInFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/replace-flat-object-metadata-in-flat-object-metadata-maps-or-throw.util';
|
||||
import { FlatObjectMetadataValidatorService } from 'src/engine/metadata-modules/flat-object-metadata/services/flat-object-metadata-validator.service';
|
||||
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { fromCreateObjectInputToFlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-create-object-input-to-flat-object-metadata.util';
|
||||
import { fromDeleteObjectInputToFlatFieldMetadatasToDelete } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-delete-object-input-to-flat-field-metadatas-to-delete.util';
|
||||
import { fromFlatObjectMetadataToObjectMetadataDto } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-flat-object-metadata-to-object-metadata-dto.util';
|
||||
import { fromUpdateObjectInputToFlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-update-object-input-to-flat-object-metadata.util';
|
||||
import { CreateObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/create-object.input';
|
||||
import { DeleteOneObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/delete-object.input';
|
||||
import { ObjectMetadataDTO } from 'src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto';
|
||||
import { UpdateOneObjectInput } from 'src/engine/metadata-modules/object-metadata/dtos/update-object.input';
|
||||
import {
|
||||
ObjectMetadataException,
|
||||
ObjectMetadataExceptionCode,
|
||||
@@ -33,6 +36,86 @@ export class ObjectMetadataServiceV2 {
|
||||
private readonly flatObjectMetadataValidatorService: FlatObjectMetadataValidatorService,
|
||||
) {}
|
||||
|
||||
async updateOne({
|
||||
updateObjectInput,
|
||||
workspaceId,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
updateObjectInput: UpdateOneObjectInput;
|
||||
}): Promise<ObjectMetadataDTO> {
|
||||
const { flatObjectMetadataMaps: existingFlatObjectMetadataMaps } =
|
||||
await this.workspaceMetadataCacheService.getExistingOrRecomputeFlatObjectMetadataMaps(
|
||||
{
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
|
||||
const optimisticallyUpdatedFlatObjectMetadata =
|
||||
fromUpdateObjectInputToFlatObjectMetadata({
|
||||
existingFlatObjectMetadataMaps,
|
||||
updateObjectInput,
|
||||
});
|
||||
|
||||
const validationErrors =
|
||||
this.flatObjectMetadataValidatorService.validateFlatObjectMetadataUpdate({
|
||||
existingFlatObjectMetadataMaps,
|
||||
updatedFlatObjectMetadata: optimisticallyUpdatedFlatObjectMetadata,
|
||||
});
|
||||
|
||||
if (validationErrors.length > 0) {
|
||||
throw new MultipleMetadataValidationErrors(
|
||||
validationErrors,
|
||||
'Multiple validation errors occurred while updating object',
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const fromFlatObjectMetadataMaps = getSubFlatObjectMetadataMapsOrThrow({
|
||||
flatObjectMetadataMaps: existingFlatObjectMetadataMaps,
|
||||
objectMetadataIds: [optimisticallyUpdatedFlatObjectMetadata.id],
|
||||
});
|
||||
const toFlatObjectMetadataMaps =
|
||||
replaceFlatObjectMetadataInFlatObjectMetadataMapsOrThrow({
|
||||
flatObjectMetadata: optimisticallyUpdatedFlatObjectMetadata,
|
||||
flatObjectMetadataMaps: fromFlatObjectMetadataMaps,
|
||||
});
|
||||
const workspaceMigration = this.workspaceMigrationBuilderV2.build({
|
||||
fromFlatObjectMetadataMaps,
|
||||
toFlatObjectMetadataMaps,
|
||||
inferDeletionFromMissingObjectFieldIndex: false,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
await this.workspaceMigrationRunnerV2Service.run(workspaceMigration);
|
||||
} catch {
|
||||
throw new ObjectMetadataException(
|
||||
'Workspace migration failed to run',
|
||||
ObjectMetadataExceptionCode.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
|
||||
const { flatObjectMetadataMaps: recomputedFlatObjectMetadataMaps } =
|
||||
await this.workspaceMetadataCacheService.getExistingOrRecomputeFlatObjectMetadataMaps(
|
||||
{
|
||||
workspaceId,
|
||||
},
|
||||
);
|
||||
|
||||
const updatedFlatObjectMetadata =
|
||||
recomputedFlatObjectMetadataMaps.byId[
|
||||
optimisticallyUpdatedFlatObjectMetadata.id
|
||||
];
|
||||
|
||||
if (!isDefined(updatedFlatObjectMetadata)) {
|
||||
throw new ObjectMetadataException(
|
||||
'Updated object metadata not found in recomputed cache',
|
||||
ObjectMetadataExceptionCode.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
|
||||
return fromFlatObjectMetadataToObjectMetadataDto(updatedFlatObjectMetadata);
|
||||
}
|
||||
|
||||
async deleteOne({
|
||||
deleteObjectInput,
|
||||
workspaceId,
|
||||
@@ -189,7 +272,7 @@ export class ObjectMetadataServiceV2 {
|
||||
|
||||
if (!isDefined(createdFlatObjectMetadata)) {
|
||||
throw new ObjectMetadataException(
|
||||
'Fail to find just created object metadata',
|
||||
'Created object metadata not found in recomputed cache',
|
||||
ObjectMetadataExceptionCode.OBJECT_METADATA_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
+30
-5
@@ -8,6 +8,8 @@ import {
|
||||
Resolver,
|
||||
} from '@nestjs/graphql';
|
||||
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
|
||||
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
|
||||
import { I18nContext } from 'src/engine/core-modules/i18n/types/i18n-context.type';
|
||||
@@ -25,6 +27,7 @@ import {
|
||||
type UpdateObjectPayload,
|
||||
} from 'src/engine/metadata-modules/object-metadata/dtos/update-object.input';
|
||||
import { BeforeUpdateOneObject } from 'src/engine/metadata-modules/object-metadata/hooks/before-update-one-object.hook';
|
||||
import { ObjectMetadataServiceV2 } from 'src/engine/metadata-modules/object-metadata/object-metadata-v2.service';
|
||||
import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service';
|
||||
import { objectMetadataGraphqlApiExceptionHandler } from 'src/engine/metadata-modules/object-metadata/utils/object-metadata-graphql-api-exception-handler.util';
|
||||
import { resolveObjectMetadataStandardOverride } from 'src/engine/metadata-modules/object-metadata/utils/resolve-object-metadata-standard-override.util';
|
||||
@@ -42,6 +45,8 @@ export class ObjectMetadataResolver {
|
||||
constructor(
|
||||
private readonly objectMetadataService: ObjectMetadataService,
|
||||
private readonly beforeUpdateOneObject: BeforeUpdateOneObject<UpdateObjectPayload>,
|
||||
private readonly featureFlagService: FeatureFlagService,
|
||||
private readonly objectMetadataServiceV2: ObjectMetadataServiceV2,
|
||||
) {}
|
||||
|
||||
@ResolveField(() => String, { nullable: true })
|
||||
@@ -112,15 +117,35 @@ export class ObjectMetadataResolver {
|
||||
@UseGuards(SettingsPermissionsGuard(PermissionFlagType.DATA_MODEL))
|
||||
@Mutation(() => ObjectMetadataDTO)
|
||||
async updateOneObject(
|
||||
@Args('input') input: UpdateOneObjectInput,
|
||||
@Args('input') updateObjectInput: UpdateOneObjectInput,
|
||||
@AuthWorkspace() { id: workspaceId }: Workspace,
|
||||
@Context() context: I18nContext,
|
||||
) {
|
||||
try {
|
||||
const updatedInput = (await this.beforeUpdateOneObject.run(input, {
|
||||
const isWorkspaceMigrationV2Enabled =
|
||||
await this.featureFlagService.isFeatureEnabled(
|
||||
FeatureFlagKey.IS_WORKSPACE_MIGRATION_V2_ENABLED,
|
||||
workspaceId,
|
||||
locale: context.req.locale,
|
||||
})) as UpdateOneObjectInput;
|
||||
);
|
||||
|
||||
if (isWorkspaceMigrationV2Enabled) {
|
||||
try {
|
||||
return await this.objectMetadataServiceV2.updateOne({
|
||||
updateObjectInput,
|
||||
workspaceId,
|
||||
});
|
||||
} catch (error) {
|
||||
objectMetadataGraphqlApiExceptionHandler(error);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const updatedInput = (await this.beforeUpdateOneObject.run(
|
||||
updateObjectInput,
|
||||
{
|
||||
workspaceId,
|
||||
locale: context.req.locale,
|
||||
},
|
||||
)) as UpdateOneObjectInput;
|
||||
|
||||
return await this.objectMetadataService.updateOneObject(
|
||||
updatedInput,
|
||||
|
||||
+9
-8
@@ -110,7 +110,6 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
workspaceId: createObjectInput.workspaceId,
|
||||
});
|
||||
|
||||
// Since V2 returns FlatObjectMetadata, we need to fetch the created entity
|
||||
const createdObjectMetadata = await this.objectMetadataRepository.findOne(
|
||||
{
|
||||
where: {
|
||||
@@ -288,7 +287,7 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
}
|
||||
|
||||
public async updateOneObject(
|
||||
input: UpdateOneObjectInput,
|
||||
updateObjectInput: UpdateOneObjectInput,
|
||||
workspaceId: string,
|
||||
): Promise<ObjectMetadataEntity> {
|
||||
const mainDataSource =
|
||||
@@ -306,14 +305,16 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
|
||||
await this.workspaceMetadataCacheService.getExistingOrRecomputeMetadataMaps(
|
||||
{ workspaceId },
|
||||
);
|
||||
const inputId = input.id;
|
||||
const inputId = updateObjectInput.id;
|
||||
const inputPayload = {
|
||||
...input.update,
|
||||
...(isDefined(input.update.labelSingular)
|
||||
? { labelSingular: capitalize(input.update.labelSingular) }
|
||||
...updateObjectInput.update,
|
||||
...(isDefined(updateObjectInput.update.labelSingular)
|
||||
? {
|
||||
labelSingular: capitalize(updateObjectInput.update.labelSingular),
|
||||
}
|
||||
: {}),
|
||||
...(isDefined(input.update.labelPlural)
|
||||
? { labelPlural: capitalize(input.update.labelPlural) }
|
||||
...(isDefined(updateObjectInput.update.labelPlural)
|
||||
? { labelPlural: capitalize(updateObjectInput.update.labelPlural) }
|
||||
: {}),
|
||||
};
|
||||
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
import { type OBJECT_METADATA_STANDARD_OVERRIDES_PROPERTIES } from 'src/engine/metadata-modules/object-metadata/constants/object-metadata-standard-overrides-properties.constant';
|
||||
|
||||
export type ObjectMetadataStandardOverridesProperties =
|
||||
(typeof OBJECT_METADATA_STANDARD_OVERRIDES_PROPERTIES)[number];
|
||||
@@ -0,0 +1,10 @@
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
|
||||
export const isStandardMetadata = (
|
||||
metadata:
|
||||
| Pick<FlatObjectMetadata, 'standardId' | 'isCustom'>
|
||||
| Pick<FlatFieldMetadata, 'standardId' | 'isCustom'>,
|
||||
) => !metadata.isCustom && isDefined(metadata.standardId);
|
||||
Reference in New Issue
Block a user