diff --git a/packages/twenty-server/src/engine/api/common/common-args-processors/data-arg-processor/transformer-utils/transform-actor-field.util.ts b/packages/twenty-server/src/engine/api/common/common-args-processors/data-arg-processor/transformer-utils/transform-actor-field.util.ts index 11e9e3b4afa..5003d2a6452 100644 --- a/packages/twenty-server/src/engine/api/common/common-args-processors/data-arg-processor/transformer-utils/transform-actor-field.util.ts +++ b/packages/twenty-server/src/engine/api/common/common-args-processors/data-arg-processor/transformer-utils/transform-actor-field.util.ts @@ -6,12 +6,12 @@ import { transformRawJsonField } from 'src/engine/api/common/common-args-process export const transformActorField = ( value: { source?: FieldActorSource | null; - context?: object | null; + context?: object | string | null; } | null, isNullEquivalenceEnabled: boolean = false, ): { source?: FieldActorSource | null; - context?: object | null; + context?: object | string | null; } | null => { if (isNull(value)) return null; diff --git a/packages/twenty-server/src/engine/api/common/common-args-processors/data-arg-processor/transformer-utils/transform-raw-json-field.util.ts b/packages/twenty-server/src/engine/api/common/common-args-processors/data-arg-processor/transformer-utils/transform-raw-json-field.util.ts index 804e038b72e..d1a4f66ff4b 100644 --- a/packages/twenty-server/src/engine/api/common/common-args-processors/data-arg-processor/transformer-utils/transform-raw-json-field.util.ts +++ b/packages/twenty-server/src/engine/api/common/common-args-processors/data-arg-processor/transformer-utils/transform-raw-json-field.util.ts @@ -1,9 +1,10 @@ +//Json.parse() for RawJsonField is done in formatFieldMetadataValue in ORM import { isNull } from '@sniptt/guards'; export const transformRawJsonField = ( - value: object | null, + value: object | string | null, isNullEquivalenceEnabled: boolean = false, -): object | null => { +): object | string | null => { return isNullEquivalenceEnabled && !isNull(value) && Object.keys(value).length === 0 diff --git a/packages/twenty-server/src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/__tests__/validate-raw-json-field-or-throw.util.spec.ts b/packages/twenty-server/src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/__tests__/validate-raw-json-field-or-throw.util.spec.ts index 8ace0f960ef..69a6bbbfa6e 100644 --- a/packages/twenty-server/src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/__tests__/validate-raw-json-field-or-throw.util.spec.ts +++ b/packages/twenty-server/src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/__tests__/validate-raw-json-field-or-throw.util.spec.ts @@ -28,6 +28,20 @@ describe('validateRawJsonFieldOrThrow', () => { expect(result).toEqual(jsonArray); }); + + it('should accept a valid JSON string', () => { + const jsonString = '{"key":"value","nested":{"prop":123}}'; + const result = validateRawJsonFieldOrThrow(jsonString, 'testField'); + + expect(result).toBe(jsonString); + }); + + it('should accept a valid JSON array string', () => { + const jsonArrayString = '[1, 2, 3, "test"]'; + const result = validateRawJsonFieldOrThrow(jsonArrayString, 'testField'); + + expect(result).toBe(jsonArrayString); + }); }); describe('invalid inputs', () => { @@ -51,10 +65,16 @@ describe('validateRawJsonFieldOrThrow', () => { ); }); - it('should throw when value is a string', () => { + it('should throw when value is an invalid JSON string', () => { expect(() => - validateRawJsonFieldOrThrow('string value', 'testField'), + validateRawJsonFieldOrThrow('not valid json', 'testField'), ).toThrow(CommonQueryRunnerException); }); + + it('should throw when value is a boolean', () => { + expect(() => validateRawJsonFieldOrThrow(true, 'testField')).toThrow( + CommonQueryRunnerException, + ); + }); }); }); diff --git a/packages/twenty-server/src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/validate-raw-json-field-or-throw.util.ts b/packages/twenty-server/src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/validate-raw-json-field-or-throw.util.ts index 04dd0af1085..6744ac77ea4 100644 --- a/packages/twenty-server/src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/validate-raw-json-field-or-throw.util.ts +++ b/packages/twenty-server/src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/validate-raw-json-field-or-throw.util.ts @@ -10,9 +10,22 @@ import { export const validateRawJsonFieldOrThrow = ( value: unknown, fieldName: string, -): object | null => { +): object | string | null => { if (isNull(value)) return null; + if (typeof value === 'string') { + try { + JSON.parse(value); + } catch { + throw new CommonQueryRunnerException( + `Invalid object value ${inspect(value)} for field "${fieldName}"`, + CommonQueryRunnerExceptionCode.INVALID_ARGS_DATA, + ); + } + + return value; + } + if (!isObject(value)) { throw new CommonQueryRunnerException( `Invalid object value ${inspect(value)} for field "${fieldName}"`, diff --git a/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/__snapshots__/raw-json-field-create-input-validation.integration-spec.ts.snap b/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/__snapshots__/raw-json-field-create-input-validation.integration-spec.ts.snap index 925ad17fccd..f8dde60a9ed 100644 --- a/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/__snapshots__/raw-json-field-create-input-validation.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/__snapshots__/raw-json-field-create-input-validation.integration-spec.ts.snap @@ -1,5 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Create input validation - RAW_JSON Gql create input - failure RAW_JSON - should fail with : {"rawJsonField":"not-a-json"} 1`] = `"Invalid object value 'not-a-json' for field "rawJsonField""`; -exports[`Create input validation - RAW_JSON Rest create input - failure RAW_JSON - should fail with : {"rawJsonField":"not-a-json"} 1`] = `"["Invalid object value 'not-a-json' for field \\"rawJsonField\\""]"`; +exports[`Create input validation - RAW_JSON Gql create input - failure RAW_JSON - should fail with : {"rawJsonField":"not-a-stringified-json"} 1`] = `"Invalid JSON string value 'not-a-stringified-json' for field "rawJsonField""`; + + +exports[`Create input validation - RAW_JSON Rest create input - failure RAW_JSON - should fail with : {"rawJsonField":"not-a-stringified-json"} 1`] = `"["Invalid JSON string value 'not-a-stringified-json' for field \\"rawJsonField\\""]"`; diff --git a/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant.ts b/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant.ts index 488d437e564..84393341460 100644 --- a/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant.ts +++ b/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/constants/failing-create-input-by-field-metadata-type.constant.ts @@ -149,7 +149,7 @@ export const failingCreateInputByFieldMetadataType: { [FieldMetadataType.RAW_JSON]: [ { input: { - rawJsonField: 'not-a-json', + rawJsonField: 'not-a-stringified-json', }, }, ], diff --git a/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant.ts b/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant.ts index 1675bf946f2..544edfc8bbf 100644 --- a/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant.ts +++ b/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/constants/successful-create-input-by-field-metadata-type.constant.ts @@ -145,6 +145,14 @@ export const successfulCreateInputByFieldMetadataType: { return record.rawJsonField === null; }, }, + { + input: { + rawJsonField: '{"key": "value"}', + }, + validateInput: (record: Record) => { + return record.rawJsonField.key === 'value'; + }, + }, ], [FieldMetadataType.ARRAY]: [ {