From ffcb476b1760471793edcffc3eb53fe66b8d6048 Mon Sep 17 00:00:00 2001 From: Pagan Gazzard Date: Tue, 5 May 2020 16:48:42 +0100 Subject: [PATCH] Add 'Date Time Range' type Change-type: minor --- Type.sbvr | 1 + src/index.ts | 2 ++ src/types/date-time-range.ts | 58 +++++++++++++++++++++++++++++++++ test/Date Time Range.coffee | 62 ++++++++++++++++++++++++++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 src/types/date-time-range.ts create mode 100644 test/Date Time Range.coffee diff --git a/Type.sbvr b/Type.sbvr index 11d7151..99dec7e 100644 --- a/Type.sbvr +++ b/Type.sbvr @@ -4,6 +4,7 @@ Term: Real Term: Text Term: Date Term: Date Time +Term: Date Time Range Term: Time Term: Interval Term: File diff --git a/src/index.ts b/src/index.ts index d5e16b9..8d9ec0f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,7 @@ import * as Color from './types/color'; import * as ConceptType from './types/concept-type'; import * as Date from './types/date'; import * as DateTime from './types/date-time'; +import * as DateTimeRange from './types/date-time-range'; import * as File from './types/file'; import * as ForeignKey from './types/foreign-key'; import * as Hashed from './types/hashed'; @@ -40,6 +41,7 @@ export = { Color, ConceptType, 'Date Time': DateTime, + 'Date Time Range': DateTimeRange, Date, File, ForeignKey, diff --git a/src/types/date-time-range.ts b/src/types/date-time-range.ts new file mode 100644 index 0000000..7fa483e --- /dev/null +++ b/src/types/date-time-range.ts @@ -0,0 +1,58 @@ +import * as TypeUtils from '../type-utils'; + +export const types = { + postgres: 'TSRANGE', + mysql: 'TEXT', + websql: 'TEXT', + odata: { + name: 'Edm.String', + }, +}; + +export interface TSRange { + lowerInclusive: boolean; + lowerDate?: Date; + upperDate?: Date; + upperInclusive: boolean; +} + +const regex = /(\[|\()(?:"((?:\\"|[^"])*)"|[^"]*),(?:"((?:\\"|[^"])*)"|[^"]*)(\]|\))/; + +export async function fetchProcessing(data: null | undefined): Promise; +export async function fetchProcessing(data: any): Promise; +export async function fetchProcessing(data: any): Promise { + if (data == null) { + return data; + } + + const match = regex.exec(data); + if (!match) { + throw new Error(`Invalid date time range: '${data}`); + } + + const [, lowerBound, lowerDate, upperDate, upperBound] = match; + return { + lowerInclusive: lowerBound === '[', + lowerDate: lowerDate == null ? undefined : new Date(lowerDate), + upperDate: upperDate == null ? undefined : new Date(upperDate), + upperInclusive: upperBound === ']', + }; +} + +export const validate = TypeUtils.validate.checkRequired(async value => { + let rangeObj: TSRange; + if (value == null) { + rangeObj = value; + } else if (typeof value === 'string') { + rangeObj = await fetchProcessing(value); + } else if (typeof value === 'object') { + rangeObj = value; + } else { + throw new Error('is neither a string or date time range object: ' + value); + } + const lowerBound = rangeObj.lowerInclusive ? '[' : '('; + const upperBound = rangeObj.upperInclusive ? ']' : ')'; + const lowerDate = rangeObj.lowerDate?.toISOString() ?? ''; + const upperDate = rangeObj.upperDate?.toISOString() ?? ''; + return `${lowerBound}"${lowerDate}","${upperDate}"${upperBound}`; +}); diff --git a/test/Date Time Range.coffee b/test/Date Time Range.coffee new file mode 100644 index 0000000..da4a7a2 --- /dev/null +++ b/test/Date Time Range.coffee @@ -0,0 +1,62 @@ +helpers = require './helpers' + +helpers.describe 'Date Time Range', (test) -> + describe 'fetchProcessing', -> + test.fetch('["2010-01-01 14:30:00","2010-01-01 15:30:00")', { + lowerInclusive: true, + lowerDate: new Date('2010-01-01 14:30:00'), + upperDate: new Date('2010-01-01 15:30:00'), + upperInclusive: false, + }) + test.fetch('("2010-01-01 14:30:00",]', { + lowerInclusive: false, + lowerDate: new Date('2010-01-01 14:30:00'), + upperDate: undefined, + upperInclusive: true, + }) + test.fetch('[,"2010-01-01 14:30:00"]', { + lowerInclusive: true, + lowerDate: undefined, + upperDate: new Date('2010-01-01 14:30:00'), + upperInclusive: true, + }) + test.validate('[2010-01-01T14:30:00.000Z,2010-01-01T15:30:00.000Z)', { + lowerInclusive: true, + lowerDate: new Date('2010-01-01 14:30:00'), + upperDate: new Date('2010-01-01 15:30:00'), + upperInclusive: false, + }) + + describe 'validate', -> + test.validate({ + lowerInclusive: true, + lowerDate: new Date('2010-01-01 14:30:00'), + upperDate: new Date('2010-01-01 15:30:00'), + upperInclusive: false, + }, true, '["2010-01-01T14:30:00.000Z","2010-01-01T15:30:00.000Z")') + test.validate({ + lowerInclusive: false, + lowerDate: new Date('2010-01-01 14:30:00'), + upperDate: undefined, + upperInclusive: true, + }, true, '("2010-01-01T14:30:00.000Z",]') + test.validate({ + lowerInclusive: true, + lowerDate: undefined, + upperDate: new Date('2010-01-01 14:30:00'), + upperInclusive: true, + }, true, '[,"2010-01-01T14:30:00.000Z"]') + # test.validate({ + # r: 0 + # g: 0 + # b: 0 + # a: 0 + # }, true, 0) + # test.validate({ + # r: 255 + # g: 255 + # b: 255 + # a: 255 + # }, true, -1) + # test.validate(0, true, 0) + # test.validate(-1, true, -1)