fix: QueryRunner overrideDataByFieldMetadata sub fields not being stringified (#14187)
Adding `secondaryLinks` to company is broken, this fixes it Regression can be traced back to this commit https://github.com/twentyhq/twenty/pull/10912/files#diff-8a992c6bff80abc8c9075d585d293f6aa98c246df097efb4f904b82dc3ff8114R210-R214 https://github.com/user-attachments/assets/463cee62-8ee3-45dc-9912-fd8fb5244579
This commit is contained in:
+14
-10
@@ -114,6 +114,7 @@ export class QueryRunnerArgsFactory {
|
||||
'id',
|
||||
id,
|
||||
fieldMetadataMapByNameByName,
|
||||
options.objectMetadataItemWithFieldMaps,
|
||||
),
|
||||
) ?? [],
|
||||
)) as string[],
|
||||
@@ -132,6 +133,7 @@ export class QueryRunnerArgsFactory {
|
||||
'id',
|
||||
id,
|
||||
fieldMetadataMapByNameByName,
|
||||
options.objectMetadataItemWithFieldMaps,
|
||||
),
|
||||
) ?? [],
|
||||
)) as string[],
|
||||
@@ -191,13 +193,14 @@ export class QueryRunnerArgsFactory {
|
||||
case FieldMetadataType.RICH_TEXT_V2:
|
||||
case FieldMetadataType.LINKS:
|
||||
case FieldMetadataType.EMAILS: {
|
||||
const transformedValue =
|
||||
await this.recordInputTransformerService.transformFieldValue(
|
||||
fieldMetadata.type,
|
||||
value,
|
||||
);
|
||||
const transformedRecord =
|
||||
await this.recordInputTransformerService.process({
|
||||
recordInput: { [key]: value },
|
||||
objectMetadataMapItem:
|
||||
options.objectMetadataItemWithFieldMaps,
|
||||
});
|
||||
|
||||
return [key, transformedValue];
|
||||
return [key, transformedRecord[key]];
|
||||
}
|
||||
default:
|
||||
return [key, value];
|
||||
@@ -283,6 +286,7 @@ export class QueryRunnerArgsFactory {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
value: any,
|
||||
fieldMetadataMapByName: FieldMetadataMap,
|
||||
objectMetadataItemWithFieldMaps: ObjectMetadataItemWithFieldMaps,
|
||||
) {
|
||||
const fieldMetadata = fieldMetadataMapByName[key];
|
||||
|
||||
@@ -290,9 +294,9 @@ export class QueryRunnerArgsFactory {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.recordInputTransformerService.transformFieldValue(
|
||||
fieldMetadata.type,
|
||||
value,
|
||||
);
|
||||
return this.recordInputTransformerService.process({
|
||||
recordInput: { [key]: value },
|
||||
objectMetadataMapItem: objectMetadataItemWithFieldMaps,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ export class RecordInputTransformerService {
|
||||
return transformedEntries;
|
||||
}
|
||||
|
||||
async transformFieldValue(
|
||||
private async transformFieldValue(
|
||||
fieldType: FieldMetadataType,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
value: any,
|
||||
|
||||
+9
-9
@@ -7,7 +7,7 @@ describe('transformLinksValue', () => {
|
||||
expect(transformLinksValue({})).toEqual({
|
||||
primaryLinkLabel: null,
|
||||
primaryLinkUrl: null,
|
||||
secondaryLinks: '[]',
|
||||
secondaryLinks: null,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,13 +16,13 @@ describe('transformLinksValue', () => {
|
||||
const input = {
|
||||
primaryLinkUrl: 'HTTPS://EXAMPLE.COM',
|
||||
primaryLinkLabel: 'Example',
|
||||
secondaryLinks: '[]',
|
||||
secondaryLinks: null,
|
||||
};
|
||||
|
||||
const expected = {
|
||||
primaryLinkUrl: 'https://example.com',
|
||||
primaryLinkLabel: 'Example',
|
||||
secondaryLinks: '[]',
|
||||
secondaryLinks: null,
|
||||
};
|
||||
|
||||
expect(transformLinksValue(input)).toEqual(expected);
|
||||
@@ -32,13 +32,13 @@ describe('transformLinksValue', () => {
|
||||
const input = {
|
||||
primaryLinkUrl: 'https://example.com/',
|
||||
primaryLinkLabel: 'Example',
|
||||
secondaryLinks: '[]',
|
||||
secondaryLinks: null,
|
||||
};
|
||||
|
||||
const expected = {
|
||||
primaryLinkUrl: 'https://example.com',
|
||||
primaryLinkLabel: 'Example',
|
||||
secondaryLinks: '[]',
|
||||
secondaryLinks: null,
|
||||
};
|
||||
|
||||
expect(transformLinksValue(input)).toEqual(expected);
|
||||
@@ -48,13 +48,13 @@ describe('transformLinksValue', () => {
|
||||
const input = {
|
||||
primaryLinkUrl: 'example.com',
|
||||
primaryLinkLabel: 'Example',
|
||||
secondaryLinks: '[]',
|
||||
secondaryLinks: null,
|
||||
};
|
||||
|
||||
const expected = {
|
||||
primaryLinkUrl: 'example.com',
|
||||
primaryLinkLabel: 'Example',
|
||||
secondaryLinks: '[]',
|
||||
secondaryLinks: null,
|
||||
};
|
||||
|
||||
expect(transformLinksValue(input)).toEqual(expected);
|
||||
@@ -64,13 +64,13 @@ describe('transformLinksValue', () => {
|
||||
const input = {
|
||||
primaryLinkUrl: 'www.example.com',
|
||||
primaryLinkLabel: 'Example',
|
||||
secondaryLinks: '[]',
|
||||
secondaryLinks: null,
|
||||
};
|
||||
|
||||
const expected = {
|
||||
primaryLinkUrl: 'www.example.com',
|
||||
primaryLinkLabel: 'Example',
|
||||
secondaryLinks: '[]',
|
||||
secondaryLinks: null,
|
||||
};
|
||||
|
||||
expect(transformLinksValue(input)).toEqual(expected);
|
||||
|
||||
+11
-8
@@ -1,4 +1,5 @@
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import isEmpty from 'lodash.isempty';
|
||||
import {
|
||||
isDefined,
|
||||
lowercaseUrlOriginAndRemoveTrailingSlash,
|
||||
@@ -41,19 +42,21 @@ export const transformLinksValue = (
|
||||
},
|
||||
);
|
||||
|
||||
const processedSecondaryLinks = secondaryLinks?.map((link) => ({
|
||||
...link,
|
||||
url: isDefined(link.url)
|
||||
? lowercaseUrlOriginAndRemoveTrailingSlash(link.url)
|
||||
: link.url,
|
||||
}));
|
||||
|
||||
return {
|
||||
...value,
|
||||
primaryLinkUrl: isDefined(primaryLinkUrl)
|
||||
? lowercaseUrlOriginAndRemoveTrailingSlash(primaryLinkUrl)
|
||||
: primaryLinkUrl,
|
||||
primaryLinkLabel,
|
||||
secondaryLinks: JSON.stringify(
|
||||
secondaryLinks?.map((link) => ({
|
||||
...link,
|
||||
url: isDefined(link.url)
|
||||
? lowercaseUrlOriginAndRemoveTrailingSlash(link.url)
|
||||
: link.url,
|
||||
})),
|
||||
),
|
||||
secondaryLinks: isEmpty(processedSecondaryLinks)
|
||||
? null
|
||||
: JSON.stringify(processedSecondaryLinks),
|
||||
};
|
||||
};
|
||||
|
||||
+15
-5
@@ -4,10 +4,12 @@ import {
|
||||
type CountryCallingCode,
|
||||
parsePhoneNumberWithError,
|
||||
} from 'libphonenumber-js';
|
||||
import isEmpty from 'lodash.isempty';
|
||||
import {
|
||||
getCountryCodesForCallingCode,
|
||||
isDefined,
|
||||
isValidCountryCode,
|
||||
parseJson,
|
||||
removeUndefinedFields,
|
||||
} from 'twenty-shared/utils';
|
||||
|
||||
@@ -23,7 +25,7 @@ import {
|
||||
export type PhonesFieldGraphQLInput =
|
||||
| Partial<
|
||||
Omit<PhonesMetadata, 'additionalPhones'> & {
|
||||
additionalPhones: Partial<AdditionalPhoneMetadata>[];
|
||||
additionalPhones: string | null;
|
||||
}
|
||||
>
|
||||
| null
|
||||
@@ -194,12 +196,20 @@ export const transformPhonesValue = ({
|
||||
number: primary.primaryPhoneNumber,
|
||||
});
|
||||
|
||||
const parsedAdditionalPhones = isArray(additionalPhones)
|
||||
? additionalPhones
|
||||
: [];
|
||||
const parsedAdditionalPhones = isNonEmptyString(additionalPhones)
|
||||
? (parseJson<Partial<AdditionalPhoneMetadata>[]>(additionalPhones) ?? [])
|
||||
: isArray(additionalPhones)
|
||||
? additionalPhones
|
||||
: [];
|
||||
|
||||
const validatedAdditionalPhones = parsedAdditionalPhones.map(
|
||||
validateAndInferPhoneInput,
|
||||
);
|
||||
|
||||
return removeUndefinedFields({
|
||||
additionalPhones: parsedAdditionalPhones.map(validateAndInferPhoneInput),
|
||||
additionalPhones: isEmpty(validatedAdditionalPhones)
|
||||
? null
|
||||
: JSON.stringify(validatedAdditionalPhones),
|
||||
primaryPhoneCallingCode,
|
||||
primaryPhoneCountryCode,
|
||||
primaryPhoneNumber,
|
||||
|
||||
Reference in New Issue
Block a user