Date & DateTime validation fixes / improvements (#18009)

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

- Backend should have strict date/dateTime format validation
- FE in import csv is more permissive

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
This commit is contained in:
Etienne
2026-02-18 11:13:18 +01:00
committed by GitHub
parent ee15e034b5
commit 08a3d983cb
25 changed files with 1781 additions and 549 deletions
@@ -428,8 +428,8 @@ describe('buildRecordFromImportedStructuredRow', () => {
blocknote: 'Rich content in blocknote format',
markdown: 'Content in markdown format',
},
dateField: '2023-12-25',
dateTimeField: '2023-12-25T10:30:00Z',
dateField: '2023-12-25T00:00:00.000Z',
dateTimeField: '2023-12-25T10:30:00.000Z',
ratingField: '4',
});
});
@@ -349,13 +349,22 @@ export const buildRecordFromImportedStructuredRow = ({
break;
}
case FieldMetadataType.UUID:
if (
isDefined(importedFieldValue) &&
isNonEmptyString(importedFieldValue)
) {
recordToBuild[field.name] = importedFieldValue;
}
break;
case FieldMetadataType.DATE:
case FieldMetadataType.DATE_TIME:
if (
isDefined(importedFieldValue) &&
isNonEmptyString(importedFieldValue)
) {
recordToBuild[field.name] = importedFieldValue;
recordToBuild[field.name] = new Date(
importedFieldValue,
).toISOString();
}
break;
case FieldMetadataType.SELECT:
@@ -0,0 +1,209 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`DataArgProcessor failing inputs validation ADDRESS should throw for invalid input #1: "not-an-address" 1`] = `"Invalid object value 'not-an-address' for field "addressField""`;
exports[`DataArgProcessor failing inputs validation ADDRESS should throw for invalid input #2: 1 1`] = `"Invalid object value 1 for field "addressField""`;
exports[`DataArgProcessor failing inputs validation ADDRESS should throw for invalid input #3: true 1`] = `"Invalid object value true for field "addressField""`;
exports[`DataArgProcessor failing inputs validation ARRAY should throw for invalid input #1: true 1`] = `"Invalid value true for field "arrayField - Array values need to be string""`;
exports[`DataArgProcessor failing inputs validation ARRAY should throw for invalid input #2: 1 1`] = `"Invalid value 1 for field "arrayField - Array values need to be string""`;
exports[`DataArgProcessor failing inputs validation BOOLEAN should throw for invalid input #1: {} 1`] = `"Invalid boolean value {} for field "booleanField""`;
exports[`DataArgProcessor failing inputs validation BOOLEAN should throw for invalid input #2: [] 1`] = `"Invalid boolean value [] for field "booleanField""`;
exports[`DataArgProcessor failing inputs validation BOOLEAN should throw for invalid input #3: "string" 1`] = `"Invalid boolean value 'string' for field "booleanField""`;
exports[`DataArgProcessor failing inputs validation BOOLEAN should throw for invalid input #4: 1 1`] = `"Invalid boolean value 1 for field "booleanField""`;
exports[`DataArgProcessor failing inputs validation CURRENCY should throw for invalid input #1: "not-a-currency" 1`] = `"Invalid object value 'not-a-currency' for field "currencyField""`;
exports[`DataArgProcessor failing inputs validation CURRENCY should throw for invalid input #2: 1 1`] = `"Invalid object value 1 for field "currencyField""`;
exports[`DataArgProcessor failing inputs validation CURRENCY should throw for invalid input #3: true 1`] = `"Invalid object value true for field "currencyField""`;
exports[`DataArgProcessor failing inputs validation DATE should throw for invalid input #1: "malformed-date" 1`] = `"Invalid value 'malformed-date' for date field "dateField". Expected format: 'YYYY-MM-DD'"`;
exports[`DataArgProcessor failing inputs validation DATE should throw for invalid input #2: {} 1`] = `"Invalid value {} for date field "dateField". Expected format: 'YYYY-MM-DD'"`;
exports[`DataArgProcessor failing inputs validation DATE should throw for invalid input #3: [] 1`] = `"Invalid value [] for date field "dateField". Expected format: 'YYYY-MM-DD'"`;
exports[`DataArgProcessor failing inputs validation DATE should throw for invalid input #4: true 1`] = `"Invalid value true for date field "dateField". Expected format: 'YYYY-MM-DD'"`;
exports[`DataArgProcessor failing inputs validation DATE should throw for invalid input #5: 1 1`] = `"Invalid value 1 for date field "dateField". Expected format: 'YYYY-MM-DD'"`;
exports[`DataArgProcessor failing inputs validation DATE should throw for invalid input #6: "2024" 1`] = `"Invalid value '2024' for date field "dateField". Expected format: 'YYYY-MM-DD'"`;
exports[`DataArgProcessor failing inputs validation DATE should throw for invalid input #7: "2024-01" 1`] = `"Invalid value '2024-01' for date field "dateField". Expected format: 'YYYY-MM-DD'"`;
exports[`DataArgProcessor failing inputs validation DATE should throw for invalid input #8: "2024-13-01" 1`] = `"Invalid value '2024-13-01' for date field "dateField". Expected format: 'YYYY-MM-DD'"`;
exports[`DataArgProcessor failing inputs validation DATE should throw for invalid input #9: "2024-02-31" 1`] = `"Invalid value '2024-02-31' for date field "dateField". Expected format: 'YYYY-MM-DD'"`;
exports[`DataArgProcessor failing inputs validation DATE_TIME should throw for invalid input #1: "malformed-date" 1`] = `"Invalid value 'malformed-date' for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'"`;
exports[`DataArgProcessor failing inputs validation DATE_TIME should throw for invalid input #2: {} 1`] = `"Invalid value {} for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'"`;
exports[`DataArgProcessor failing inputs validation DATE_TIME should throw for invalid input #3: [] 1`] = `"Invalid value [] for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'"`;
exports[`DataArgProcessor failing inputs validation DATE_TIME should throw for invalid input #4: true 1`] = `"Invalid value true for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'"`;
exports[`DataArgProcessor failing inputs validation DATE_TIME should throw for invalid input #5: 1 1`] = `"Invalid value 1 for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'"`;
exports[`DataArgProcessor failing inputs validation DATE_TIME should throw for invalid input #6: "2024" 1`] = `"Invalid value '2024' for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'"`;
exports[`DataArgProcessor failing inputs validation DATE_TIME should throw for invalid input #7: "2024-01" 1`] = `"Invalid value '2024-01' for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'"`;
exports[`DataArgProcessor failing inputs validation DATE_TIME should throw for invalid input #8: "2024-13-01T10:30:00Z" 1`] = `"Invalid value '2024-13-01T10:30:00Z' for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'"`;
exports[`DataArgProcessor failing inputs validation DATE_TIME should throw for invalid input #9: "2024-01-15T25:30:00Z" 1`] = `"Invalid value '2024-01-15T25:30:00Z' for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'"`;
exports[`DataArgProcessor failing inputs validation EMAILS should throw for invalid input #1: "not-an-email" 1`] = `"Invalid object value 'not-an-email' for field "emailsField""`;
exports[`DataArgProcessor failing inputs validation EMAILS should throw for invalid input #2: {"primaryEmail":"not-an-email"} 1`] = `"Invalid string value 'not-an-email' for email field "emailsField.primaryEmail""`;
exports[`DataArgProcessor failing inputs validation EMAILS should throw for invalid input #3: {"additionalEmails":"not-an-email"} 1`] = `"Invalid string value 'not-an-email' for email field "emailsField.additionalEmails""`;
exports[`DataArgProcessor failing inputs validation EMAILS should throw for invalid input #4: {"additionalEmails":["not-an-email"]} 1`] = `"Invalid string value 'not-an-email' for email field "emailsField.additionalEmails""`;
exports[`DataArgProcessor failing inputs validation EMAILS should throw for invalid input #5: {"primaryEmail":"email@email.com","additionalEmails":["not-an-email"]} 1`] = `"Invalid string value 'not-an-email' for email field "emailsField.additionalEmails""`;
exports[`DataArgProcessor failing inputs validation EMAILS should throw for invalid input #6: {"primaryEmail":"not-an-email","additionalEmails":["additional@email.com"]} 1`] = `"Invalid string value 'not-an-email' for email field "emailsField.primaryEmail""`;
exports[`DataArgProcessor failing inputs validation EMAILS should throw for invalid input #7: {"additionalEmails":["not-an-email","additional@email.com"]} 1`] = `"Invalid string value 'not-an-email' for email field "emailsField.additionalEmails""`;
exports[`DataArgProcessor failing inputs validation FILES should throw for invalid input #1: "not-an-addFiles-property" 1`] = `"Invalid value "'not-an-addFiles-property'" for FILES field "filesField" - It should be an array of objects with "fileId" and "label" properties."`;
exports[`DataArgProcessor failing inputs validation FILES should throw for invalid input #2: {"addFiles":[{"invalidField":"test"}]} 1`] = `"Invalid value "{ addFiles: [ { invalidField: 'test' } ] }" for FILES field "filesField" - : Invalid input: expected array, received object"`;
exports[`DataArgProcessor failing inputs validation FILES should throw for invalid input #3: {"addFiles":[{"fileId":"not-a-uuid","label":"Doc.pdf"}]} 1`] = `"Invalid value "{ addFiles: [ { fileId: 'not-a-uuid', label: 'Doc.pdf' } ] }" for FILES field "filesField" - : Invalid input: expected array, received object"`;
exports[`DataArgProcessor failing inputs validation FILES should throw for invalid input #4: [{"addFiles":[{"fileId":"550e8400-e29b-41d4-a716-446655440000","label":12345}]}] 1`] = `"Invalid value "[ { addFiles: [ [Object] ] } ]" for FILES field "filesField" - 0.fileId: Invalid input: expected string, received undefined, 0.label: Invalid input: expected string, received undefined, 0: Unrecognized key: "addFiles""`;
exports[`DataArgProcessor failing inputs validation FILES should throw for invalid input #5: {"addFiles":[{"fileId":"550e8400-e29b-41d4-a716-446655440000","label":"Document.pdf","extension":"not-allowed-in-input"}]} 1`] = `
"Invalid value "{
addFiles: [
{
fileId: '550e8400-e29b-41d4-a716-446655440000',
label: 'Document.pdf',
extension: 'not-allowed-in-input'
}
]
}" for FILES field "filesField" - : Invalid input: expected array, received object"
`;
exports[`DataArgProcessor failing inputs validation FULL_NAME should throw for invalid input #1: "not-a-full-name" 1`] = `"Invalid object value 'not-a-full-name' for field "fullNameField""`;
exports[`DataArgProcessor failing inputs validation FULL_NAME should throw for invalid input #2: 1 1`] = `"Invalid object value 1 for field "fullNameField""`;
exports[`DataArgProcessor failing inputs validation FULL_NAME should throw for invalid input #3: true 1`] = `"Invalid object value true for field "fullNameField""`;
exports[`DataArgProcessor failing inputs validation LINKS should throw for invalid input #1: "not-a-link" 1`] = `"Invalid object value 'not-a-link' for field "linksField""`;
exports[`DataArgProcessor failing inputs validation LINKS should throw for invalid input #2: 1 1`] = `"Invalid object value 1 for field "linksField""`;
exports[`DataArgProcessor failing inputs validation LINKS should throw for invalid input #3: true 1`] = `"Invalid object value true for field "linksField""`;
exports[`DataArgProcessor failing inputs validation MORPH_RELATION should throw for invalid input #1: "not-a-morph-relation" 1`] = `"Invalid UUID value 'not-a-morph-relation' for field "manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id""`;
exports[`DataArgProcessor failing inputs validation MORPH_RELATION should throw for invalid input #2: {} 1`] = `"Invalid UUID value {} for field "manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id""`;
exports[`DataArgProcessor failing inputs validation MORPH_RELATION should throw for invalid input #3: [] 1`] = `"Invalid UUID value [] for field "manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id""`;
exports[`DataArgProcessor failing inputs validation MORPH_RELATION should throw for invalid input #4: true 1`] = `"Invalid UUID value true for field "manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id""`;
exports[`DataArgProcessor failing inputs validation MORPH_RELATION should throw for invalid input #5: 1 1`] = `"Invalid UUID value 1 for field "manyToOneMorphRelationFieldApiInputValidationTargetTestObject1Id""`;
exports[`DataArgProcessor failing inputs validation MULTI_SELECT should throw for invalid input #1: "not-a-select-option" 1`] = `"Invalid value 'not-a-select-option' for multi select field "multiSelectField""`;
exports[`DataArgProcessor failing inputs validation MULTI_SELECT should throw for invalid input #2: {} 1`] = `"Invalid value {} for field "multiSelectField - Array values need to be string""`;
exports[`DataArgProcessor failing inputs validation MULTI_SELECT should throw for invalid input #3: true 1`] = `"Invalid value true for field "multiSelectField - Array values need to be string""`;
exports[`DataArgProcessor failing inputs validation MULTI_SELECT should throw for invalid input #4: 1 1`] = `"Invalid value 1 for field "multiSelectField - Array values need to be string""`;
exports[`DataArgProcessor failing inputs validation NUMBER should throw for invalid input #1: {} 1`] = `"Invalid number value {} for field "numberField""`;
exports[`DataArgProcessor failing inputs validation NUMBER should throw for invalid input #2: [] 1`] = `"Invalid number value [] for field "numberField""`;
exports[`DataArgProcessor failing inputs validation NUMBER should throw for invalid input #3: true 1`] = `"Invalid number value true for field "numberField""`;
exports[`DataArgProcessor failing inputs validation NUMBER should throw for invalid input #4: "string" 1`] = `"Invalid number value 'string' for field "numberField""`;
exports[`DataArgProcessor failing inputs validation NUMERIC should throw for invalid input #1: {} 1`] = `"Invalid number value NaN for field "numericField""`;
exports[`DataArgProcessor failing inputs validation NUMERIC should throw for invalid input #2: "not-a-number" 1`] = `"Invalid number value NaN for field "numericField""`;
exports[`DataArgProcessor failing inputs validation PHONES should throw for invalid input #1: "not-a-phone" 1`] = `"Invalid object value 'not-a-phone' for field "phonesField""`;
exports[`DataArgProcessor failing inputs validation PHONES should throw for invalid input #2: 1 1`] = `"Invalid object value 1 for field "phonesField""`;
exports[`DataArgProcessor failing inputs validation PHONES should throw for invalid input #3: true 1`] = `"Invalid object value true for field "phonesField""`;
exports[`DataArgProcessor failing inputs validation POSITION should throw for invalid input #1: "not-a-position" 1`] = `"Invalid position value 'not-a-position' for field "position""`;
exports[`DataArgProcessor failing inputs validation POSITION should throw for invalid input #2: null 1`] = `"Invalid position value NaN for field "position""`;
exports[`DataArgProcessor failing inputs validation POSITION should throw for invalid input #3: {} 1`] = `"Invalid position value {} for field "position""`;
exports[`DataArgProcessor failing inputs validation POSITION should throw for invalid input #4: [] 1`] = `"Invalid position value [] for field "position""`;
exports[`DataArgProcessor failing inputs validation RATING should throw for invalid input #1: "not-a-rating" 1`] = `"Invalid value 'not-a-rating' for field "ratingField""`;
exports[`DataArgProcessor failing inputs validation RATING should throw for invalid input #2: {} 1`] = `"Invalid string value {} for text field "ratingField""`;
exports[`DataArgProcessor failing inputs validation RATING should throw for invalid input #3: [] 1`] = `"Invalid string value [] for text field "ratingField""`;
exports[`DataArgProcessor failing inputs validation RATING should throw for invalid input #4: true 1`] = `"Invalid string value true for text field "ratingField""`;
exports[`DataArgProcessor failing inputs validation RATING should throw for invalid input #5: 1 1`] = `"Invalid string value 1 for text field "ratingField""`;
exports[`DataArgProcessor failing inputs validation RAW_JSON should throw for invalid input #1: "not-a-json" 1`] = `"Invalid object value 'not-a-json' for field "rawJsonField""`;
exports[`DataArgProcessor failing inputs validation RELATION should throw for invalid input #1: {} 1`] = `"Invalid UUID value {} for field "manyToOneRelationFieldId""`;
exports[`DataArgProcessor failing inputs validation RELATION should throw for invalid input #2: [] 1`] = `"Invalid UUID value [] for field "manyToOneRelationFieldId""`;
exports[`DataArgProcessor failing inputs validation RELATION should throw for invalid input #3: true 1`] = `"Invalid UUID value true for field "manyToOneRelationFieldId""`;
exports[`DataArgProcessor failing inputs validation RELATION should throw for invalid input #4: 1 1`] = `"Invalid UUID value 1 for field "manyToOneRelationFieldId""`;
exports[`DataArgProcessor failing inputs validation RELATION should throw for invalid input #5: "non-uuid" 1`] = `"Invalid UUID value 'non-uuid' for field "manyToOneRelationFieldId""`;
exports[`DataArgProcessor failing inputs validation RICH_TEXT should throw for invalid input #1: "test" 1`] = `"richTextField RICH_TEXT-typed field does not support write operations"`;
exports[`DataArgProcessor failing inputs validation RICH_TEXT_V2 should throw for invalid input #1: "not-a-rich-text" 1`] = `"Invalid rich text v2 value 'not-a-rich-text' for field "richTextV2Field" - Should be an object"`;
exports[`DataArgProcessor failing inputs validation RICH_TEXT_V2 should throw for invalid input #2: 1 1`] = `"Invalid rich text v2 value 1 for field "richTextV2Field" - Should be an object"`;
exports[`DataArgProcessor failing inputs validation RICH_TEXT_V2 should throw for invalid input #3: true 1`] = `"Invalid rich text v2 value true for field "richTextV2Field" - Should be an object"`;
exports[`DataArgProcessor failing inputs validation SELECT should throw for invalid input #1: "not-a-select-option" 1`] = `"Invalid value 'not-a-select-option' for field "selectField""`;
exports[`DataArgProcessor failing inputs validation SELECT should throw for invalid input #2: {} 1`] = `"Invalid string value {} for text field "selectField""`;
exports[`DataArgProcessor failing inputs validation SELECT should throw for invalid input #3: [] 1`] = `"Invalid string value [] for text field "selectField""`;
exports[`DataArgProcessor failing inputs validation SELECT should throw for invalid input #4: true 1`] = `"Invalid string value true for text field "selectField""`;
exports[`DataArgProcessor failing inputs validation SELECT should throw for invalid input #5: 1 1`] = `"Invalid string value 1 for text field "selectField""`;
exports[`DataArgProcessor failing inputs validation TEXT should throw for invalid input #1: {} 1`] = `"Invalid string value {} for text field "textField""`;
exports[`DataArgProcessor failing inputs validation TEXT should throw for invalid input #2: [] 1`] = `"Invalid string value [] for text field "textField""`;
exports[`DataArgProcessor failing inputs validation TEXT should throw for invalid input #3: true 1`] = `"Invalid string value true for text field "textField""`;
exports[`DataArgProcessor failing inputs validation TEXT should throw for invalid input #4: 1 1`] = `"Invalid string value 1 for text field "textField""`;
exports[`DataArgProcessor failing inputs validation UUID should throw for invalid input #1: {} 1`] = `"Invalid UUID value {} for field "uuidField""`;
exports[`DataArgProcessor failing inputs validation UUID should throw for invalid input #2: [] 1`] = `"Invalid UUID value [] for field "uuidField""`;
exports[`DataArgProcessor failing inputs validation UUID should throw for invalid input #3: true 1`] = `"Invalid UUID value true for field "uuidField""`;
exports[`DataArgProcessor failing inputs validation UUID should throw for invalid input #4: 1 1`] = `"Invalid UUID value 1 for field "uuidField""`;
exports[`DataArgProcessor failing inputs validation UUID should throw for invalid input #5: "non-uuid" 1`] = `"Invalid UUID value 'non-uuid' for field "uuidField""`;
@@ -0,0 +1,202 @@
import { joinColumnNameForManyToOneMorphRelationField1 } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
export const failingInputsByFieldMetadataType: {
[K in FieldMetadataType]?: {
input: Record<string, unknown>;
}[];
} = {
[FieldMetadataType.TEXT]: [
{ input: { textField: {} } },
{ input: { textField: [] } },
{ input: { textField: true } },
{ input: { textField: 1 } },
],
[FieldMetadataType.NUMBER]: [
{ input: { numberField: {} } },
{ input: { numberField: [] } },
{ input: { numberField: true } },
{ input: { numberField: 'string' } },
],
[FieldMetadataType.UUID]: [
{ input: { uuidField: {} } },
{ input: { uuidField: [] } },
{ input: { uuidField: true } },
{ input: { uuidField: 1 } },
{ input: { uuidField: 'non-uuid' } },
],
[FieldMetadataType.SELECT]: [
{ input: { selectField: 'not-a-select-option' } },
{ input: { selectField: {} } },
{ input: { selectField: [] } },
{ input: { selectField: true } },
{ input: { selectField: 1 } },
],
[FieldMetadataType.RELATION]: [
{ input: { manyToOneRelationFieldId: {} } },
{ input: { manyToOneRelationFieldId: [] } },
{ input: { manyToOneRelationFieldId: true } },
{ input: { manyToOneRelationFieldId: 1 } },
{ input: { manyToOneRelationFieldId: 'non-uuid' } },
],
[FieldMetadataType.RAW_JSON]: [{ input: { rawJsonField: 'not-a-json' } }],
[FieldMetadataType.ARRAY]: [
{ input: { arrayField: true } },
{ input: { arrayField: 1 } },
],
[FieldMetadataType.MORPH_RELATION]: [
{
input: {
[joinColumnNameForManyToOneMorphRelationField1]: 'not-a-morph-relation',
},
},
{ input: { [joinColumnNameForManyToOneMorphRelationField1]: {} } },
{ input: { [joinColumnNameForManyToOneMorphRelationField1]: [] } },
{ input: { [joinColumnNameForManyToOneMorphRelationField1]: true } },
{ input: { [joinColumnNameForManyToOneMorphRelationField1]: 1 } },
],
[FieldMetadataType.RATING]: [
{ input: { ratingField: 'not-a-rating' } },
{ input: { ratingField: {} } },
{ input: { ratingField: [] } },
{ input: { ratingField: true } },
{ input: { ratingField: 1 } },
],
[FieldMetadataType.MULTI_SELECT]: [
{ input: { multiSelectField: 'not-a-select-option' } },
{ input: { multiSelectField: {} } },
{ input: { multiSelectField: true } },
{ input: { multiSelectField: 1 } },
],
[FieldMetadataType.DATE]: [
{ input: { dateField: 'malformed-date' } },
{ input: { dateField: {} } },
{ input: { dateField: [] } },
{ input: { dateField: true } },
{ input: { dateField: 1 } },
{ input: { dateField: '2024' } },
{ input: { dateField: '2024-01' } },
{ input: { dateField: '2024-13-01' } },
{ input: { dateField: '2024-02-31' } },
],
[FieldMetadataType.DATE_TIME]: [
{ input: { dateTimeField: 'malformed-date' } },
{ input: { dateTimeField: {} } },
{ input: { dateTimeField: [] } },
{ input: { dateTimeField: true } },
{ input: { dateTimeField: 1 } },
{ input: { dateTimeField: '2024' } },
{ input: { dateTimeField: '2024-01' } },
{ input: { dateTimeField: '2024-13-01T10:30:00Z' } },
{ input: { dateTimeField: '2024-01-15T25:30:00Z' } },
],
[FieldMetadataType.BOOLEAN]: [
{ input: { booleanField: {} } },
{ input: { booleanField: [] } },
{ input: { booleanField: 'string' } },
{ input: { booleanField: 1 } },
],
[FieldMetadataType.RICH_TEXT]: [{ input: { richTextField: 'test' } }],
[FieldMetadataType.ADDRESS]: [
{ input: { addressField: 'not-an-address' } },
{ input: { addressField: 1 } },
{ input: { addressField: true } },
],
[FieldMetadataType.CURRENCY]: [
{ input: { currencyField: 'not-a-currency' } },
{ input: { currencyField: 1 } },
{ input: { currencyField: true } },
],
[FieldMetadataType.EMAILS]: [
{ input: { emailsField: 'not-an-email' } },
{ input: { emailsField: { primaryEmail: 'not-an-email' } } },
{ input: { emailsField: { additionalEmails: 'not-an-email' } } },
{ input: { emailsField: { additionalEmails: ['not-an-email'] } } },
{
input: {
emailsField: {
primaryEmail: 'email@email.com',
additionalEmails: ['not-an-email'],
},
},
},
{
input: {
emailsField: {
primaryEmail: 'not-an-email',
additionalEmails: ['additional@email.com'],
},
},
},
{
input: {
emailsField: {
additionalEmails: ['not-an-email', 'additional@email.com'],
},
},
},
],
[FieldMetadataType.PHONES]: [
{ input: { phonesField: 'not-a-phone' } },
{ input: { phonesField: 1 } },
{ input: { phonesField: true } },
],
[FieldMetadataType.FULL_NAME]: [
{ input: { fullNameField: 'not-a-full-name' } },
{ input: { fullNameField: 1 } },
{ input: { fullNameField: true } },
],
[FieldMetadataType.LINKS]: [
{ input: { linksField: 'not-a-link' } },
{ input: { linksField: 1 } },
{ input: { linksField: true } },
],
[FieldMetadataType.RICH_TEXT_V2]: [
{ input: { richTextV2Field: 'not-a-rich-text' } },
{ input: { richTextV2Field: 1 } },
{ input: { richTextV2Field: true } },
],
[FieldMetadataType.POSITION]: [
{ input: { position: 'not-a-position' } },
{ input: { position: NaN } },
{ input: { position: {} } },
{ input: { position: [] } },
],
[FieldMetadataType.FILES]: [
{ input: { filesField: 'not-an-addFiles-property' } },
{ input: { filesField: { addFiles: [{ invalidField: 'test' }] } } },
{
input: {
filesField: { addFiles: [{ fileId: 'not-a-uuid', label: 'Doc.pdf' }] },
},
},
{
input: {
filesField: [
{
addFiles: [
{ fileId: '550e8400-e29b-41d4-a716-446655440000', label: 12345 },
],
},
],
},
},
{
input: {
filesField: {
addFiles: [
{
fileId: '550e8400-e29b-41d4-a716-446655440000',
label: 'Document.pdf',
extension: 'not-allowed-in-input',
},
],
},
},
},
],
[FieldMetadataType.NUMERIC]: [
{ input: { numericField: {} } },
{ input: { numericField: 'not-a-number' } },
],
};
@@ -0,0 +1,172 @@
import { joinColumnNameForManyToOneMorphRelationField1 } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import {
type FieldMetadataDefaultOption,
type FieldMetadataOptions,
type FieldMetadataSettings,
FieldMetadataType,
RelationType,
} from 'twenty-shared/types';
export type FieldMetadataConfig = {
name: string;
type: FieldMetadataType;
isNullable: boolean;
options?: FieldMetadataOptions;
settings?: FieldMetadataSettings;
defaultValue?: unknown;
};
export const fieldMetadataConfigByFieldName: Record<
string,
FieldMetadataConfig
> = {
textField: {
name: 'textField',
type: FieldMetadataType.TEXT,
isNullable: true,
},
numberField: {
name: 'numberField',
type: FieldMetadataType.NUMBER,
isNullable: true,
},
numericField: {
name: 'numericField',
type: FieldMetadataType.NUMERIC,
isNullable: true,
},
uuidField: {
name: 'uuidField',
type: FieldMetadataType.UUID,
isNullable: true,
},
selectField: {
name: 'selectField',
type: FieldMetadataType.SELECT,
isNullable: true,
options: [
{ value: 'OPTION_1' },
{ value: 'OPTION_2' },
] as FieldMetadataDefaultOption[],
},
manyToOneRelationFieldId: {
name: 'manyToOneRelationFieldId',
type: FieldMetadataType.RELATION,
isNullable: true,
settings: {
relationType: RelationType.MANY_TO_ONE,
joinColumnName: 'manyToOneRelationFieldId',
},
},
rawJsonField: {
name: 'rawJsonField',
type: FieldMetadataType.RAW_JSON,
isNullable: true,
},
arrayField: {
name: 'arrayField',
type: FieldMetadataType.ARRAY,
isNullable: true,
},
ratingField: {
name: 'ratingField',
type: FieldMetadataType.RATING,
isNullable: true,
options: [
{ value: 'RATING_1' },
{ value: 'RATING_2' },
{ value: 'RATING_3' },
{ value: 'RATING_4' },
{ value: 'RATING_5' },
] as FieldMetadataDefaultOption[],
},
multiSelectField: {
name: 'multiSelectField',
type: FieldMetadataType.MULTI_SELECT,
isNullable: true,
options: [
{ value: 'OPTION_1' },
{ value: 'OPTION_2' },
] as FieldMetadataDefaultOption[],
},
dateField: {
name: 'dateField',
type: FieldMetadataType.DATE,
isNullable: true,
},
dateTimeField: {
name: 'dateTimeField',
type: FieldMetadataType.DATE_TIME,
isNullable: true,
},
booleanField: {
name: 'booleanField',
type: FieldMetadataType.BOOLEAN,
isNullable: true,
},
addressField: {
name: 'addressField',
type: FieldMetadataType.ADDRESS,
isNullable: true,
},
currencyField: {
name: 'currencyField',
type: FieldMetadataType.CURRENCY,
isNullable: true,
},
emailsField: {
name: 'emailsField',
type: FieldMetadataType.EMAILS,
isNullable: true,
},
phonesField: {
name: 'phonesField',
type: FieldMetadataType.PHONES,
isNullable: true,
},
fullNameField: {
name: 'fullNameField',
type: FieldMetadataType.FULL_NAME,
isNullable: true,
},
linksField: {
name: 'linksField',
type: FieldMetadataType.LINKS,
isNullable: true,
},
richTextV2Field: {
name: 'richTextV2Field',
type: FieldMetadataType.RICH_TEXT_V2,
isNullable: true,
},
richTextField: {
name: 'richTextField',
type: FieldMetadataType.RICH_TEXT,
isNullable: true,
},
position: {
name: 'position',
type: FieldMetadataType.POSITION,
isNullable: true,
},
filesField: {
name: 'filesField',
type: FieldMetadataType.FILES,
isNullable: true,
settings: {} as FieldMetadataSettings,
},
actorField: {
name: 'actorField',
type: FieldMetadataType.ACTOR,
isNullable: true,
},
[joinColumnNameForManyToOneMorphRelationField1]: {
name: joinColumnNameForManyToOneMorphRelationField1,
type: FieldMetadataType.MORPH_RELATION,
isNullable: true,
settings: {
relationType: RelationType.MANY_TO_ONE,
joinColumnName: joinColumnNameForManyToOneMorphRelationField1,
},
},
};
@@ -0,0 +1,448 @@
import { joinColumnNameForManyToOneMorphRelationField1 } from 'test/integration/graphql/suites/inputs-validation/utils/setup-test-objects-with-all-field-types.util';
import { FieldMetadataType } from 'twenty-shared/types';
const TEST_UUID = '20202020-b21e-4ec2-873b-de4264d89021';
export const successfulInputsByFieldMetadataType: {
[K in FieldMetadataType]?: {
input: Record<string, unknown>;
expectedOutput: Record<string, unknown>;
}[];
} = {
[FieldMetadataType.TEXT]: [
{ input: { textField: 'test' }, expectedOutput: { textField: 'test' } },
{ input: { textField: '' }, expectedOutput: { textField: null } },
{ input: { textField: null }, expectedOutput: { textField: null } },
],
[FieldMetadataType.NUMBER]: [
{ input: { numberField: 1 }, expectedOutput: { numberField: 1 } },
{ input: { numberField: null }, expectedOutput: { numberField: null } },
{ input: { numberField: 0 }, expectedOutput: { numberField: 0 } },
{ input: { numberField: -1.1 }, expectedOutput: { numberField: -1.1 } },
],
[FieldMetadataType.UUID]: [
{
input: { uuidField: TEST_UUID },
expectedOutput: { uuidField: TEST_UUID },
},
{ input: { uuidField: null }, expectedOutput: { uuidField: null } },
],
[FieldMetadataType.SELECT]: [
{
input: { selectField: 'OPTION_1' },
expectedOutput: { selectField: 'OPTION_1' },
},
{ input: { selectField: null }, expectedOutput: { selectField: null } },
],
[FieldMetadataType.RELATION]: [
{
input: { manyToOneRelationFieldId: TEST_UUID },
expectedOutput: { manyToOneRelationFieldId: TEST_UUID },
},
{
input: { manyToOneRelationFieldId: null },
expectedOutput: { manyToOneRelationFieldId: null },
},
],
[FieldMetadataType.MORPH_RELATION]: [
{
input: { [joinColumnNameForManyToOneMorphRelationField1]: TEST_UUID },
expectedOutput: {
[joinColumnNameForManyToOneMorphRelationField1]: TEST_UUID,
},
},
{
input: { [joinColumnNameForManyToOneMorphRelationField1]: null },
expectedOutput: { [joinColumnNameForManyToOneMorphRelationField1]: null },
},
],
[FieldMetadataType.RAW_JSON]: [
{
input: { rawJsonField: { key: 'value' } },
expectedOutput: { rawJsonField: { key: 'value' } },
},
{ input: { rawJsonField: {} }, expectedOutput: { rawJsonField: null } },
{ input: { rawJsonField: null }, expectedOutput: { rawJsonField: null } },
{
input: { rawJsonField: '{"key": "value"}' },
expectedOutput: { rawJsonField: '{"key": "value"}' },
},
],
[FieldMetadataType.ARRAY]: [
{
input: { arrayField: ['item1', 'item2'] },
expectedOutput: { arrayField: ['item1', 'item2'] },
},
{
input: { arrayField: 'item1' },
expectedOutput: { arrayField: ['item1'] },
},
{ input: { arrayField: [] }, expectedOutput: { arrayField: null } },
{ input: { arrayField: null }, expectedOutput: { arrayField: null } },
],
[FieldMetadataType.RATING]: [
{
input: { ratingField: 'RATING_2' },
expectedOutput: { ratingField: 'RATING_2' },
},
{ input: { ratingField: null }, expectedOutput: { ratingField: null } },
],
[FieldMetadataType.MULTI_SELECT]: [
{
input: { multiSelectField: ['OPTION_1'] },
expectedOutput: { multiSelectField: ['OPTION_1'] },
},
{
input: { multiSelectField: [] },
expectedOutput: { multiSelectField: null },
},
{
input: { multiSelectField: null },
expectedOutput: { multiSelectField: null },
},
],
[FieldMetadataType.DATE]: [
{ input: { dateField: null }, expectedOutput: { dateField: null } },
{
input: { dateField: '2025-01-13' },
expectedOutput: { dateField: '2025-01-13' },
},
{
input: { dateField: '20250113' },
expectedOutput: { dateField: '20250113' },
},
{
input: { dateField: '2025.01.13' },
expectedOutput: { dateField: '2025.01.13' },
},
{
input: { dateField: '2025/01/13' },
expectedOutput: { dateField: '2025/01/13' },
},
{
input: { dateField: '01-13-2025' },
expectedOutput: { dateField: '01-13-2025' },
},
{
input: { dateField: '01/13/2025' },
expectedOutput: { dateField: '01/13/2025' },
},
{
input: { dateField: '01.13.2025' },
expectedOutput: { dateField: '01.13.2025' },
},
{
input: { dateField: 'January 13, 2025' },
expectedOutput: { dateField: 'January 13, 2025' },
},
{
input: { dateField: 'Jan 13, 2025' },
expectedOutput: { dateField: 'Jan 13, 2025' },
},
{
input: { dateField: '13 January 2025' },
expectedOutput: { dateField: '13 January 2025' },
},
{
input: { dateField: '13 Jan 2025' },
expectedOutput: { dateField: '13 Jan 2025' },
},
{
input: { dateField: '13-Jan-2025' },
expectedOutput: { dateField: '13-Jan-2025' },
},
{
input: { dateField: '2025-Jan-13' },
expectedOutput: { dateField: '2025-Jan-13' },
},
{
input: { dateField: '2025-01-13T10:30:00.000Z' },
expectedOutput: { dateField: '2025-01-13T10:30:00.000Z' },
},
{
input: { dateField: '2025-01-13T10:30:00Z' },
expectedOutput: { dateField: '2025-01-13T10:30:00Z' },
},
{
input: { dateField: '2025-01-13T10:30:00.000' },
expectedOutput: { dateField: '2025-01-13T10:30:00.000' },
},
{
input: { dateField: '2025-01-13T10:30:00' },
expectedOutput: { dateField: '2025-01-13T10:30:00' },
},
{
input: { dateField: '2025-01-13 10:30:00' },
expectedOutput: { dateField: '2025-01-13 10:30:00' },
},
{
input: { dateField: '2025-01-13 10:30:00.000' },
expectedOutput: { dateField: '2025-01-13 10:30:00.000' },
},
],
[FieldMetadataType.DATE_TIME]: [
{ input: { dateTimeField: null }, expectedOutput: { dateTimeField: null } },
{
input: { dateTimeField: '2025-01-13T10:30:00.000Z' },
expectedOutput: { dateTimeField: '2025-01-13T10:30:00.000Z' },
},
{
input: { dateTimeField: '2025-01-13T10:30:00Z' },
expectedOutput: { dateTimeField: '2025-01-13T10:30:00Z' },
},
{
input: { dateTimeField: '2025-01-13T10:30:00.000+02:00' },
expectedOutput: { dateTimeField: '2025-01-13T10:30:00.000+02:00' },
},
{
input: { dateTimeField: '2025-01-13T10:30:00+02:00' },
expectedOutput: { dateTimeField: '2025-01-13T10:30:00+02:00' },
},
{
input: { dateTimeField: '2025-01-13T10:30:00.000' },
expectedOutput: { dateTimeField: '2025-01-13T10:30:00.000' },
},
{
input: { dateTimeField: '2025-01-13T10:30:00' },
expectedOutput: { dateTimeField: '2025-01-13T10:30:00' },
},
{
input: { dateTimeField: '2025-01-13 10:30:00.000' },
expectedOutput: { dateTimeField: '2025-01-13 10:30:00.000' },
},
{
input: { dateTimeField: '2025-01-13 10:30:00' },
expectedOutput: { dateTimeField: '2025-01-13 10:30:00' },
},
{
input: { dateTimeField: '2025-01-13 10:30' },
expectedOutput: { dateTimeField: '2025-01-13 10:30' },
},
{
input: { dateTimeField: '2025-01-13' },
expectedOutput: { dateTimeField: '2025-01-13' },
},
{
input: { dateTimeField: '20250113' },
expectedOutput: { dateTimeField: '20250113' },
},
{
input: { dateTimeField: '2025.01.13' },
expectedOutput: { dateTimeField: '2025.01.13' },
},
{
input: { dateTimeField: '2025/01/13' },
expectedOutput: { dateTimeField: '2025/01/13' },
},
{
input: { dateTimeField: '01-13-2025' },
expectedOutput: { dateTimeField: '01-13-2025' },
},
{
input: { dateTimeField: '01/13/2025' },
expectedOutput: { dateTimeField: '01/13/2025' },
},
{
input: { dateTimeField: '01.13.2025' },
expectedOutput: { dateTimeField: '01.13.2025' },
},
{
input: { dateTimeField: 'January 13, 2025' },
expectedOutput: { dateTimeField: 'January 13, 2025' },
},
{
input: { dateTimeField: 'Jan 13, 2025' },
expectedOutput: { dateTimeField: 'Jan 13, 2025' },
},
{
input: { dateTimeField: '13 January 2025' },
expectedOutput: { dateTimeField: '13 January 2025' },
},
{
input: { dateTimeField: '13 Jan 2025' },
expectedOutput: { dateTimeField: '13 Jan 2025' },
},
{
input: { dateTimeField: '13-Jan-2025' },
expectedOutput: { dateTimeField: '13-Jan-2025' },
},
{
input: { dateTimeField: '2025-Jan-13' },
expectedOutput: { dateTimeField: '2025-Jan-13' },
},
],
[FieldMetadataType.BOOLEAN]: [
{ input: { booleanField: true }, expectedOutput: { booleanField: true } },
{ input: { booleanField: false }, expectedOutput: { booleanField: false } },
{ input: { booleanField: null }, expectedOutput: { booleanField: null } },
],
[FieldMetadataType.ADDRESS]: [
{
input: {
addressField: {
addressPostcode: 'postcode',
addressStreet1: 'street 1',
addressStreet2: 'street 2',
addressCity: 'city',
addressState: 'state',
addressCountry: 'country',
},
},
expectedOutput: {
addressField: {
addressPostcode: 'postcode',
addressStreet1: 'street 1',
addressStreet2: 'street 2',
addressCity: 'city',
addressState: 'state',
addressCountry: 'country',
addressLat: undefined,
addressLng: undefined,
},
},
},
{ input: { addressField: null }, expectedOutput: { addressField: null } },
],
[FieldMetadataType.CURRENCY]: [
{
input: { currencyField: { amountMicros: 1000000, currencyCode: 'USD' } },
expectedOutput: {
currencyField: { amountMicros: 1000000, currencyCode: 'USD' },
},
},
{ input: { currencyField: null }, expectedOutput: { currencyField: null } },
],
[FieldMetadataType.EMAILS]: [
{
input: {
emailsField: {
primaryEmail: 'test@test.com',
additionalEmails: ['test2@test.com'],
},
},
expectedOutput: {
emailsField: {
primaryEmail: 'test@test.com',
additionalEmails: '["test2@test.com"]',
},
},
},
{ input: { emailsField: null }, expectedOutput: { emailsField: null } },
],
[FieldMetadataType.PHONES]: [
{
input: {
phonesField: {
primaryPhoneNumber: '1234567890',
primaryPhoneCountryCode: 'FR',
primaryPhoneCallingCode: '+33',
additionalPhones: [
{ number: '1234567890', callingCode: '+33', countryCode: 'FR' },
],
},
},
expectedOutput: {
phonesField: {
primaryPhoneNumber: '1234567890',
primaryPhoneCountryCode: 'FR',
primaryPhoneCallingCode: '+33',
additionalPhones:
'[{"countryCode":"FR","callingCode":"+33","number":"1234567890"}]',
},
},
},
{ input: { phonesField: null }, expectedOutput: { phonesField: null } },
],
[FieldMetadataType.FULL_NAME]: [
{
input: { fullNameField: { firstName: 'John', lastName: 'Doe' } },
expectedOutput: {
fullNameField: { firstName: 'John', lastName: 'Doe' },
},
},
{ input: { fullNameField: null }, expectedOutput: { fullNameField: null } },
],
[FieldMetadataType.LINKS]: [
{
input: {
linksField: {
primaryLinkUrl: 'https://twenty.com',
primaryLinkLabel: 'Twenty',
secondaryLinks: [{ url: 'twenty.com', label: 'Twenty' }],
},
},
expectedOutput: {
linksField: {
primaryLinkUrl: 'https://twenty.com',
primaryLinkLabel: 'Twenty',
secondaryLinks: '[{"url":"twenty.com","label":"Twenty"}]',
},
},
},
{ input: { linksField: null }, expectedOutput: { linksField: null } },
],
[FieldMetadataType.RICH_TEXT_V2]: [
{
input: { richTextV2Field: { blocknote: 'test', markdown: 'test' } },
expectedOutput: {
richTextV2Field: { blocknote: 'test', markdown: 'test' },
},
},
{
input: { richTextV2Field: null },
expectedOutput: { richTextV2Field: null },
},
],
[FieldMetadataType.POSITION]: [
{ input: { position: 1000 }, expectedOutput: { position: 1000 } },
{ input: { position: 0 }, expectedOutput: { position: 0 } },
{ input: { position: -100 }, expectedOutput: { position: -100 } },
],
[FieldMetadataType.FILES]: [
{
input: {
filesField: [
{ fileId: '550e8400-e29b-41d4-a716-446655440000', label: 'Doc.pdf' },
],
},
expectedOutput: {
filesField: [
{ fileId: '550e8400-e29b-41d4-a716-446655440000', label: 'Doc.pdf' },
],
},
},
{ input: { filesField: [] }, expectedOutput: { filesField: null } },
{ input: { filesField: null }, expectedOutput: { filesField: null } },
],
[FieldMetadataType.NUMERIC]: [
{
input: { numericField: '123.45' },
expectedOutput: { numericField: 123.45 },
},
{
input: { numericField: 123.45 },
expectedOutput: { numericField: 123.45 },
},
{ input: { numericField: null }, expectedOutput: { numericField: null } },
],
[FieldMetadataType.ACTOR]: [
{
input: {
actorField: {
source: 'MANUAL',
name: 'John Doe',
workspaceMemberId: TEST_UUID,
},
},
expectedOutput: {
actorField: {
source: 'MANUAL',
name: 'John Doe',
workspaceMemberId: TEST_UUID,
context: undefined,
},
},
},
{ input: { actorField: null }, expectedOutput: { actorField: null } },
],
};
@@ -0,0 +1,195 @@
import { Test, type TestingModule } from '@nestjs/testing';
import { FieldMetadataType } from 'twenty-shared/types';
import { DataArgProcessor } from 'src/engine/api/common/common-args-processors/data-arg-processor/data-arg.processor';
import { type AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { RecordPositionService } from 'src/engine/core-modules/record-position/services/record-position.service';
import { type FlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/flat-entity-maps.type';
import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type';
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
import { failingInputsByFieldMetadataType } from './constants/failing-inputs-by-field-metadata-type.constant';
import { fieldMetadataConfigByFieldName } from './constants/field-metadata-config-by-field-name.constant';
import { successfulInputsByFieldMetadataType } from './constants/successful-inputs-by-field-metadata-type.constant';
// Mock the rich text v2 transformation to avoid BlockNote module issues
jest.mock(
'src/engine/core-modules/record-transformer/utils/transform-rich-text-v2.util',
() => ({
transformRichTextV2Value: jest.fn().mockImplementation((value) => value),
}),
);
describe('DataArgProcessor', () => {
let dataArgProcessor: DataArgProcessor;
let recordPositionService: jest.Mocked<RecordPositionService>;
const mockWorkspaceId = '20202020-1234-1234-1234-123456789012';
const createMockAuthContext = (): AuthContext =>
({
workspace: {
id: mockWorkspaceId,
},
}) as AuthContext;
const createFlatFieldMetadataMaps = (
fieldNames: string[],
): FlatEntityMaps<FlatFieldMetadata> => {
const byUniversalIdentifier: Record<string, FlatFieldMetadata> = {};
const universalIdentifierById: Record<string, string> = {};
for (const fieldName of fieldNames) {
const config = fieldMetadataConfigByFieldName[fieldName];
if (!config) {
throw new Error(`No config found for field: ${fieldName}`);
}
const fieldId = `${fieldName}-id`;
const universalId = `${fieldName}-universal-id`;
byUniversalIdentifier[universalId] = {
id: fieldId,
name: fieldName,
type: config.type ?? FieldMetadataType.TEXT,
isNullable: config.isNullable ?? true,
objectMetadataId: 'object-id',
universalIdentifier: universalId,
options: config.options,
settings: config.settings,
defaultValue: config.defaultValue,
} as FlatFieldMetadata;
universalIdentifierById[fieldId] = universalId;
}
return {
byUniversalIdentifier,
universalIdentifierById,
universalIdentifiersByApplicationId: {},
};
};
const createFlatObjectMetadata = (fieldNames: string[]): FlatObjectMetadata =>
({
id: 'object-id',
nameSingular: 'testObject',
namePlural: 'testObjects',
isCustom: false,
fieldIds: fieldNames.map((name) => `${name}-id`),
universalIdentifier: 'test-object-universal-id',
labelIdentifierFieldMetadataUniversalIdentifier: null,
imageIdentifierFieldMetadataUniversalIdentifier: null,
}) as FlatObjectMetadata;
beforeEach(async () => {
recordPositionService = {
overridePositionOnRecords: jest
.fn()
.mockImplementation(({ partialRecordInputs }) => partialRecordInputs),
buildRecordPosition: jest.fn(),
findByPosition: jest.fn(),
updatePosition: jest.fn(),
} as unknown as jest.Mocked<RecordPositionService>;
const module: TestingModule = await Test.createTestingModule({
providers: [
DataArgProcessor,
{
provide: RecordPositionService,
useValue: recordPositionService,
},
],
}).compile();
dataArgProcessor = module.get<DataArgProcessor>(DataArgProcessor);
});
afterEach(() => {
jest.clearAllMocks();
});
it('should be defined', () => {
expect(dataArgProcessor).toBeDefined();
});
describe('failing inputs validation', () => {
const fieldMetadataTypesToTest = Object.keys(
failingInputsByFieldMetadataType,
) as FieldMetadataType[];
for (const fieldMetadataType of fieldMetadataTypesToTest) {
const testCases = failingInputsByFieldMetadataType[fieldMetadataType];
if (!testCases) {
continue;
}
describe(`${fieldMetadataType}`, () => {
for (const [index, testCase] of testCases.entries()) {
const fieldName = Object.keys(testCase.input)[0];
const fieldValue = testCase.input[fieldName];
it(`should throw for invalid input #${index + 1}: ${JSON.stringify(fieldValue)}`, async () => {
const fieldNames = [fieldName];
const flatFieldMetadataMaps =
createFlatFieldMetadataMaps(fieldNames);
const flatObjectMetadata = createFlatObjectMetadata(fieldNames);
await expect(
dataArgProcessor.process({
partialRecordInputs: [testCase.input],
authContext: createMockAuthContext(),
flatObjectMetadata,
flatFieldMetadataMaps,
}),
).rejects.toThrowErrorMatchingSnapshot();
});
}
});
}
});
describe('successful inputs validation', () => {
const fieldMetadataTypesToTest = Object.keys(
successfulInputsByFieldMetadataType,
) as FieldMetadataType[];
for (const fieldMetadataType of fieldMetadataTypesToTest) {
const testCases = successfulInputsByFieldMetadataType[fieldMetadataType];
if (!testCases) {
continue;
}
describe(`${fieldMetadataType}`, () => {
for (const [index, testCase] of testCases.entries()) {
const fieldName = Object.keys(testCase.input)[0];
const fieldValue = testCase.input[fieldName];
it(`should process valid input #${index + 1}: ${JSON.stringify(fieldValue)}`, async () => {
const fieldNames = [fieldName];
const flatFieldMetadataMaps =
createFlatFieldMetadataMaps(fieldNames);
const flatObjectMetadata = createFlatObjectMetadata(fieldNames);
const result = await dataArgProcessor.process({
partialRecordInputs: [testCase.input],
authContext: createMockAuthContext(),
flatObjectMetadata,
flatFieldMetadataMaps,
});
expect(result).toBeDefined();
expect(result).toHaveLength(1);
expect(result[0]).toEqual(testCase.expectedOutput);
});
}
});
}
});
});
@@ -27,7 +27,8 @@ import { validateAddressFieldOrThrow } from 'src/engine/api/common/common-args-p
import { validateArrayFieldOrThrow } from 'src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/validate-array-field-or-throw.util';
import { validateBooleanFieldOrThrow } from 'src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/validate-boolean-field-or-throw.util';
import { validateCurrencyFieldOrThrow } from 'src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/validate-currency-field-or-throw.util';
import { validateDateAndDateTimeFieldOrThrow } from 'src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/validate-date-and-date-time-field-or-throw.util';
import { validateDateFieldOrThrow } from 'src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/validate-date-field-or-throw.util';
import { validateDateTimeFieldOrThrow } from 'src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/validate-date-time-field-or-throw.util';
import { validateEmailsFieldOrThrow } from 'src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/validate-emails-field-or-throw.util';
import { validateFilesFieldOrThrow } from 'src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/validate-files-field-or-throw.util';
import { validateFullNameFieldOrThrow } from 'src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/validate-full-name-field-or-throw.util';
@@ -184,8 +185,9 @@ export class DataArgProcessor {
return transformTextField(validatedValue);
}
case FieldMetadataType.DATE_TIME:
return validateDateTimeFieldOrThrow(value, key);
case FieldMetadataType.DATE:
return validateDateAndDateTimeFieldOrThrow(value, key);
return validateDateFieldOrThrow(value, key);
case FieldMetadataType.BOOLEAN:
return validateBooleanFieldOrThrow(value, key);
case FieldMetadataType.RATING:
@@ -1,97 +0,0 @@
import { validateDateAndDateTimeFieldOrThrow } from 'src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/validate-date-and-date-time-field-or-throw.util';
import { CommonQueryRunnerException } from 'src/engine/api/common/common-query-runners/errors/common-query-runner.exception';
describe('validateDateAndDateTimeFieldOrThrow', () => {
describe('valid inputs', () => {
it('should return null when value is null', () => {
const result = validateDateAndDateTimeFieldOrThrow(null, 'testField');
expect(result).toBeNull();
});
it('should return the value when it is a valid ISO date string', () => {
const dateString = '2024-01-15';
const result = validateDateAndDateTimeFieldOrThrow(
dateString,
'testField',
);
expect(result).toBe(dateString);
});
it('should return the value when it is a valid ISO datetime string', () => {
const datetimeString = '2024-01-15T10:30:00Z';
const result = validateDateAndDateTimeFieldOrThrow(
datetimeString,
'testField',
);
expect(result).toBe(datetimeString);
});
it('should return the value when it is a Date object', () => {
const dateObject = new Date('2024-01-15');
const result = validateDateAndDateTimeFieldOrThrow(
dateObject,
'testField',
);
expect(result).toBe(dateObject);
});
it('should return the value when it is a timestamp number', () => {
const timestamp = Date.now();
const result = validateDateAndDateTimeFieldOrThrow(
timestamp,
'testField',
);
expect(result).toBe(timestamp);
});
it('should return the value when it is a Date', () => {
const date = new Date();
const result = validateDateAndDateTimeFieldOrThrow(date, 'testField');
expect(result).toBe(date);
});
});
describe('invalid inputs', () => {
it('should throw when value is an invalid date string', () => {
expect(() =>
validateDateAndDateTimeFieldOrThrow('invalid-date', 'testField'),
).toThrow(CommonQueryRunnerException);
});
it('should throw when value is an empty string', () => {
expect(() =>
validateDateAndDateTimeFieldOrThrow('', 'testField'),
).toThrow(CommonQueryRunnerException);
});
it('should throw when value is a boolean', () => {
expect(() =>
validateDateAndDateTimeFieldOrThrow(true, 'testField'),
).toThrow(CommonQueryRunnerException);
});
it('should throw when value is an array', () => {
expect(() =>
validateDateAndDateTimeFieldOrThrow([], 'testField'),
).toThrow(CommonQueryRunnerException);
});
it('should throw when value is an object', () => {
expect(() =>
validateDateAndDateTimeFieldOrThrow({}, 'testField'),
).toThrow(CommonQueryRunnerException);
});
it('should throw when value is undefined', () => {
expect(() =>
validateDateAndDateTimeFieldOrThrow(undefined, 'testField'),
).toThrow(CommonQueryRunnerException);
});
});
});
@@ -0,0 +1,191 @@
import { validateDateFieldOrThrow } from 'src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/validate-date-field-or-throw.util';
import { CommonQueryRunnerException } from 'src/engine/api/common/common-query-runners/errors/common-query-runner.exception';
describe('validateDateFieldOrThrow', () => {
describe('valid inputs', () => {
it('should return null when value is null', () => {
const result = validateDateFieldOrThrow(null, 'testField');
expect(result).toBeNull();
});
it('should return the value when it is a valid ISO date string (YYYY-MM-DD)', () => {
const dateString = '2024-01-15';
const result = validateDateFieldOrThrow(dateString, 'testField');
expect(result).toBe(dateString);
});
it('should return the value when it is a valid ISO compact date string (YYYYMMDD)', () => {
const dateString = '20240115';
const result = validateDateFieldOrThrow(dateString, 'testField');
expect(result).toBe(dateString);
});
it('should return the value when it is a valid date with dots (YYYY.MM.DD)', () => {
const dateString = '2024.01.15';
const result = validateDateFieldOrThrow(dateString, 'testField');
expect(result).toBe(dateString);
});
it('should return the value when it is a valid date with slashes (YYYY/MM/DD)', () => {
const dateString = '2024/01/15';
const result = validateDateFieldOrThrow(dateString, 'testField');
expect(result).toBe(dateString);
});
it('should return the value when it is a valid date in MM-DD-YYYY format', () => {
const dateString = '01-15-2024';
const result = validateDateFieldOrThrow(dateString, 'testField');
expect(result).toBe(dateString);
});
it('should return the value when it is a valid date in MM/DD/YYYY format', () => {
const dateString = '01/15/2024';
const result = validateDateFieldOrThrow(dateString, 'testField');
expect(result).toBe(dateString);
});
it('should return the value when it is a valid date with full month name (MMMM d, yyyy)', () => {
const dateString = 'January 15, 2024';
const result = validateDateFieldOrThrow(dateString, 'testField');
expect(result).toBe(dateString);
});
it('should return the value when it is a valid date with abbreviated month name (MMM d, yyyy)', () => {
const dateString = 'Jan 15, 2024';
const result = validateDateFieldOrThrow(dateString, 'testField');
expect(result).toBe(dateString);
});
it('should return the value when it is a valid date in d MMMM yyyy format', () => {
const dateString = '15 January 2024';
const result = validateDateFieldOrThrow(dateString, 'testField');
expect(result).toBe(dateString);
});
it('should return the value when it is a valid date in d MMM yyyy format', () => {
const dateString = '15 Jan 2024';
const result = validateDateFieldOrThrow(dateString, 'testField');
expect(result).toBe(dateString);
});
it('should return the value when it is a valid ISO datetime string (time will be ignored by PostgreSQL)', () => {
const datetimeString = '2024-01-15T10:30:00Z';
const result = validateDateFieldOrThrow(datetimeString, 'testField');
expect(result).toBe(datetimeString);
});
it('should return the value when it is a valid datetime with milliseconds', () => {
const datetimeString = '2024-01-15T10:30:00.000Z';
const result = validateDateFieldOrThrow(datetimeString, 'testField');
expect(result).toBe(datetimeString);
});
it('should return the value when it is a valid datetime without timezone', () => {
const datetimeString = '2024-01-15T10:30:00';
const result = validateDateFieldOrThrow(datetimeString, 'testField');
expect(result).toBe(datetimeString);
});
it('should return the value when it is a valid datetime with space separator', () => {
const datetimeString = '2024-01-15 10:30:00';
const result = validateDateFieldOrThrow(datetimeString, 'testField');
expect(result).toBe(datetimeString);
});
it('should return the value when it is a Date object', () => {
const dateObject = new Date('2024-01-15');
const result = validateDateFieldOrThrow(dateObject, 'testField');
expect(result).toBe(dateObject);
});
});
describe('invalid inputs', () => {
it('should throw when value is just a year', () => {
expect(() => validateDateFieldOrThrow('2024', 'testField')).toThrow(
CommonQueryRunnerException,
);
});
it('should throw when value is year and month only', () => {
expect(() => validateDateFieldOrThrow('2024-01', 'testField')).toThrow(
CommonQueryRunnerException,
);
});
it('should throw when value is an invalid date string', () => {
expect(() =>
validateDateFieldOrThrow('invalid-date', 'testField'),
).toThrow(CommonQueryRunnerException);
});
it('should throw when value is an empty string', () => {
expect(() => validateDateFieldOrThrow('', 'testField')).toThrow(
CommonQueryRunnerException,
);
});
it('should throw when value is a boolean', () => {
expect(() => validateDateFieldOrThrow(true, 'testField')).toThrow(
CommonQueryRunnerException,
);
});
it('should throw when value is an array', () => {
expect(() => validateDateFieldOrThrow([], 'testField')).toThrow(
CommonQueryRunnerException,
);
});
it('should throw when value is an object', () => {
expect(() => validateDateFieldOrThrow({}, 'testField')).toThrow(
CommonQueryRunnerException,
);
});
it('should throw when value is undefined', () => {
expect(() => validateDateFieldOrThrow(undefined, 'testField')).toThrow(
CommonQueryRunnerException,
);
});
it('should throw when value is a number (timestamp)', () => {
expect(() => validateDateFieldOrThrow(1234567890, 'testField')).toThrow(
CommonQueryRunnerException,
);
});
it('should throw when value is a random string', () => {
expect(() =>
validateDateFieldOrThrow('hello world', 'testField'),
).toThrow(CommonQueryRunnerException);
});
it('should throw when value is a date with invalid month', () => {
expect(() => validateDateFieldOrThrow('2024-13-01', 'testField')).toThrow(
CommonQueryRunnerException,
);
});
it('should throw when value is a date with invalid day', () => {
expect(() => validateDateFieldOrThrow('2024-02-31', 'testField')).toThrow(
CommonQueryRunnerException,
);
});
});
});
@@ -0,0 +1,189 @@
import { validateDateTimeFieldOrThrow } from 'src/engine/api/common/common-args-processors/data-arg-processor/validator-utils/validate-date-time-field-or-throw.util';
import { CommonQueryRunnerException } from 'src/engine/api/common/common-query-runners/errors/common-query-runner.exception';
describe('validateDateTimeFieldOrThrow', () => {
describe('valid inputs', () => {
it('should return null when value is null', () => {
const result = validateDateTimeFieldOrThrow(null, 'testField');
expect(result).toBeNull();
});
it('should return the value when it is a valid ISO datetime string with Z timezone', () => {
const datetimeString = '2024-01-15T10:30:00Z';
const result = validateDateTimeFieldOrThrow(datetimeString, 'testField');
expect(result).toBe(datetimeString);
});
it('should return the value when it is a valid ISO datetime string with milliseconds and Z timezone', () => {
const datetimeString = '2024-01-15T10:30:00.000Z';
const result = validateDateTimeFieldOrThrow(datetimeString, 'testField');
expect(result).toBe(datetimeString);
});
it('should return the value when it is a valid ISO datetime string with timezone offset', () => {
const datetimeString = '2024-01-15T10:30:00+02:00';
const result = validateDateTimeFieldOrThrow(datetimeString, 'testField');
expect(result).toBe(datetimeString);
});
it('should return the value when it is a valid ISO datetime string with milliseconds and timezone offset', () => {
const datetimeString = '2024-01-15T10:30:00.000+02:00';
const result = validateDateTimeFieldOrThrow(datetimeString, 'testField');
expect(result).toBe(datetimeString);
});
it('should return the value when it is a valid ISO datetime string without timezone', () => {
const datetimeString = '2024-01-15T10:30:00';
const result = validateDateTimeFieldOrThrow(datetimeString, 'testField');
expect(result).toBe(datetimeString);
});
it('should return the value when it is a valid ISO datetime string with milliseconds without timezone', () => {
const datetimeString = '2024-01-15T10:30:00.000';
const result = validateDateTimeFieldOrThrow(datetimeString, 'testField');
expect(result).toBe(datetimeString);
});
it('should return the value when it is a valid datetime with space separator', () => {
const datetimeString = '2024-01-15 10:30:00';
const result = validateDateTimeFieldOrThrow(datetimeString, 'testField');
expect(result).toBe(datetimeString);
});
it('should return the value when it is a valid datetime with space separator and milliseconds', () => {
const datetimeString = '2024-01-15 10:30:00.000';
const result = validateDateTimeFieldOrThrow(datetimeString, 'testField');
expect(result).toBe(datetimeString);
});
it('should return the value when it is a valid datetime with space separator without seconds', () => {
const datetimeString = '2024-01-15 10:30';
const result = validateDateTimeFieldOrThrow(datetimeString, 'testField');
expect(result).toBe(datetimeString);
});
it('should return the value when it is a valid ISO date string (will be treated as midnight)', () => {
const dateString = '2024-01-15';
const result = validateDateTimeFieldOrThrow(dateString, 'testField');
expect(result).toBe(dateString);
});
it('should return the value when it is a valid ISO compact date string', () => {
const dateString = '20240115';
const result = validateDateTimeFieldOrThrow(dateString, 'testField');
expect(result).toBe(dateString);
});
it('should return the value when it is a valid date with full month name', () => {
const dateString = 'January 15, 2024';
const result = validateDateTimeFieldOrThrow(dateString, 'testField');
expect(result).toBe(dateString);
});
it('should return the value when it is a Date object', () => {
const dateObject = new Date('2024-01-15T10:30:00Z');
const result = validateDateTimeFieldOrThrow(dateObject, 'testField');
expect(result).toBe(dateObject);
});
});
describe('invalid inputs', () => {
it('should throw when value is just a year', () => {
expect(() => validateDateTimeFieldOrThrow('2024', 'testField')).toThrow(
CommonQueryRunnerException,
);
});
it('should throw when value is year and month only', () => {
expect(() =>
validateDateTimeFieldOrThrow('2024-01', 'testField'),
).toThrow(CommonQueryRunnerException);
});
it('should throw when value is an invalid datetime string', () => {
expect(() =>
validateDateTimeFieldOrThrow('invalid-datetime', 'testField'),
).toThrow(CommonQueryRunnerException);
});
it('should throw when value is an empty string', () => {
expect(() => validateDateTimeFieldOrThrow('', 'testField')).toThrow(
CommonQueryRunnerException,
);
});
it('should throw when value is a boolean', () => {
expect(() => validateDateTimeFieldOrThrow(true, 'testField')).toThrow(
CommonQueryRunnerException,
);
});
it('should throw when value is an array', () => {
expect(() => validateDateTimeFieldOrThrow([], 'testField')).toThrow(
CommonQueryRunnerException,
);
});
it('should throw when value is an object', () => {
expect(() => validateDateTimeFieldOrThrow({}, 'testField')).toThrow(
CommonQueryRunnerException,
);
});
it('should throw when value is undefined', () => {
expect(() =>
validateDateTimeFieldOrThrow(undefined, 'testField'),
).toThrow(CommonQueryRunnerException);
});
it('should throw when value is a number (timestamp)', () => {
expect(() =>
validateDateTimeFieldOrThrow(1234567890, 'testField'),
).toThrow(CommonQueryRunnerException);
});
it('should throw when value is a random string', () => {
expect(() =>
validateDateTimeFieldOrThrow('hello world', 'testField'),
).toThrow(CommonQueryRunnerException);
});
it('should throw when value is a datetime with invalid month', () => {
expect(() =>
validateDateTimeFieldOrThrow('2024-13-01T10:30:00Z', 'testField'),
).toThrow(CommonQueryRunnerException);
});
it('should throw when value is a datetime with invalid day', () => {
expect(() =>
validateDateTimeFieldOrThrow('2024-02-31T10:30:00Z', 'testField'),
).toThrow(CommonQueryRunnerException);
});
it('should throw when value is a datetime with invalid hour', () => {
expect(() =>
validateDateTimeFieldOrThrow('2024-01-15T25:30:00Z', 'testField'),
).toThrow(CommonQueryRunnerException);
});
it('should throw when value is a datetime with invalid minute', () => {
expect(() =>
validateDateTimeFieldOrThrow('2024-01-15T10:60:00Z', 'testField'),
).toThrow(CommonQueryRunnerException);
});
});
});
@@ -1,31 +0,0 @@
import { inspect } from 'util';
import { msg } from '@lingui/core/macro';
import { isDate, isNull, isNumber, isString } from '@sniptt/guards';
import {
CommonQueryRunnerException,
CommonQueryRunnerExceptionCode,
} from 'src/engine/api/common/common-query-runners/errors/common-query-runner.exception';
// TODO: should be splitted in both validateDate and validateDateTime because both format are different even if Date parses them indeferrently
export const validateDateAndDateTimeFieldOrThrow = (
value: unknown,
fieldName: string,
) => {
if (isNull(value)) return null;
if (isString(value) || isNumber(value) || isDate(value)) {
const date = new Date(value);
if (!isNaN(date.getTime())) return value;
}
const inspectedValue = inspect(value);
throw new CommonQueryRunnerException(
`Invalid value ${inspectedValue} for date or date-time field "${fieldName}"`,
CommonQueryRunnerExceptionCode.INVALID_ARGS_DATA,
{ userFriendlyMessage: msg`Invalid value for date: "${inspectedValue}"` },
);
};
@@ -0,0 +1,69 @@
import { inspect } from 'util';
import { msg } from '@lingui/core/macro';
import { isDate, isNull, isString } from '@sniptt/guards';
import { isValid, parse } from 'date-fns';
import {
CommonQueryRunnerException,
CommonQueryRunnerExceptionCode,
} from 'src/engine/api/common/common-query-runners/errors/common-query-runner.exception';
const ACCEPTED_DATE_FORMATS = [
'yyyy-MM-dd',
'yyyyMMdd',
'yyyy.MM.dd',
'yyyy/MM/dd',
'MM-dd-yyyy',
'MM/dd/yyyy',
'MM.dd.yyyy',
'MMMM d, yyyy',
'MMM d, yyyy',
'd MMMM yyyy',
'd MMM yyyy',
'dd-MMM-yyyy',
'yyyy-MMM-dd',
"yyyy-MM-dd'T'HH:mm:ss.SSSX",
"yyyy-MM-dd'T'HH:mm:ssX",
"yyyy-MM-dd'T'HH:mm:ss.SSS",
"yyyy-MM-dd'T'HH:mm:ss",
'yyyy-MM-dd HH:mm:ss',
'yyyy-MM-dd HH:mm:ss.SSS',
];
const isValidDateFormat = (value: string): boolean => {
for (const format of ACCEPTED_DATE_FORMATS) {
const parsed = parse(value, format, new Date());
if (isValid(parsed)) {
return true;
}
}
return false;
};
export const validateDateFieldOrThrow = (
value: unknown,
fieldName: string,
): unknown => {
if (isNull(value)) return null;
if (isDate(value) && isValid(value)) {
return value;
}
if (isString(value) && isValidDateFormat(value)) {
return value;
}
const inspectedValue = inspect(value);
throw new CommonQueryRunnerException(
`Invalid value ${inspectedValue} for date field "${fieldName}". Expected format: 'YYYY-MM-DD'`,
CommonQueryRunnerExceptionCode.INVALID_ARGS_DATA,
{
userFriendlyMessage: msg`Invalid value for date: "${inspectedValue}". Expected format: 'YYYY-MM-DD'`,
},
);
};
@@ -0,0 +1,72 @@
import { inspect } from 'util';
import { msg } from '@lingui/core/macro';
import { isDate, isNull, isString } from '@sniptt/guards';
import { isValid, parse } from 'date-fns';
import {
CommonQueryRunnerException,
CommonQueryRunnerExceptionCode,
} from 'src/engine/api/common/common-query-runners/errors/common-query-runner.exception';
const ACCEPTED_DATE_TIME_FORMATS = [
"yyyy-MM-dd'T'HH:mm:ss.SSSX",
"yyyy-MM-dd'T'HH:mm:ssX",
"yyyy-MM-dd'T'HH:mm:ss.SSSxxx",
"yyyy-MM-dd'T'HH:mm:ssxxx",
"yyyy-MM-dd'T'HH:mm:ss.SSS",
"yyyy-MM-dd'T'HH:mm:ss",
'yyyy-MM-dd HH:mm:ss.SSS',
'yyyy-MM-dd HH:mm:ss',
'yyyy-MM-dd HH:mm',
'yyyy-MM-dd',
'yyyyMMdd',
'yyyy.MM.dd',
'yyyy/MM/dd',
'MM-dd-yyyy',
'MM/dd/yyyy',
'MM.dd.yyyy',
'MMMM d, yyyy',
'MMM d, yyyy',
'd MMMM yyyy',
'd MMM yyyy',
'dd-MMM-yyyy',
'yyyy-MMM-dd',
];
const isValidDateTimeFormat = (value: string): boolean => {
for (const format of ACCEPTED_DATE_TIME_FORMATS) {
const parsed = parse(value, format, new Date());
if (isValid(parsed)) {
return true;
}
}
return false;
};
export const validateDateTimeFieldOrThrow = (
value: unknown,
fieldName: string,
): unknown => {
if (isNull(value)) return null;
if (isDate(value) && isValid(value)) {
return value;
}
if (isString(value) && isValidDateTimeFormat(value)) {
return value;
}
const inspectedValue = inspect(value);
throw new CommonQueryRunnerException(
`Invalid value ${inspectedValue} for date-time field "${fieldName}". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'`,
CommonQueryRunnerExceptionCode.INVALID_ARGS_DATA,
{
userFriendlyMessage: msg`Invalid value for date-time: "${inspectedValue}". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'`,
},
);
};
@@ -1,21 +1,5 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - DATE Gql create input - failure DATE - should fail with : {"dateField":"malformed-date"} 1`] = `"Invalid value 'malformed-date' for date or date-time field "dateField""`;
exports[`Create input validation - DATE Gql create input - failure DATE - should fail with : {"dateField":"malformed-date"} 1`] = `"Invalid value 'malformed-date' for date field "dateField". Expected format: 'YYYY-MM-DD'"`;
exports[`Create input validation - DATE Gql create input - failure DATE - should fail with : {"dateField":[]} 1`] = `"Invalid value [] for date or date-time field "dateField""`;
exports[`Create input validation - DATE Gql create input - failure DATE - should fail with : {"dateField":{}} 1`] = `"Invalid value {} for date or date-time field "dateField""`;
exports[`Create input validation - DATE Gql create input - failure DATE - should fail with : {"dateField":1} 1`] = `"Data validation error."`;
exports[`Create input validation - DATE Gql create input - failure DATE - should fail with : {"dateField":true} 1`] = `"Invalid value true for date or date-time field "dateField""`;
exports[`Create input validation - DATE Rest create input - failure DATE - should fail with : {"dateField":"malformed-date"} 1`] = `"["Invalid value 'malformed-date' for date or date-time field \\"dateField\\""]"`;
exports[`Create input validation - DATE Rest create input - failure DATE - should fail with : {"dateField":[]} 1`] = `"["Invalid value [] for date or date-time field \\"dateField\\""]"`;
exports[`Create input validation - DATE Rest create input - failure DATE - should fail with : {"dateField":{}} 1`] = `"["Invalid value {} for date or date-time field \\"dateField\\""]"`;
exports[`Create input validation - DATE Rest create input - failure DATE - should fail with : {"dateField":1} 1`] = `"["Data validation error."]"`;
exports[`Create input validation - DATE Rest create input - failure DATE - should fail with : {"dateField":true} 1`] = `"["Invalid value true for date or date-time field \\"dateField\\""]"`;
exports[`Create input validation - DATE Rest create input - failure DATE - should fail with : {"dateField":"malformed-date"} 1`] = `"["Invalid value 'malformed-date' for date field \\"dateField\\". Expected format: 'YYYY-MM-DD'"]"`;
@@ -1,21 +1,5 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - DATE_TIME Gql create input - failure DATE_TIME - should fail with : {"dateTimeField":"malformed-date"} 1`] = `"Invalid value 'malformed-date' for date or date-time field "dateTimeField""`;
exports[`Create input validation - DATE_TIME Gql create input - failure DATE_TIME - should fail with : {"dateTimeField":"malformed-date-time"} 1`] = `"Invalid value 'malformed-date-time' for date-time field "dateTimeField". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'"`;
exports[`Create input validation - DATE_TIME Gql create input - failure DATE_TIME - should fail with : {"dateTimeField":[]} 1`] = `"Invalid value [] for date or date-time field "dateTimeField""`;
exports[`Create input validation - DATE_TIME Gql create input - failure DATE_TIME - should fail with : {"dateTimeField":{}} 1`] = `"Invalid value {} for date or date-time field "dateTimeField""`;
exports[`Create input validation - DATE_TIME Gql create input - failure DATE_TIME - should fail with : {"dateTimeField":1} 1`] = `"Invalid DATE_TIME field "dateTimeField", value: "1", it should be a string, Date instance or plain object, (current type : number)."`;
exports[`Create input validation - DATE_TIME Gql create input - failure DATE_TIME - should fail with : {"dateTimeField":true} 1`] = `"Invalid value true for date or date-time field "dateTimeField""`;
exports[`Create input validation - DATE_TIME Rest create input - failure DATE_TIME - should fail with : {"dateTimeField":"malformed-date"} 1`] = `"["Invalid value 'malformed-date' for date or date-time field \\"dateTimeField\\""]"`;
exports[`Create input validation - DATE_TIME Rest create input - failure DATE_TIME - should fail with : {"dateTimeField":[]} 1`] = `"["Invalid value [] for date or date-time field \\"dateTimeField\\""]"`;
exports[`Create input validation - DATE_TIME Rest create input - failure DATE_TIME - should fail with : {"dateTimeField":{}} 1`] = `"["Invalid value {} for date or date-time field \\"dateTimeField\\""]"`;
exports[`Create input validation - DATE_TIME Rest create input - failure DATE_TIME - should fail with : {"dateTimeField":1} 1`] = `"["Invalid DATE_TIME field \\"dateTimeField\\", value: \\"1\\", it should be a string, Date instance or plain object, (current type : number)."]"`;
exports[`Create input validation - DATE_TIME Rest create input - failure DATE_TIME - should fail with : {"dateTimeField":true} 1`] = `"["Invalid value true for date or date-time field \\"dateTimeField\\""]"`;
exports[`Create input validation - DATE_TIME Rest create input - failure DATE_TIME - should fail with : {"dateTimeField":"malformed-date-time"} 1`] = `"["Invalid value 'malformed-date-time' for date-time field \\"dateTimeField\\". Expected format: 'YYYY-MM-DDTHH:mm:ssZ'"]"`;
@@ -2,16 +2,4 @@
exports[`Create input validation - MULTI_SELECT Gql create input - failure MULTI_SELECT - should fail with : {"multiSelectField":"not-a-select-option"} 1`] = `"Value "not-a-select-option" does not exist in "ApiInputValidationTestObjectMultiSelectFieldEnum" enum."`;
exports[`Create input validation - MULTI_SELECT Gql create input - failure MULTI_SELECT - should fail with : {"multiSelectField":{}} 1`] = `"Enum "ApiInputValidationTestObjectMultiSelectFieldEnum" cannot represent non-string value: {}."`;
exports[`Create input validation - MULTI_SELECT Gql create input - failure MULTI_SELECT - should fail with : {"multiSelectField":1} 1`] = `"Enum "ApiInputValidationTestObjectMultiSelectFieldEnum" cannot represent non-string value: 1."`;
exports[`Create input validation - MULTI_SELECT Gql create input - failure MULTI_SELECT - should fail with : {"multiSelectField":true} 1`] = `"Enum "ApiInputValidationTestObjectMultiSelectFieldEnum" cannot represent non-string value: true."`;
exports[`Create input validation - MULTI_SELECT Rest create input - failure MULTI_SELECT - should fail with : {"multiSelectField":"not-a-select-option"} 1`] = `"["Invalid value 'not-a-select-option' for multi select field \\"multiSelectField\\""]"`;
exports[`Create input validation - MULTI_SELECT Rest create input - failure MULTI_SELECT - should fail with : {"multiSelectField":{}} 1`] = `"["Invalid value {} for field \\"multiSelectField - Array values need to be string\\""]"`;
exports[`Create input validation - MULTI_SELECT Rest create input - failure MULTI_SELECT - should fail with : {"multiSelectField":1} 1`] = `"["Invalid value 1 for field \\"multiSelectField - Array values need to be string\\""]"`;
exports[`Create input validation - MULTI_SELECT Rest create input - failure MULTI_SELECT - should fail with : {"multiSelectField":true} 1`] = `"["Invalid value true for field \\"multiSelectField - Array values need to be string\\""]"`;
@@ -2,16 +2,4 @@
exports[`Create input validation - NUMBER Gql create input - failure NUMBER - should fail with : {"numberField":"string"} 1`] = `"Float cannot represent non numeric value: "string""`;
exports[`Create input validation - NUMBER Gql create input - failure NUMBER - should fail with : {"numberField":[]} 1`] = `"Float cannot represent non numeric value: []"`;
exports[`Create input validation - NUMBER Gql create input - failure NUMBER - should fail with : {"numberField":{}} 1`] = `"Float cannot represent non numeric value: {}"`;
exports[`Create input validation - NUMBER Gql create input - failure NUMBER - should fail with : {"numberField":true} 1`] = `"Float cannot represent non numeric value: true"`;
exports[`Create input validation - NUMBER Rest create input - failure NUMBER - should fail with : {"numberField":"string"} 1`] = `"["Invalid number value 'string' for field \\"numberField\\""]"`;
exports[`Create input validation - NUMBER Rest create input - failure NUMBER - should fail with : {"numberField":[]} 1`] = `"["Invalid number value [] for field \\"numberField\\""]"`;
exports[`Create input validation - NUMBER Rest create input - failure NUMBER - should fail with : {"numberField":{}} 1`] = `"["Invalid number value {} for field \\"numberField\\""]"`;
exports[`Create input validation - NUMBER Rest create input - failure NUMBER - should fail with : {"numberField":true} 1`] = `"["Invalid number value true for field \\"numberField\\""]"`;
@@ -2,20 +2,4 @@
exports[`Create input validation - RATING Gql create input - failure RATING - should fail with : {"ratingField":"not-a-rating"} 1`] = `"Value "not-a-rating" does not exist in "ApiInputValidationTestObjectRatingFieldEnum" enum."`;
exports[`Create input validation - RATING Gql create input - failure RATING - should fail with : {"ratingField":[]} 1`] = `"Enum "ApiInputValidationTestObjectRatingFieldEnum" cannot represent non-string value: []."`;
exports[`Create input validation - RATING Gql create input - failure RATING - should fail with : {"ratingField":{}} 1`] = `"Enum "ApiInputValidationTestObjectRatingFieldEnum" cannot represent non-string value: {}."`;
exports[`Create input validation - RATING Gql create input - failure RATING - should fail with : {"ratingField":1} 1`] = `"Enum "ApiInputValidationTestObjectRatingFieldEnum" cannot represent non-string value: 1."`;
exports[`Create input validation - RATING Gql create input - failure RATING - should fail with : {"ratingField":true} 1`] = `"Enum "ApiInputValidationTestObjectRatingFieldEnum" cannot represent non-string value: true."`;
exports[`Create input validation - RATING Rest create input - failure RATING - should fail with : {"ratingField":"not-a-rating"} 1`] = `"["Invalid value 'not-a-rating' for field \\"ratingField\\""]"`;
exports[`Create input validation - RATING Rest create input - failure RATING - should fail with : {"ratingField":[]} 1`] = `"["Invalid string value [] for text field \\"ratingField\\""]"`;
exports[`Create input validation - RATING Rest create input - failure RATING - should fail with : {"ratingField":{}} 1`] = `"["Invalid string value {} for text field \\"ratingField\\""]"`;
exports[`Create input validation - RATING Rest create input - failure RATING - should fail with : {"ratingField":1} 1`] = `"["Invalid string value 1 for text field \\"ratingField\\""]"`;
exports[`Create input validation - RATING Rest create input - failure RATING - should fail with : {"ratingField":true} 1`] = `"["Invalid string value true for text field \\"ratingField\\""]"`;
@@ -2,28 +2,12 @@
exports[`Create input validation - RELATION Gql create input - failure RELATION - should fail with : {"manyToOneRelationFieldId":"non-uuid"} 1`] = `"Invalid UUID value 'non-uuid' for field "manyToOneRelationFieldId""`;
exports[`Create input validation - RELATION Gql create input - failure RELATION - should fail with : {"manyToOneRelationFieldId":[]} 1`] = `"ID cannot represent value: []"`;
exports[`Create input validation - RELATION Gql create input - failure RELATION - should fail with : {"manyToOneRelationFieldId":{}} 1`] = `"ID cannot represent value: {}"`;
exports[`Create input validation - RELATION Gql create input - failure RELATION - should fail with : {"manyToOneRelationFieldId":1} 1`] = `"Invalid UUID value '1' for field "manyToOneRelationFieldId""`;
exports[`Create input validation - RELATION Gql create input - failure RELATION - should fail with : {"manyToOneRelationFieldId":true} 1`] = `"ID cannot represent value: true"`;
exports[`Create input validation - RELATION Gql create input - failure RELATION - should fail with : {"oneToManyRelationFieldId":"not-existing-field"} 1`] = `"Field "oneToManyRelationFieldId" is not defined by type "ApiInputValidationTestObjectCreateInput". Did you mean "manyToOneRelationFieldId" or "manyToOneRelationField"?"`;
exports[`Create input validation - RELATION Gql create input - failure RELATION - should fail with : {"oneToOneRelationField":"not-existing-field"} 1`] = `"Field "oneToOneRelationField" is not defined by type "ApiInputValidationTestObjectCreateInput". Did you mean "manyToOneRelationField" or "manyToOneRelationFieldId"?"`;
exports[`Create input validation - RELATION Rest create input - failure RELATION - should fail with : {"manyToOneRelationFieldId":"non-uuid"} 1`] = `"["Invalid UUID value 'non-uuid' for field \\"manyToOneRelationFieldId\\""]"`;
exports[`Create input validation - RELATION Rest create input - failure RELATION - should fail with : {"manyToOneRelationFieldId":[]} 1`] = `"["Invalid UUID value [] for field \\"manyToOneRelationFieldId\\""]"`;
exports[`Create input validation - RELATION Rest create input - failure RELATION - should fail with : {"manyToOneRelationFieldId":{}} 1`] = `"["Invalid UUID value {} for field \\"manyToOneRelationFieldId\\""]"`;
exports[`Create input validation - RELATION Rest create input - failure RELATION - should fail with : {"manyToOneRelationFieldId":1} 1`] = `"["Invalid UUID value 1 for field \\"manyToOneRelationFieldId\\""]"`;
exports[`Create input validation - RELATION Rest create input - failure RELATION - should fail with : {"manyToOneRelationFieldId":true} 1`] = `"["Invalid UUID value true for field \\"manyToOneRelationFieldId\\""]"`;
exports[`Create input validation - RELATION Rest create input - failure RELATION - should fail with : {"oneToManyRelationFieldId":"not-existing-field"} 1`] = `"["Object apiInputValidationTestObject doesn't have any \\"oneToManyRelationFieldId\\" field."]"`;
exports[`Create input validation - RELATION Rest create input - failure RELATION - should fail with : {"oneToOneRelationField":"not-existing-field"} 1`] = `"["Object apiInputValidationTestObject doesn't have any \\"oneToOneRelationField\\" field."]"`;
@@ -2,20 +2,8 @@
exports[`Create input validation - SELECT Gql create input - failure SELECT - should fail with : {"selectField":"not-a-select-option"} 1`] = `"Value "not-a-select-option" does not exist in "ApiInputValidationTestObjectSelectFieldEnum" enum."`;
exports[`Create input validation - SELECT Gql create input - failure SELECT - should fail with : {"selectField":[]} 1`] = `"Enum "ApiInputValidationTestObjectSelectFieldEnum" cannot represent non-string value: []."`;
exports[`Create input validation - SELECT Gql create input - failure SELECT - should fail with : {"selectField":{}} 1`] = `"Enum "ApiInputValidationTestObjectSelectFieldEnum" cannot represent non-string value: {}."`;
exports[`Create input validation - SELECT Gql create input - failure SELECT - should fail with : {"selectField":1} 1`] = `"Enum "ApiInputValidationTestObjectSelectFieldEnum" cannot represent non-string value: 1."`;
exports[`Create input validation - SELECT Gql create input - failure SELECT - should fail with : {"selectField":true} 1`] = `"Enum "ApiInputValidationTestObjectSelectFieldEnum" cannot represent non-string value: true."`;
exports[`Create input validation - SELECT Rest create input - failure SELECT - should fail with : {"selectField":"not-a-select-option"} 1`] = `"["Invalid value 'not-a-select-option' for field \\"selectField\\""]"`;
exports[`Create input validation - SELECT Rest create input - failure SELECT - should fail with : {"selectField":[]} 1`] = `"["Invalid string value [] for text field \\"selectField\\""]"`;
exports[`Create input validation - SELECT Rest create input - failure SELECT - should fail with : {"selectField":{}} 1`] = `"["Invalid string value {} for text field \\"selectField\\""]"`;
exports[`Create input validation - SELECT Rest create input - failure SELECT - should fail with : {"selectField":1} 1`] = `"["Invalid string value 1 for text field \\"selectField\\""]"`;
exports[`Create input validation - SELECT Rest create input - failure SELECT - should fail with : {"selectField":true} 1`] = `"["Invalid string value true for text field \\"selectField\\""]"`;
@@ -1,17 +1,5 @@
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Create input validation - TEXT Gql create input - failure TEXT - should fail with : {"textField":[]} 1`] = `"String cannot represent a non string value: []"`;
exports[`Create input validation - TEXT Gql create input - failure TEXT - should fail with : {"textField":{}} 1`] = `"String cannot represent a non string value: {}"`;
exports[`Create input validation - TEXT Gql create input - failure TEXT - should fail with : {"textField":1} 1`] = `"String cannot represent a non string value: 1"`;
exports[`Create input validation - TEXT Gql create input - failure TEXT - should fail with : {"textField":true} 1`] = `"String cannot represent a non string value: true"`;
exports[`Create input validation - TEXT Rest create input - failure TEXT - should fail with : {"textField":[]} 1`] = `"["Invalid string value [] for text field \\"textField\\""]"`;
exports[`Create input validation - TEXT Rest create input - failure TEXT - should fail with : {"textField":{}} 1`] = `"["Invalid string value {} for text field \\"textField\\""]"`;
exports[`Create input validation - TEXT Rest create input - failure TEXT - should fail with : {"textField":1} 1`] = `"["Invalid string value 1 for text field \\"textField\\""]"`;
exports[`Create input validation - TEXT Rest create input - failure TEXT - should fail with : {"textField":true} 1`] = `"["Invalid string value true for text field \\"textField\\""]"`;
@@ -2,20 +2,4 @@
exports[`Create input validation - UUID Gql create input - failure UUID - should fail with : {"uuidField":"non-uuid"} 1`] = `"Invalid UUID"`;
exports[`Create input validation - UUID Gql create input - failure UUID - should fail with : {"uuidField":[]} 1`] = `"UUID must be a string"`;
exports[`Create input validation - UUID Gql create input - failure UUID - should fail with : {"uuidField":{}} 1`] = `"UUID must be a string"`;
exports[`Create input validation - UUID Gql create input - failure UUID - should fail with : {"uuidField":1} 1`] = `"UUID must be a string"`;
exports[`Create input validation - UUID Gql create input - failure UUID - should fail with : {"uuidField":true} 1`] = `"UUID must be a string"`;
exports[`Create input validation - UUID Rest create input - failure UUID - should fail with : {"uuidField":"non-uuid"} 1`] = `"["Invalid UUID value 'non-uuid' for field \\"uuidField\\""]"`;
exports[`Create input validation - UUID Rest create input - failure UUID - should fail with : {"uuidField":[]} 1`] = `"["Invalid UUID value [] for field \\"uuidField\\""]"`;
exports[`Create input validation - UUID Rest create input - failure UUID - should fail with : {"uuidField":{}} 1`] = `"["Invalid UUID value {} for field \\"uuidField\\""]"`;
exports[`Create input validation - UUID Rest create input - failure UUID - should fail with : {"uuidField":1} 1`] = `"["Invalid UUID value 1 for field \\"uuidField\\""]"`;
exports[`Create input validation - UUID Rest create input - failure UUID - should fail with : {"uuidField":true} 1`] = `"["Invalid UUID value true for field \\"uuidField\\""]"`;
@@ -8,21 +8,6 @@ export const failingCreateInputByFieldMetadataType: {
}[];
} = {
[FieldMetadataType.TEXT]: [
{
input: {
textField: {},
},
},
{
input: {
textField: [],
},
},
{
input: {
textField: true,
},
},
{
input: {
textField: 1,
@@ -30,21 +15,6 @@ export const failingCreateInputByFieldMetadataType: {
},
],
[FieldMetadataType.NUMBER]: [
{
input: {
numberField: {},
},
},
{
input: {
numberField: [],
},
},
{
input: {
numberField: true,
},
},
{
input: {
numberField: 'string',
@@ -52,26 +22,6 @@ export const failingCreateInputByFieldMetadataType: {
},
],
[FieldMetadataType.UUID]: [
{
input: {
uuidField: {},
},
},
{
input: {
uuidField: [],
},
},
{
input: {
uuidField: true,
},
},
{
input: {
uuidField: 1,
},
},
{
input: {
uuidField: 'non-uuid',
@@ -84,21 +34,6 @@ export const failingCreateInputByFieldMetadataType: {
selectField: 'not-a-select-option',
},
},
{
input: {
selectField: {},
},
},
{
input: {
selectField: [],
},
},
{
input: {
selectField: true,
},
},
{
input: {
selectField: 1,
@@ -106,26 +41,6 @@ export const failingCreateInputByFieldMetadataType: {
},
],
[FieldMetadataType.RELATION]: [
{
input: {
manyToOneRelationFieldId: {},
},
},
{
input: {
manyToOneRelationFieldId: [],
},
},
{
input: {
manyToOneRelationFieldId: true,
},
},
{
input: {
manyToOneRelationFieldId: 1,
},
},
{
input: {
manyToOneRelationFieldId: 'non-uuid',
@@ -194,26 +109,6 @@ export const failingCreateInputByFieldMetadataType: {
ratingField: 'not-a-rating',
},
},
{
input: {
ratingField: {},
},
},
{
input: {
ratingField: [],
},
},
{
input: {
ratingField: true,
},
},
{
input: {
ratingField: 1,
},
},
],
[FieldMetadataType.MULTI_SELECT]: [
{
@@ -221,21 +116,6 @@ export const failingCreateInputByFieldMetadataType: {
multiSelectField: 'not-a-select-option',
},
},
{
input: {
multiSelectField: {},
},
},
{
input: {
multiSelectField: true,
},
},
{
input: {
multiSelectField: 1,
},
},
],
[FieldMetadataType.DATE]: [
{
@@ -243,75 +123,15 @@ export const failingCreateInputByFieldMetadataType: {
dateField: 'malformed-date',
},
},
{
input: {
dateField: {},
},
},
{
input: {
dateField: [],
},
},
{
input: {
dateField: true,
},
},
{
input: {
dateField: 1,
},
},
],
[FieldMetadataType.DATE_TIME]: [
{
input: {
dateTimeField: 'malformed-date',
},
},
{
input: {
dateTimeField: {},
},
},
{
input: {
dateTimeField: [],
},
},
{
input: {
dateTimeField: true,
},
},
{
input: {
dateTimeField: 1,
dateTimeField: 'malformed-date-time',
},
},
],
[FieldMetadataType.BOOLEAN]: [
{
input: {
booleanField: null,
},
},
{
input: {
booleanField: {},
},
},
{
input: {
booleanField: [],
},
},
{
input: {
booleanField: 'string',
},
},
{
input: {
booleanField: 1,
@@ -23,14 +23,6 @@ export const successfulCreateInputByFieldMetadataType: {
return record.textField === 'test';
},
},
{
input: {
textField: '',
},
validateInput: (record: Record<string, any>) => {
return record.textField === '';
},
},
],
[FieldMetadataType.NUMBER]: [
{
@@ -41,30 +33,6 @@ export const successfulCreateInputByFieldMetadataType: {
return record.numberField === 1;
},
},
{
input: {
numberField: null,
},
validateInput: (record: Record<string, any>) => {
return record.numberField === null;
},
},
{
input: {
numberField: 0,
},
validateInput: (record: Record<string, any>) => {
return record.numberField === 0;
},
},
{
input: {
numberField: -1.1,
},
validateInput: (record: Record<string, any>) => {
return record.numberField === -1.1;
},
},
],
[FieldMetadataType.UUID]: [
{
@@ -75,14 +43,6 @@ export const successfulCreateInputByFieldMetadataType: {
return record.uuidField === '00000000-0000-4000-8000-000000000000';
},
},
{
input: {
uuidField: null,
},
validateInput: (record: Record<string, any>) => {
return record.uuidField === null;
},
},
],
[FieldMetadataType.SELECT]: [
{
@@ -162,22 +122,6 @@ export const successfulCreateInputByFieldMetadataType: {
return record.rawJsonField === null;
},
},
{
input: {
rawJsonField: null,
},
validateInput: (record: Record<string, any>) => {
return record.rawJsonField === null;
},
},
{
input: {
rawJsonField: '{"key": "value"}',
},
validateInput: (record: Record<string, any>) => {
return record.rawJsonField.key === 'value';
},
},
],
[FieldMetadataType.ARRAY]: [
{
@@ -202,26 +146,6 @@ export const successfulCreateInputByFieldMetadataType: {
);
},
},
{
input: {
arrayField: [],
},
validateInput: (record: Record<string, any>) => {
return (
Array.isArray(record.arrayField) && record.arrayField.length === 0
);
},
},
{
input: {
arrayField: null,
},
validateInput: (record: Record<string, any>) => {
return (
Array.isArray(record.arrayField) && record.arrayField.length === 0
);
},
},
],
[FieldMetadataType.RATING]: [
{
@@ -232,14 +156,6 @@ export const successfulCreateInputByFieldMetadataType: {
return record.ratingField === 'RATING_2';
},
},
{
input: {
ratingField: null,
},
validateInput: (record: Record<string, any>) => {
return record.ratingField === null;
},
},
],
[FieldMetadataType.MULTI_SELECT]: [
{
@@ -277,14 +193,6 @@ export const successfulCreateInputByFieldMetadataType: {
},
],
[FieldMetadataType.DATE]: [
{
input: {
dateField: '2025-01-13',
},
validateInput: (record: Record<string, any>) => {
return new Date(record.dateField).toDateString() === 'Mon Jan 13 2025';
},
},
{
input: {
dateField: null,
@@ -293,30 +201,32 @@ export const successfulCreateInputByFieldMetadataType: {
return record.dateField === null;
},
},
{
input: {
dateField: '2025-01-13',
},
validateInput: (record: Record<string, any>) => {
return new Date(record.dateField).toDateString() === 'Mon Jan 13 2025';
},
},
],
[FieldMetadataType.DATE_TIME]: [
{
input: {
dateTimeField: '2025-01-13 00:00:00',
dateTimeField: '2025-01-13T10:30:00.000Z',
},
validateInput: (record: Record<string, any>) => {
const date = new Date(record.dateTimeField);
return (
date.toDateString() === 'Mon Jan 13 2025' &&
date.getMinutes() === 0 &&
date.getSeconds() === 0
date.getUTCHours() === 10 &&
date.getUTCMinutes() === 30 &&
date.getUTCSeconds() === 0 &&
date.getUTCMilliseconds() === 0
);
},
},
{
input: {
dateTimeField: null,
},
validateInput: (record: Record<string, any>) => {
return record.dateTimeField === null;
},
},
],
[FieldMetadataType.BOOLEAN]: [
{