Skip to content

Commit

Permalink
fix: handle defaults and examples for IsDate
Browse files Browse the repository at this point in the history
  • Loading branch information
glebbash committed Sep 19, 2022
1 parent b17a7d8 commit d8c3dd3
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 6 deletions.
79 changes: 79 additions & 0 deletions src/decorators/is-date.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,46 @@ describe('IsDate', () => {
Result.ok(make(TestNullable, { date: null }))
);
});

describe('with default value', () => {
const DEFAULT_DATE = new Date();
const DEFAULT_DATE_STR = DEFAULT_DATE.toISOString().split('T')[0];

class TestOptional {
@IsDate({
format: 'date',
optional: true,
example: [DEFAULT_DATE, DEFAULT_DATE],
default: DEFAULT_DATE,
})
date?: Date;
}

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

it('transforms to and from plain', async () => {
const dto = make(TestOptional, {});
expect(output(dto)).toStrictEqual({ date: DEFAULT_DATE_STR });

expect(await input(TestOptional, {})).toStrictEqual(
Result.ok(make(TestOptional, { date: new Date(DEFAULT_DATE_STR) }))
);
});
});
});

describe('single date-time', () => {
Expand Down Expand Up @@ -152,5 +192,44 @@ describe('IsDate', () => {
Result.ok(make(TestNullable, { date: null }))
);
});

describe('with default value', () => {
const DEFAULT_DATE = new Date();

class TestOptional {
@IsDate({
format: 'date-time',
optional: true,
example: DEFAULT_DATE,
default: DEFAULT_DATE,
})
date?: Date;
}

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

it('transforms to and from plain', async () => {
const dto = make(TestOptional, {});
expect(output(dto)).toStrictEqual({ date: DEFAULT_DATE.toISOString() });

expect(await input(TestOptional, {})).toStrictEqual(
Result.ok(make(TestOptional, { date: DEFAULT_DATE }))
);
});
});
});
});
48 changes: 42 additions & 6 deletions src/decorators/is-date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,27 @@ const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
// TODO: array support
export const IsDate = ({
format,
default: def,
example,
...base
}: Omit<PropertyOptions<Date, { format: 'date' | 'date-time' }>, 'isArray'>): PropertyDecorator =>
compose(
}: Omit<PropertyOptions<Date, { format: 'date' | 'date-time' }>, 'isArray'>): PropertyDecorator => {
const dateTime = format === 'date-time';

return compose(
{ type: 'string', format },
base,
TransformHandlingOptional(base, format === 'date' ? transformDate : transformDateTime),
{ ...base, default: stringify(def, dateTime), example: stringify(example, dateTime) },
TransformHandlingOptional(base, dateTime ? transformDateTime : transformDate),
IsDateCV({ message: ({ value }) => value?.message })
);
};

function transformDate({ key, value, type }: TransformFnParams) {
if (type === TransformationType.CLASS_TO_PLAIN) {
return value.toISOString().split('T')[0];
if (typeof value === 'string') {
return value;
}

return dateToString(value);
}

if (!dateRegex.test(value)) {
Expand All @@ -37,7 +46,11 @@ function transformDate({ key, value, type }: TransformFnParams) {

function transformDateTime({ key, value, type }: TransformFnParams) {
if (type === TransformationType.CLASS_TO_PLAIN) {
return value.toISOString();
if (typeof value === 'string') {
return value;
}

return dateTimeToString(value);
}

if (!isDateString(value, { strict: true })) {
Expand All @@ -46,3 +59,26 @@ function transformDateTime({ key, value, type }: TransformFnParams) {

return new Date(value);
}

function stringify(
value: Date | Date[] | undefined,
dateTime: boolean
): string | string[] | undefined {
if (value === undefined) {
return value;
}

if (value instanceof Date) {
return dateTime ? dateTimeToString(value) : dateToString(value);
}

return value.map((v) => stringify(v, dateTime) as string);
}

function dateTimeToString(date: Date): string {
return date.toISOString();
}

function dateToString(date: Date): string {
return date.toISOString().split('T')[0];
}

0 comments on commit d8c3dd3

Please sign in to comment.