Skip to content

Commit

Permalink
chore: add range error validation for date types
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelSun90 committed Dec 1, 2023
1 parent 57998f2 commit 671c1d1
Show file tree
Hide file tree
Showing 7 changed files with 214 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/data-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export interface DataType {
generateTypeInfo(parameter: ParameterData, options: InternalConnectionOptions): Buffer;
generateParameterLength(parameter: ParameterData, options: InternalConnectionOptions): Buffer;
generateParameterData(parameter: ParameterData, options: InternalConnectionOptions): Generator<Buffer, void>;
validate(value: any, collation: Collation | undefined): any; // TODO: Refactor 'any' and replace with more specific type.
validate(value: any, collation: Collation | undefined, options?: InternalConnectionOptions): any; // TODO: Refactor 'any' and replace with more specific type.

hasTableName?: boolean;

Expand Down
22 changes: 20 additions & 2 deletions src/data-types/date.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { type DataType } from '../data-type';
import { ChronoUnit, LocalDate } from '@js-joda/core';
import { type InternalConnectionOptions } from '../connection';

import { Collation } from '../collation';

// globalDate is to be used for JavaScript's global 'Date' object to avoid name clashing with the 'Date' constant below
const globalDate = global.Date;
const EPOCH_DATE = LocalDate.ofYearDay(1, 1);
const NULL_LENGTH = Buffer.from([0x00]);
const DATA_LENGTH = Buffer.from([0x03]);

const MIN_DATE = new globalDate('January 1, 0001');
const MAX_DATE = new globalDate('December 31, 9999');

const Date: DataType = {
id: 0x28,
type: 'DATEN',
Expand Down Expand Up @@ -35,7 +41,7 @@ const Date: DataType = {

const value = parameter.value as any; // Temporary solution. Remove 'any' later.

let date;
let date: LocalDate;
if (options.useUTC) {
date = LocalDate.of(value.getUTCFullYear(), value.getUTCMonth() + 1, value.getUTCDate());
} else {
Expand All @@ -49,7 +55,7 @@ const Date: DataType = {
},

// TODO: value is technically of type 'unknown'.
validate: function(value): null | Date {
validate: function(value: any, collation: Collation | undefined, options: InternalConnectionOptions): null | Date {
if (value == null) {
return null;
}
Expand All @@ -58,6 +64,18 @@ const Date: DataType = {
value = new globalDate(globalDate.parse(value));
}

value = value as Date;

// TODO: check date range: January 1, 0001, through December 31, 9999
// : time range: 00:00:00 through 23:59:59.997
if (options && options.useUTC) {
value = new globalDate(value.toUTCString());

Check warning on line 72 in src/data-types/date.ts

View check run for this annotation

Codecov / codecov/patch

src/data-types/date.ts#L72

Added line #L72 was not covered by tests
}

if (value < MIN_DATE || value > MAX_DATE) {
throw new TypeError('Out of range.');
}

if (isNaN(value)) {
throw new TypeError('Invalid date.');
}
Expand Down
22 changes: 20 additions & 2 deletions src/data-types/datetime.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { type DataType } from '../data-type';
import DateTimeN from './datetimen';
import { ChronoUnit, LocalDate } from '@js-joda/core';
import { type InternalConnectionOptions } from '../connection';

import { Collation } from '../collation';

const EPOCH_DATE = LocalDate.ofYearDay(1900, 1);
const NULL_LENGTH = Buffer.from([0x00]);
const DATA_LENGTH = Buffer.from([0x08]);

const MIN_DATE = new Date('January 1, 1753');
const MAX_DATE = new Date('December 31, 9999');

const DateTime: DataType = {
id: 0x3D,
type: 'DATETIME',
Expand Down Expand Up @@ -34,7 +40,7 @@ const DateTime: DataType = {

const value = parameter.value as any; // Temporary solution. Remove 'any' later.

let date;
let date: LocalDate;
if (options.useUTC) {
date = LocalDate.of(value.getUTCFullYear(), value.getUTCMonth() + 1, value.getUTCDate());
} else {
Expand Down Expand Up @@ -72,7 +78,7 @@ const DateTime: DataType = {
},

// TODO: type 'any' needs to be revisited.
validate: function(value): null | number {
validate: function(value: any, collation: Collation | undefined, options: InternalConnectionOptions): null | number {
if (value == null) {
return null;
}
Expand All @@ -81,6 +87,18 @@ const DateTime: DataType = {
value = new Date(Date.parse(value));
}

value = value as Date;

// TODO: check date range: January 1, 1753, through December 31, 9999
// : time range: 00:00:00 through 23:59:59.997
if (options && options.useUTC) {
value = new Date(value.toUTCString());

Check warning on line 95 in src/data-types/datetime.ts

View check run for this annotation

Codecov / codecov/patch

src/data-types/datetime.ts#L95

Added line #L95 was not covered by tests
}

if (value < MIN_DATE || value > MAX_DATE) {
throw new TypeError('Out of range.');
}

if (isNaN(value)) {
throw new TypeError('Invalid date.');
}
Expand Down
22 changes: 20 additions & 2 deletions src/data-types/datetime2.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { type DataType } from '../data-type';
import { ChronoUnit, LocalDate } from '@js-joda/core';
import WritableTrackingBuffer from '../tracking-buffer/writable-tracking-buffer';
import { type InternalConnectionOptions } from '../connection';

import { Collation } from '../collation';

const EPOCH_DATE = LocalDate.ofYearDay(1, 1);
const NULL_LENGTH = Buffer.from([0x00]);

const MIN_DATE = new Date('January 1, 0001');
const MAX_DATE = new Date('December 31, 9999');

const DateTime2: DataType & { resolveScale: NonNullable<DataType['resolveScale']> } = {
id: 0x2A,
type: 'DATETIME2N',
Expand Down Expand Up @@ -64,7 +70,7 @@ const DateTime2: DataType & { resolveScale: NonNullable<DataType['resolveScale']
const buffer = new WritableTrackingBuffer(16);
scale = scale!;

let timestamp;
let timestamp: number;
if (options.useUTC) {
timestamp = ((value.getUTCHours() * 60 + value.getUTCMinutes()) * 60 + value.getUTCSeconds()) * 1000 + value.getUTCMilliseconds();
} else {
Expand Down Expand Up @@ -102,7 +108,7 @@ const DateTime2: DataType & { resolveScale: NonNullable<DataType['resolveScale']
yield buffer.data;
},

validate: function(value): null | number {
validate: function(value: any, collation: Collation | undefined, options: InternalConnectionOptions): null | number {
if (value == null) {
return null;
}
Expand All @@ -111,6 +117,18 @@ const DateTime2: DataType & { resolveScale: NonNullable<DataType['resolveScale']
value = new Date(Date.parse(value));
}

value = value as Date;

// TODO: check date range: January 1, 0001, through December 31, 9999
// : time range: 00:00:00 through 23:59:59.997
if (options && options.useUTC) {
value = new Date(value.toUTCString());

Check warning on line 125 in src/data-types/datetime2.ts

View check run for this annotation

Codecov / codecov/patch

src/data-types/datetime2.ts#L125

Added line #L125 was not covered by tests
}

if (value < MIN_DATE || value > MAX_DATE) {
throw new TypeError('Out of range.');
}

if (isNaN(value)) {
throw new TypeError('Invalid date.');
}
Expand Down
22 changes: 20 additions & 2 deletions src/data-types/datetimeoffset.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { type DataType } from '../data-type';
import { ChronoUnit, LocalDate } from '@js-joda/core';
import WritableTrackingBuffer from '../tracking-buffer/writable-tracking-buffer';
import { type InternalConnectionOptions } from '../connection';

import { Collation } from '../collation';

const EPOCH_DATE = LocalDate.ofYearDay(1, 1);
const NULL_LENGTH = Buffer.from([0x00]);

const MIN_DATE = new Date('January 1, 0001');
const MAX_DATE = new Date('December 31, 9999');

const DateTimeOffset: DataType & { resolveScale: NonNullable<DataType['resolveScale']> } = {
id: 0x2B,
type: 'DATETIMEOFFSETN',
Expand Down Expand Up @@ -62,7 +68,7 @@ const DateTimeOffset: DataType & { resolveScale: NonNullable<DataType['resolveSc
const buffer = new WritableTrackingBuffer(16);
scale = scale!;

let timestamp;
let timestamp: number;
timestamp = ((value.getUTCHours() * 60 + value.getUTCMinutes()) * 60 + value.getUTCSeconds()) * 1000 + value.getMilliseconds();
timestamp = timestamp * Math.pow(10, scale - 3);
timestamp += (value.nanosecondDelta != null ? value.nanosecondDelta : 0) * Math.pow(10, scale);
Expand Down Expand Up @@ -92,7 +98,7 @@ const DateTimeOffset: DataType & { resolveScale: NonNullable<DataType['resolveSc
buffer.writeInt16LE(offset);
yield buffer.data;
},
validate: function(value): null | number {
validate: function(value: any, collation: Collation | undefined, options: InternalConnectionOptions): null | number {
if (value == null) {
return null;
}
Expand All @@ -101,6 +107,18 @@ const DateTimeOffset: DataType & { resolveScale: NonNullable<DataType['resolveSc
value = new Date(Date.parse(value));
}

value = value as Date;

// TODO: check date range: January 1, 0001, through December 31, 9999
// : time range: 00:00:00 through 23:59:59.997
if (options && options.useUTC) {
value = new Date(value.toUTCString());

Check warning on line 115 in src/data-types/datetimeoffset.ts

View check run for this annotation

Codecov / codecov/patch

src/data-types/datetimeoffset.ts#L115

Added line #L115 was not covered by tests
}

if (value < MIN_DATE || value > MAX_DATE) {
throw new TypeError('Out of range.');
}

if (isNaN(value)) {
throw new TypeError('Invalid date.');
}
Expand Down
20 changes: 18 additions & 2 deletions src/data-types/smalldatetime.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { type DataType } from '../data-type';
import DateTimeN from './datetimen';
import { type InternalConnectionOptions } from '../connection';

import { Collation } from '../collation';

const EPOCH_DATE = new Date(1900, 0, 1);
const UTC_EPOCH_DATE = new Date(Date.UTC(1900, 0, 1));

const MIN_DATE = new Date(1900, 1, 1);
const MAX_DATE = new Date(2079, 5, 6, 23, 59, 59, 0);

const DATA_LENGTH = Buffer.from([0x04]);
const NULL_LENGTH = Buffer.from([0x00]);

Expand Down Expand Up @@ -35,7 +41,7 @@ const SmallDateTime: DataType = {

const buffer = Buffer.alloc(4);

let days, dstDiff, minutes;
let days: number, dstDiff: number, minutes: number;
if (options.useUTC) {
days = Math.floor((parameter.value.getTime() - UTC_EPOCH_DATE.getTime()) / (1000 * 60 * 60 * 24));
minutes = (parameter.value.getUTCHours() * 60) + parameter.value.getUTCMinutes();
Expand All @@ -51,7 +57,7 @@ const SmallDateTime: DataType = {
yield buffer;
},

validate: function(value): null | Date {
validate: function(value, collation: Collation | undefined, options: InternalConnectionOptions): null | Date {
if (value == null) {
return null;
}
Expand All @@ -60,6 +66,16 @@ const SmallDateTime: DataType = {
value = new Date(Date.parse(value));
}

value = value as Date;

if (options && options.useUTC) {
value = new Date(value.toUTCString());

Check warning on line 72 in src/data-types/smalldatetime.ts

View check run for this annotation

Codecov / codecov/patch

src/data-types/smalldatetime.ts#L72

Added line #L72 was not covered by tests
}

if (value < MIN_DATE || value > MAX_DATE) {
throw new TypeError('Out of range.');
}

if (isNaN(value)) {
throw new TypeError('Invalid date.');
}
Expand Down
Loading

0 comments on commit 671c1d1

Please sign in to comment.