From c419c8592f16a002d9f460c555db5f8bc04d95b8 Mon Sep 17 00:00:00 2001 From: Elias Meire Date: Fri, 2 Feb 2024 11:27:31 +0100 Subject: [PATCH] fix: Allow Date/Luxon objects and additional formats in DateTime validation (#8525) --- packages/workflow/src/TypeValidation.ts | 16 ++++++++ .../workflow/test/FilterParameter.test.ts | 7 ++++ packages/workflow/test/TypeValidation.test.ts | 38 ++++++++++--------- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/packages/workflow/src/TypeValidation.ts b/packages/workflow/src/TypeValidation.ts index fb71825e93..cb3f294dfd 100644 --- a/packages/workflow/src/TypeValidation.ts +++ b/packages/workflow/src/TypeValidation.ts @@ -52,6 +52,17 @@ export const tryToParseBoolean = (value: unknown): value is boolean => { }; export const tryToParseDateTime = (value: unknown): DateTime => { + if (value instanceof DateTime && value.isValid) { + return value; + } + + if (value instanceof Date) { + const fromJSDate = DateTime.fromJSDate(value); + if (fromJSDate.isValid) { + return fromJSDate; + } + } + const dateString = String(value).trim(); // Rely on luxon to parse different date formats @@ -72,6 +83,11 @@ export const tryToParseDateTime = (value: unknown): DateTime => { return sqlDate; } + const parsedDateTime = DateTime.fromMillis(Date.parse(dateString)); + if (parsedDateTime.isValid) { + return parsedDateTime; + } + throw new ApplicationError('Value is not a valid date', { extra: { dateString } }); }; diff --git a/packages/workflow/test/FilterParameter.test.ts b/packages/workflow/test/FilterParameter.test.ts index 4b6e8e7f8a..37ffe4c57c 100644 --- a/packages/workflow/test/FilterParameter.test.ts +++ b/packages/workflow/test/FilterParameter.test.ts @@ -1,6 +1,7 @@ import { executeFilter } from '@/NodeParameters/FilterParameter'; import type { FilterConditionValue, FilterValue } from '@/Interfaces'; import merge from 'lodash/merge'; +import { DateTime } from 'luxon'; type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P]; @@ -676,6 +677,12 @@ describe('FilterParameter', () => { { left: '2023-11-15T17:10:49.113Z', right: '2023-11-15T17:10:49.113Z', expected: false }, { left: '2023-11-15T17:10:49.113Z', right: '2023-11-15T17:12:49.113Z', expected: false }, { left: '2023-11-15T17:10:49.113Z', right: '2023-01-01T00:00:00.000Z', expected: true }, + { left: '2024-01-01', right: new Date('2023-01-01T00:00:00.000Z'), expected: true }, + { + left: DateTime.fromFormat('2024-01-01', 'yyyy-MM-dd'), + right: '1-Feb-2024', + expected: false, + }, ])('dateTime:after("$left", "$right") === $expected', ({ left, right, expected }) => { const result = executeFilter( filterFactory({ diff --git a/packages/workflow/test/TypeValidation.test.ts b/packages/workflow/test/TypeValidation.test.ts index 9c26105b34..16467f06de 100644 --- a/packages/workflow/test/TypeValidation.test.ts +++ b/packages/workflow/test/TypeValidation.test.ts @@ -1,5 +1,5 @@ import { validateFieldType } from '@/TypeValidation'; -import type { DateTime } from 'luxon'; +import { DateTime } from 'luxon'; const VALID_ISO_DATES = [ '1994-11-05T08:15:30-05:00', @@ -30,12 +30,18 @@ const VALID_RFC_DATES = [ const VALID_SQL_DATES = ['2008-11-11', '2008-11-11 13:23:44']; +const OTHER_VALID_DATES = [ + 'Wed, 17 May 2023 10:52:32', + 'SMT, 17 May 2023 10:52:32', + '1-Feb-2024', + new Date(), + DateTime.now(), +]; + const INVALID_DATES = [ '1994-11-05M08:15:30-05:00', '18-05-2020', '', - 'Wed, 17 May 2023 10:52:32', - 'SMT, 17 May 2023 10:52:32', '1685084980', // We are not supporting timestamps '1685085012135', 1685084980, @@ -45,40 +51,38 @@ const INVALID_DATES = [ ]; describe('Type Validation', () => { - it('should validate and cast ISO dates', () => { - VALID_ISO_DATES.forEach((date) => { + describe('Dates', () => { + test.each(VALID_ISO_DATES)('should validate and cast ISO date "%s"', (date) => { const validationResult = validateFieldType('date', date, 'dateTime'); expect(validationResult.valid).toBe(true); expect((validationResult.newValue as DateTime).isValid).toBe(true); }); - }); - it('should validate and cast RFC 2822 dates', () => { - VALID_RFC_DATES.forEach((date) => { + test.each(VALID_RFC_DATES)('should validate and cast RFC2822 date "%s"', (date) => { const validationResult = validateFieldType('date', date, 'dateTime'); expect(validationResult.valid).toBe(true); expect((validationResult.newValue as DateTime).isValid).toBe(true); }); - }); - it('should validate and cast HTTP dates', () => { - VALID_HTTP_DATES.forEach((date) => { + test.each(VALID_HTTP_DATES)('should validate and cast HTTP date "%s"', (date) => { const validationResult = validateFieldType('date', date, 'dateTime'); expect(validationResult.valid).toBe(true); expect((validationResult.newValue as DateTime).isValid).toBe(true); }); - }); - it('should validate and cast SQL dates', () => { - VALID_SQL_DATES.forEach((date) => { + test.each(VALID_SQL_DATES)('should validate and cast SQL date "%s"', (date) => { const validationResult = validateFieldType('date', date, 'dateTime'); expect(validationResult.valid).toBe(true); expect((validationResult.newValue as DateTime).isValid).toBe(true); }); - }); - it('should not validate invalid dates', () => { - INVALID_DATES.forEach((date) => { + test.each(OTHER_VALID_DATES)('should validate and cast date "%s"', (date) => { + const validationResult = validateFieldType('date', date, 'dateTime'); + expect(validationResult.valid).toBe(true); + expect((validationResult.newValue as DateTime).isValid).toBe(true); + }); + + test.each(INVALID_DATES)('should not validate invalid date "%s"', (date) => { const validationResult = validateFieldType('date', date, 'dateTime'); expect(validationResult.valid).toBe(false); });