Fix unique standard field (#16371)

Fixes https://github.com/twentyhq/twenty/issues/15925

- update field metadata update logic
- uniformize the way index are named
- command to migrate v1-named unique index
- add integration testing

---------

Co-authored-by: prastoin <paul@twenty.com>
This commit is contained in:
Etienne
2025-12-08 19:05:28 +01:00
committed by GitHub
parent 950f452fef
commit 07cfaa78ef
23 changed files with 811 additions and 269 deletions
@@ -32,11 +32,13 @@ export const validateMorphRelationCreationPayload = async ({
if (morphRelationCreationPayload.length === 0) {
return {
status: 'fail',
error: {
code: FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED,
message: 'Morph relation creation payloads are empty',
userFriendlyMessage: msg`At least one relation is require`,
},
errors: [
{
code: FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED,
message: 'Morph relation creation payloads are empty',
userFriendlyMessage: msg`At least one relation is require`,
},
],
};
}
@@ -51,12 +53,14 @@ export const validateMorphRelationCreationPayload = async ({
if (allRelationType.length > 1) {
return {
status: 'fail',
error: {
code: FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED,
message:
'Morph relation creation payloads must have the same relation type',
userFriendlyMessage: msg`Morph relation creation payloads must have the same relation type`,
},
errors: [
{
code: FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED,
message:
'Morph relation creation payloads must have the same relation type',
userFriendlyMessage: msg`Morph relation creation payloads must have the same relation type`,
},
],
};
}
@@ -70,12 +74,14 @@ export const validateMorphRelationCreationPayload = async ({
if (allRelatedObjectMetadataIdsSet.includes(objectMetadataId)) {
return {
status: 'fail',
error: {
code: FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED,
message:
'Morph relation creation payloads must not target source object metadata',
userFriendlyMessage: msg`Morph relation creation payloads must only contain relation to other object metadata`,
},
errors: [
{
code: FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED,
message:
'Morph relation creation payloads must not target source object metadata',
userFriendlyMessage: msg`Morph relation creation payloads must only contain relation to other object metadata`,
},
],
};
}
@@ -84,12 +90,14 @@ export const validateMorphRelationCreationPayload = async ({
) {
return {
status: 'fail',
error: {
code: FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED,
message:
'Morph relation creation payloads must have only relation to the same object metadata',
userFriendlyMessage: msg`Morph relation creation payloads must only contain relation to the same object metadata`,
},
errors: [
{
code: FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED,
message:
'Morph relation creation payloads must have only relation to the same object metadata',
userFriendlyMessage: msg`Morph relation creation payloads must only contain relation to the same object metadata`,
},
],
};
}
@@ -127,14 +135,18 @@ export const validateMorphRelationCreationPayload = async ({
if (relationCreationPayloadReport.failed.length > 0) {
return {
status: 'fail',
error: {
code: FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED,
message: 'Morph relation input transpilation failed',
userFriendlyMessage: msg`Invalid morph relation input`,
value: relationCreationPayloadReport.failed
.map((failedTranspilation) => failedTranspilation.error.value)
.filter(isDefined),
},
errors: [
{
code: FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED,
message: 'Morph relation input transpilation failed',
userFriendlyMessage: msg`Invalid morph relation input`,
value: relationCreationPayloadReport.failed
.flatMap((failedTranspilation) =>
failedTranspilation.errors.map((error) => error.value),
)
.filter(isDefined),
},
],
};
}
@@ -39,12 +39,14 @@ export const validateRelationCreationPayload = async ({
if (error instanceof FieldMetadataException) {
return {
status: 'fail',
error: {
code: FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED,
message: `Relation creation payload is invalid`,
userFriendlyMessage: msg`Invalid relation creation payload`,
value: relationCreationPayload,
},
errors: [
{
code: FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED,
message: `Relation creation payload is invalid`,
userFriendlyMessage: msg`Invalid relation creation payload`,
value: relationCreationPayload,
},
],
};
} else {
throw error;
@@ -59,12 +61,14 @@ export const validateRelationCreationPayload = async ({
if (!isDefined(targetFlatObjectMetadata)) {
return {
status: 'fail',
error: {
code: FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED,
message: `Object metadata relation target not found for relation creation payload`,
userFriendlyMessage: msg`Object targeted by field to create not found`,
value: relationCreationPayload,
},
errors: [
{
code: FieldMetadataExceptionCode.FIELD_METADATA_RELATION_MALFORMED,
message: `Object metadata relation target not found for relation creation payload`,
userFriendlyMessage: msg`Object targeted by field to create not found`,
value: relationCreationPayload,
},
],
};
}