Files
twenty/packages/twenty-server/test/integration/metadata/suites/object-metadata/relation/delete-one-object-metadata-with-relation.integration-spec.ts
T
Paul Rastoin 47b60bd49f Deprecate FieldMetadataInterface (#13264)
# Introduction

From the moment replaced the FieldMetadataInterface definition to:
```ts
import { FieldMetadataType } from 'twenty-shared/types';

import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';

export type FieldMetadataInterface<
  T extends FieldMetadataType = FieldMetadataType,
> = FieldMetadataEntity<T>;
```
After this PR merge will create a new one removing the type and
replacing it to `FieldMetadataEntity`.
Did not renamed it here to avoid conflicts on naming + type issues fixs
within the same PR

## Field metadata entity RELATION or MORPH
Relations fields cannot be null for those field metadata entity instance
anymore, but are never for the others see
`packages/twenty-server/src/engine/metadata-modules/field-metadata/types/field-metadata-entity-test.type.ts`
( introduced TypeScript tests )

## Concerns
- TS_VECTOR is the most at risk with the `generatedType` and
`asExpression` removal from interface

## What's next
- `FielMetadataInterface` removal and rename ( see introduction )
- Depcrecating `ObjectMetadataInterface`
- Refactor `FieldMetadataEntity` optional fiels to be nullable only
- TO DIG `never` occurences on settings, defaultValue etc
- Some interfaces will be replaced by the `FlatFieldMetadata` when
deprecating the current sync and comparators tools
2025-07-21 11:30:18 +02:00

182 lines
5.7 KiB
TypeScript

import { findManyFieldsMetadataQueryFactory } from 'test/integration/metadata/suites/field-metadata/utils/find-many-fields-metadata-query-factory.util';
import { createRelationBetweenObjects } from 'test/integration/metadata/suites/object-metadata/utils/create-relation-between-objects.util';
import { deleteOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/delete-one-object-metadata.util';
import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util';
import { EachTestingContext } from 'twenty-shared/testing';
import { FieldMetadataType } from 'twenty-shared/types';
import { forceCreateOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/force-create-one-object-metadata.util';
import { RelationType } from 'src/engine/metadata-modules/field-metadata/interfaces/relation-type.interface';
import { FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto';
import { RelationDTO } from 'src/engine/metadata-modules/field-metadata/dtos/relation.dto';
type DeleteOneObjectMetadataItemTestingContext = EachTestingContext<
(args: { objectMetadataIdToDelete: string; relationFieldId: string }) => {
objectMetadataIdToDelete: string;
relationFieldId: string;
}
>[];
const successfulDeleteSourceUseCase: DeleteOneObjectMetadataItemTestingContext =
[
{
title:
'When deleting source object, the relation on the target should be deleted',
context: ({ objectMetadataIdToDelete, relationFieldId }) => ({
objectMetadataIdToDelete,
relationFieldId,
}),
},
];
const successfulDeleteTargetUseCase: DeleteOneObjectMetadataItemTestingContext =
[
{
title:
'When deleting target object, the relation on the source should be deleted',
context: ({ objectMetadataIdToDelete, relationFieldId }) => ({
objectMetadataIdToDelete,
relationFieldId,
}),
},
];
describe('Delete Object metadata with relation should succeed', () => {
let createdObjectMetadataPersonId = '';
let createdObjectMetadataOpportunityId = '';
let globalTestContext: {
opportunityMetadataId: string;
personMetadataId: string;
relationField: FieldMetadataDTO & {
relation: RelationDTO;
};
};
beforeEach(async () => {
const {
data: {
createOneObject: { id: objectMetadataPersonId },
},
} = await forceCreateOneObjectMetadata({
input: {
nameSingular: 'personForRelation',
namePlural: 'peopleForRelation',
labelSingular: 'Person For Relation',
labelPlural: 'People For Relation',
icon: 'IconPerson',
},
});
createdObjectMetadataPersonId = objectMetadataPersonId;
const {
data: {
createOneObject: { id: objectMetadataOpportunityId },
},
} = await forceCreateOneObjectMetadata({
input: {
nameSingular: 'opportunityForRelation',
namePlural: 'opportunitiesForRelation',
labelSingular: 'Opportunity For Relation',
labelPlural: 'Opportunities For Relation',
icon: 'IconOpportunity',
},
});
createdObjectMetadataOpportunityId = objectMetadataOpportunityId;
globalTestContext = {
opportunityMetadataId: createdObjectMetadataOpportunityId,
personMetadataId: createdObjectMetadataPersonId,
relationField:
await createRelationBetweenObjects<FieldMetadataType.RELATION>({
objectMetadataId: createdObjectMetadataOpportunityId,
targetObjectMetadataId: createdObjectMetadataPersonId,
type: FieldMetadataType.RELATION,
relationType: RelationType.MANY_TO_ONE,
}),
};
});
afterEach(async () => {
await deleteOneObjectMetadata({
input: { idToDelete: createdObjectMetadataPersonId },
});
await deleteOneObjectMetadata({
input: { idToDelete: createdObjectMetadataOpportunityId },
});
});
it.each(successfulDeleteSourceUseCase)('$title', async ({ context }) => {
const computedContext = context({
objectMetadataIdToDelete: globalTestContext.personMetadataId,
relationFieldId: globalTestContext.relationField.id,
});
await deleteOneObjectMetadata({
input: { idToDelete: computedContext.objectMetadataIdToDelete },
});
const opportunityFieldOnPersonAfterDeletion = await findFieldMetadata({
fieldMetadataId: computedContext.relationFieldId,
});
expect(opportunityFieldOnPersonAfterDeletion).toBeUndefined();
});
it.each(successfulDeleteTargetUseCase)('$title', async ({ context }) => {
const computedContext = context({
objectMetadataIdToDelete: globalTestContext.opportunityMetadataId,
relationFieldId: globalTestContext.relationField.id,
});
await deleteOneObjectMetadata({
input: { idToDelete: computedContext.objectMetadataIdToDelete },
});
const personFieldOnOpportunityAfterDeletion = await findFieldMetadata({
fieldMetadataId: computedContext.relationFieldId,
});
expect(personFieldOnOpportunityAfterDeletion).toBeUndefined();
});
});
const findFieldMetadata = async ({
fieldMetadataId,
}: {
fieldMetadataId: string;
}) => {
const operation = findManyFieldsMetadataQueryFactory({
gqlFields: `
id
name
object {
id
nameSingular
}
relation {
type
targetFieldMetadata {
id
}
targetObjectMetadata {
id
}
}
settings
`,
input: {
filter: {
id: { eq: fieldMetadataId },
},
paging: { first: 1 },
},
});
const fields = await makeMetadataAPIRequest(operation);
const field = fields.body.data.fields.edges?.[0]?.node;
return field;
};