Skip to content

Commit

Permalink
fix: add missing IsDate serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
glebbash authored Jul 8, 2022
1 parent d7ae432 commit 07e033a
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 24 deletions.
70 changes: 69 additions & 1 deletion src/decorators/is-date.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Result } from 'true-myth';

import { input, make } from '../../tests/helpers';
import { generateSchemas, input, make, output } from '../../tests/helpers';
import { IsDate } from '../nestjs-swagger-dto';

describe('IsDate', () => {
Expand All @@ -10,6 +10,26 @@ describe('IsDate', () => {
date!: Date;
}

it('generates correct schema', async () => {
expect(await generateSchemas([Test])).toStrictEqual({
Test: {
type: 'object',
properties: {
date: {
type: 'string',
format: 'date',
},
},
required: ['date'],
},
});
});

it('transforms to plain', async () => {
const dto = make(Test, { date: new Date('2011-12-30') });
expect(output(dto)).toStrictEqual({ date: '2011-12-30' });
});

it('accepts date', async () => {
expect(await input(Test, { date: '2011-12-30' })).toStrictEqual(
Result.ok(make(Test, { date: new Date('2011-12-30') }))
Expand All @@ -28,6 +48,20 @@ describe('IsDate', () => {
expect(await input(Test, { date: '2011/12/02' })).toStrictEqual(
Result.err('date is not formatted as `yyyy-mm-dd`')
);

expect(await input(Test, {})).toStrictEqual(Result.err('date does not exist'));
});

it('works with optional fields', async () => {
class TestOptional {
@IsDate({ format: 'date', optional: true })
date?: Date;
}

const dto = make(TestOptional, {});
expect(output(dto)).toStrictEqual({});

expect(await input(Test, {})).toStrictEqual(Result.ok(make(TestOptional, {})));
});
});

Expand All @@ -37,6 +71,26 @@ describe('IsDate', () => {
date!: Date;
}

it('generates correct schema', async () => {
expect(await generateSchemas([Test])).toStrictEqual({
Test: {
type: 'object',
properties: {
date: {
type: 'string',
format: 'date-time',
},
},
required: ['date'],
},
});
});

it('transforms to plain', async () => {
const dto = make(Test, { date: new Date('2017-06-01T18:43:26.000Z') });
expect(output(dto)).toStrictEqual({ date: '2017-06-01T18:43:26.000Z' });
});

it('accepts date-time', async () => {
expect(await input(Test, { date: '2017-06-01T18:43:26.000Z' })).toStrictEqual(
Result.ok(make(Test, { date: new Date('2017-06-01T18:43:26.000Z') }))
Expand All @@ -55,6 +109,20 @@ describe('IsDate', () => {
expect(await input(Test, { date: '2011/12/02' })).toStrictEqual(
Result.err('date is not ISO8601 format')
);

expect(await input(Test, {})).toStrictEqual(Result.err('date does not exist'));
});

it('works with optional fields', async () => {
class TestOptional {
@IsDate({ format: 'date-time', optional: true })
date?: Date;
}

const dto = make(TestOptional, {});
expect(output(dto)).toStrictEqual({});

expect(await input(TestOptional, {})).toStrictEqual(Result.ok(make(TestOptional, {})));
});
});
});
68 changes: 45 additions & 23 deletions src/decorators/is-date.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Transform } from 'class-transformer';
import { Transform, TransformationType } from 'class-transformer';
import { IsDate as IsDateCV, isDateString } from 'class-validator';

import { compose, PropertyOptions } from '../core';

const crudeDateRegex = /^\d{4}-\d{2}-\d{2}$/;
const dateRegex = /^\d{4}-\d{2}-\d{2}$/;

// TODO: array support
export const IsDate = ({
Expand All @@ -13,25 +13,47 @@ export const IsDate = ({
compose(
{ type: 'string', format },
base,
format === 'date'
? Transform(({ key, value }) => {
if (!crudeDateRegex.test(value)) {
return new Error(`${key} is not formatted as \`yyyy-mm-dd\``);
}

const date = new Date(value);
if (isNaN(date.getTime())) {
return new Error(`${key} is not a valid Date`);
}

return date;
})
: Transform(({ key, value }) => {
if (!isDateString(value, { strict: true })) {
return new Error(`${key} is not ISO8601 format`);
}

return new Date(value);
}),
IsDateCV({ message: ({ value }) => value.message })
format === 'date' ? TransformDate : TransformDateTime,
IsDateCV({ message: ({ value }) => value?.message })
);

const TransformDate = Transform(({ key, value, type }) => {
if (value === undefined) {
return new Error(`${key} does not exist`);
}

if (type === TransformationType.CLASS_TO_PLAIN) {
return stripTime(value.toISOString());
}

if (!dateRegex.test(value)) {
return new Error(`${key} is not formatted as \`yyyy-mm-dd\``);
}

const date = new Date(value);
if (isNaN(date.getTime())) {
return new Error(`${key} is not a valid Date`);
}

return date;
});

const TransformDateTime = Transform(({ key, value, type }) => {
if (value === undefined) {
return new Error(`${key} does not exist`);
}

if (type === TransformationType.CLASS_TO_PLAIN) {
return value.toISOString();
}

if (!isDateString(value, { strict: true })) {
return new Error(`${key} is not ISO8601 format`);
}

return new Date(value);
});

function stripTime(isoDate: string) {
return isoDate.split('T')[0];
}

0 comments on commit 07e033a

Please sign in to comment.