ObjectMetadataServiceV2.updateOne (#13891)
# Introduction Last service to get migrated, `updateOne` object metadata service v2
This commit is contained in:
+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;
|
||||
};
|
||||
Reference in New Issue
Block a user