Refactor builder to embed Object validation create/delete/update (#13934)
# Introduction Moving validation directly in the builder that has the perfect granularity to do it. When importing we won't have to infer and dispatch on the operation nature ( update delete create ) and validate accordingly ## Objects Only migrated object validation for the moment even though create object involves a validate flat field metadata creation call too ## TODO - improve `otherFlatObjectMetadataMapsToValidate` naming too vague ## Next - handle fields validation within fields actions build - Unit test coverage validation issue on builder and validate - integration test plugging with new feature flag ## Manual tested - Update - Delete - Create TODO
This commit is contained in:
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { ALL_FLAT_OBJECT_METADATA_MOCKS } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/all-flat-object.mock';
|
||||
import { ALL_FLAT_OBJECT_METADATA_MOCKS } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/all-flat-object-metadatas.mock';
|
||||
import { fromFlatObjectMetadatasToFlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-flat-object-metadatas-to-flat-object-metadata-maps.util';
|
||||
|
||||
export const FLAT_OBJECT_METADATA_MAPS_MOCKS =
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`getSubFlatObjectMetadataMapsOutOfFlatFieldMetadatasOrThrow should throw when object metadata id is not found 1`] = `"getSubFlatObjectMetadataMapsOfSpecificFieldsOrThrow object metadata not found"`;
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
import { jestExpectToBeDefined } from 'test/utils/expect-to-be-defined.util.test';
|
||||
import {
|
||||
eachTestingContextFilter,
|
||||
type EachTestingContext,
|
||||
} from 'twenty-shared/testing';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
|
||||
import { PET_FLAT_FIELDS_MOCK } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/pet-flat-fields.mock';
|
||||
import { ROCKET_FLAT_FIELDS_MOCK } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/rocket-flat-fields.mock';
|
||||
import { FLAT_OBJECT_METADATA_MAPS_MOCKS } from 'src/engine/metadata-modules/flat-object-metadata-maps/mocks/flat-object-metadata-maps.mock';
|
||||
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
|
||||
import {
|
||||
type GetSubFlatObjectMetadataMapsOfSpecificFieldsOrThrowArgs,
|
||||
getSubFlatObjectMetadataMapsOutOfFlatFieldMetadatasOrThrow,
|
||||
} from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/get-sub-flat-object-metadata-maps-out-of-flat-field-metadatas-or-throw.util';
|
||||
import { PET_FLAT_OBJECT_MOCK } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/pet-flat-object.mock';
|
||||
import { ROCKET_FLAT_OBJECT_MOCK } from 'src/engine/metadata-modules/flat-object-metadata/__mocks__/rocket-flat-object.mock';
|
||||
import { fromFlatObjectMetadatasToFlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata/utils/from-flat-object-metadatas-to-flat-object-metadata-maps.util';
|
||||
|
||||
type GetSubObjectMetadataMapsOrThrowTestCase = {
|
||||
input: GetSubFlatObjectMetadataMapsOfSpecificFieldsOrThrowArgs;
|
||||
shouldThrow?: true;
|
||||
expected?: FlatObjectMetadataMaps;
|
||||
};
|
||||
|
||||
describe('getSubFlatObjectMetadataMapsOutOfFlatFieldMetadatasOrThrow', () => {
|
||||
const testCases: EachTestingContext<GetSubObjectMetadataMapsOrThrowTestCase>[] =
|
||||
[
|
||||
{
|
||||
title: 'should throw when object metadata id is not found',
|
||||
context: {
|
||||
input: {
|
||||
flatFieldMetadatas: [
|
||||
getFlatFieldMetadataMock({
|
||||
objectMetadataId: 'non-existent',
|
||||
type: FieldMetadataType.TEXT,
|
||||
uniqueIdentifier: 'unique-identifier-1',
|
||||
}),
|
||||
],
|
||||
flatObjectMetadataMaps: FLAT_OBJECT_METADATA_MAPS_MOCKS,
|
||||
},
|
||||
shouldThrow: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'should extract single object metadata from maps',
|
||||
context: {
|
||||
input: {
|
||||
flatFieldMetadatas: [PET_FLAT_FIELDS_MOCK.species],
|
||||
flatObjectMetadataMaps: FLAT_OBJECT_METADATA_MAPS_MOCKS,
|
||||
},
|
||||
expected: fromFlatObjectMetadatasToFlatObjectMetadataMaps([
|
||||
{
|
||||
...PET_FLAT_OBJECT_MOCK,
|
||||
flatFieldMetadatas: [PET_FLAT_FIELDS_MOCK.species],
|
||||
},
|
||||
]),
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'should extract object metadata from maps with provided fields',
|
||||
context: {
|
||||
input: {
|
||||
flatFieldMetadatas: [
|
||||
PET_FLAT_FIELDS_MOCK.species,
|
||||
PET_FLAT_FIELDS_MOCK.name,
|
||||
ROCKET_FLAT_FIELDS_MOCK.attachments,
|
||||
],
|
||||
flatObjectMetadataMaps: FLAT_OBJECT_METADATA_MAPS_MOCKS,
|
||||
},
|
||||
expected: fromFlatObjectMetadatasToFlatObjectMetadataMaps([
|
||||
{
|
||||
...PET_FLAT_OBJECT_MOCK,
|
||||
flatFieldMetadatas: [
|
||||
PET_FLAT_FIELDS_MOCK.name,
|
||||
PET_FLAT_FIELDS_MOCK.species,
|
||||
],
|
||||
},
|
||||
{
|
||||
...ROCKET_FLAT_OBJECT_MOCK,
|
||||
flatFieldMetadatas: [ROCKET_FLAT_FIELDS_MOCK.attachments],
|
||||
},
|
||||
]),
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const filteredTestCases = eachTestingContextFilter(testCases);
|
||||
|
||||
it.each(filteredTestCases)(
|
||||
'$title',
|
||||
({
|
||||
context: {
|
||||
input: { flatFieldMetadatas, flatObjectMetadataMaps },
|
||||
shouldThrow = false,
|
||||
expected,
|
||||
},
|
||||
}) => {
|
||||
if (shouldThrow) {
|
||||
expect(() =>
|
||||
getSubFlatObjectMetadataMapsOutOfFlatFieldMetadatasOrThrow({
|
||||
flatFieldMetadatas,
|
||||
flatObjectMetadataMaps,
|
||||
}),
|
||||
).toThrowErrorMatchingSnapshot();
|
||||
} else {
|
||||
jestExpectToBeDefined(expected);
|
||||
const result =
|
||||
getSubFlatObjectMetadataMapsOutOfFlatFieldMetadatasOrThrow({
|
||||
flatFieldMetadatas,
|
||||
flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
expect(result).toEqual(expected);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
import {
|
||||
eachTestingContextFilter,
|
||||
type EachTestingContext,
|
||||
} from 'twenty-shared/testing';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
import { getFlatFieldMetadataMock } from 'src/engine/metadata-modules/flat-field-metadata/__mocks__/get-flat-field-metadata.mock';
|
||||
import { FLAT_OBJECT_METADATA_MAPS_MOCKS } from 'src/engine/metadata-modules/flat-object-metadata-maps/mocks/flat-object-metadata-maps.mock';
|
||||
import { type GetSubFlatObjectMetadataMapsOfSpecificFieldsOrThrowArgs } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/get-sub-flat-object-metadata-maps-out-of-flat-field-metadatas-or-throw.util';
|
||||
import { getSubFlatObjectMetadataMapsOutOfFlatFieldMetadatas } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/get-sub-flat-object-metadata-maps-out-of-flat-field-metadatas.util';
|
||||
|
||||
type GetSubFlatObjectMetadataMapsTestCase = {
|
||||
input: GetSubFlatObjectMetadataMapsOfSpecificFieldsOrThrowArgs;
|
||||
};
|
||||
|
||||
describe('getSubFlatObjectMetadataMapsOutOfFlatFieldMetadatas', () => {
|
||||
const testCases: EachTestingContext<GetSubFlatObjectMetadataMapsTestCase>[] =
|
||||
[
|
||||
{
|
||||
title: 'return undefined when object metadata id is not found',
|
||||
context: {
|
||||
input: {
|
||||
flatFieldMetadatas: [
|
||||
getFlatFieldMetadataMock({
|
||||
objectMetadataId: 'non-existent',
|
||||
type: FieldMetadataType.TEXT,
|
||||
uniqueIdentifier: 'unique-identifier-1',
|
||||
}),
|
||||
],
|
||||
flatObjectMetadataMaps: FLAT_OBJECT_METADATA_MAPS_MOCKS,
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const filteredTestCases = eachTestingContextFilter(testCases);
|
||||
|
||||
it.each(filteredTestCases)(
|
||||
'$title',
|
||||
({
|
||||
context: {
|
||||
input: { flatFieldMetadatas, flatObjectMetadataMaps },
|
||||
},
|
||||
}) => {
|
||||
const result = getSubFlatObjectMetadataMapsOutOfFlatFieldMetadatas({
|
||||
flatFieldMetadatas,
|
||||
flatObjectMetadataMaps,
|
||||
});
|
||||
|
||||
expect(result).toBeUndefined();
|
||||
},
|
||||
);
|
||||
});
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
import { fromArrayToValuesByKeyRecord, isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
|
||||
import { EMPTY_FLAT_OBJECT_METADATA_MAPS } from 'src/engine/metadata-modules/flat-object-metadata-maps/constant/empty-flat-object-metadata-maps.constant';
|
||||
import {
|
||||
FlatObjectMetadataMapsException,
|
||||
FlatObjectMetadataMapsExceptionCode,
|
||||
} from 'src/engine/metadata-modules/flat-object-metadata-maps/flat-object-metadata-maps.exception';
|
||||
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
|
||||
import { addFlatObjectMetadataWithFlatFieldMapsToFlatObjectMetadataMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/add-flat-object-metadata-with-field-maps-to-flat-object-metadata-maps-or-throw.util';
|
||||
import { deleteFieldFromFlatObjectMetadataWithFlatFieldMapsOrThrow } from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/delete-field-from-flat-object-metadata-with-flat-field-maps-or-throw.util';
|
||||
|
||||
export type GetSubFlatObjectMetadataMapsOfSpecificFieldsOrThrowArgs = {
|
||||
flatFieldMetadatas: Pick<FlatFieldMetadata, 'objectMetadataId' | 'id'>[];
|
||||
flatObjectMetadataMaps: FlatObjectMetadataMaps;
|
||||
};
|
||||
export const getSubFlatObjectMetadataMapsOutOfFlatFieldMetadatasOrThrow = ({
|
||||
flatObjectMetadataMaps: sourceFlatObjectMetadataMaps,
|
||||
flatFieldMetadatas,
|
||||
}: GetSubFlatObjectMetadataMapsOfSpecificFieldsOrThrowArgs): FlatObjectMetadataMaps => {
|
||||
const fieldIdPerObjectId = fromArrayToValuesByKeyRecord({
|
||||
array: flatFieldMetadatas,
|
||||
key: 'objectMetadataId',
|
||||
});
|
||||
|
||||
return Object.keys(fieldIdPerObjectId).reduce(
|
||||
(flatObjectMetadataMaps, objectMetadataId) => {
|
||||
let flatObjectMetadataWithFlatFieldMaps = structuredClone(
|
||||
sourceFlatObjectMetadataMaps.byId[objectMetadataId],
|
||||
);
|
||||
|
||||
if (!isDefined(flatObjectMetadataWithFlatFieldMaps)) {
|
||||
throw new FlatObjectMetadataMapsException(
|
||||
'getSubFlatObjectMetadataMapsOfSpecificFieldsOrThrow object metadata not found',
|
||||
FlatObjectMetadataMapsExceptionCode.OBJECT_METADATA_NOT_FOUND,
|
||||
);
|
||||
}
|
||||
|
||||
const fieldIds =
|
||||
fieldIdPerObjectId[objectMetadataId]?.map(({ id }) => id) ?? [];
|
||||
|
||||
flatObjectMetadataWithFlatFieldMaps =
|
||||
flatObjectMetadataWithFlatFieldMaps.flatFieldMetadatas.reduce(
|
||||
(flatObjectMetadataWithFlatFieldMaps, flatFieldMetadata) => {
|
||||
if (fieldIds.includes(flatFieldMetadata.id)) {
|
||||
return flatObjectMetadataWithFlatFieldMaps;
|
||||
}
|
||||
|
||||
return deleteFieldFromFlatObjectMetadataWithFlatFieldMapsOrThrow({
|
||||
fieldMetadataId: flatFieldMetadata.id,
|
||||
flatObjectMetadataWithFlatFieldMaps,
|
||||
});
|
||||
},
|
||||
flatObjectMetadataWithFlatFieldMaps,
|
||||
);
|
||||
|
||||
return addFlatObjectMetadataWithFlatFieldMapsToFlatObjectMetadataMapsOrThrow(
|
||||
{
|
||||
flatObjectMetadataWithFlatFieldMaps,
|
||||
flatObjectMetadataMaps,
|
||||
},
|
||||
);
|
||||
},
|
||||
EMPTY_FLAT_OBJECT_METADATA_MAPS,
|
||||
);
|
||||
};
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import { type FlatObjectMetadataMaps } from 'src/engine/metadata-modules/flat-object-metadata-maps/types/flat-object-metadata-maps.type';
|
||||
import {
|
||||
type GetSubFlatObjectMetadataMapsOfSpecificFieldsOrThrowArgs,
|
||||
getSubFlatObjectMetadataMapsOutOfFlatFieldMetadatasOrThrow,
|
||||
} from 'src/engine/metadata-modules/flat-object-metadata-maps/utils/get-sub-flat-object-metadata-maps-out-of-flat-field-metadatas-or-throw.util';
|
||||
|
||||
export const getSubFlatObjectMetadataMapsOutOfFlatFieldMetadatas = (
|
||||
args: GetSubFlatObjectMetadataMapsOfSpecificFieldsOrThrowArgs,
|
||||
): FlatObjectMetadataMaps | undefined => {
|
||||
try {
|
||||
return getSubFlatObjectMetadataMapsOutOfFlatFieldMetadatasOrThrow(args);
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user