Skip to content

Commit

Permalink
fix(schema.date): allow valid string Date in validation (#210)
Browse files Browse the repository at this point in the history
This fixes a bug where providing a valid string date with Date() was throwing a validation error.
Now any valid string date will be converted to date object before saving the entity.

fix #206
  • Loading branch information
sebelga committed Dec 8, 2019
1 parent 94b74d8 commit 268c22e
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 285 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@
"dependencies": {
"arrify": "^2.0.1",
"dataloader": "^1.4.0",
"date-fns": "^2.8.1",
"extend": "^3.0.2",
"is": "^3.3.0",
"lodash.get": "^4.4.2",
"lodash.set": "^4.3.2",
"moment": "^2.24.0",
"nsql-cache": "^1.1.5",
"nsql-cache-datastore": "^1.1.6",
"optional": "^0.1.4",
Expand Down
10 changes: 10 additions & 0 deletions src/entity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,16 @@ describe('Entity', () => {
});
});

test('should convert string date to Date object', () => {
schema = new Schema({ birthday: { type: Date } });
GstoreModel = gstore.model('TestDateConversion', schema);
entity = new GstoreModel({ birthday: '2001-01-20' });

return entity.save().then(() => {
expect(entity.entityData.birthday instanceof Date).to.equal(true);
});
});

test('should sanitize the entityData', () => {
schema = new Schema({ name: { type: String } });
GstoreModel = gstore.model('TestValidate', schema);
Expand Down
20 changes: 17 additions & 3 deletions src/entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -570,12 +570,26 @@ export class Entity<T extends object = GenericObject> {
*/
if ({}.hasOwnProperty.call(this.schema.__meta, 'geoPointsProps')) {
this.schema.__meta.geoPointsProps.forEach((property: string) => {
const propValue = (this.entityData as any)[property];
if (
{}.hasOwnProperty.call(this.entityData, property) &&
(this.entityData as any)[property] !== null &&
(this.entityData as any)[property].constructor.name !== 'GeoPoint'
propValue !== null &&
propValue.constructor.name !== 'GeoPoint'
) {
(this.entityData as any)[property] = this.gstore.ds.geoPoint((this.entityData as any)[property]);
(this.entityData as any)[property] = this.gstore.ds.geoPoint(propValue);
}
});
}

if ({}.hasOwnProperty.call(this.schema.__meta, 'dateProps')) {
this.schema.__meta.dateProps.forEach((property: string) => {
const propValue = (this.entityData as any)[property];
if (
{}.hasOwnProperty.call(this.entityData, property) &&
propValue !== null &&
propValue instanceof Date === false
) {
(this.entityData as any)[property] = new Date(propValue);
}
});
}
Expand Down
14 changes: 8 additions & 6 deletions src/helpers/validation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,23 +316,25 @@ describe('Validation', () => {
test('--> date ok', () => {
const { error } = validate({ birthday: '2015-01-01' });
const { error: error2 } = validate({ birthday: new Date() });
const { error: error3 } = validate({ birthday: Date() });
const { error: error4 } = validate({ birthday: '01-01-2015' });
const { error: error5 } = validate({ birthday: '2015/01/01' });
const { error: error6 } = validate({ birthday: '01/01/2015' });

expect(error).equal(null);
expect(error2).equal(null);
expect(error3).equal(null);
expect(error4).equal(null);
expect(error5).equal(null);
expect(error6).equal(null);
});

test('--> date ko', () => {
const { error } = validate({ birthday: '01-2015-01' });
const { error: error2 } = validate({ birthday: '01-01-2015' });
const { error: error3 } = validate({ birthday: '2015/01/01' });
const { error: error4 } = validate({ birthday: '01/01/2015' });
const { error: error5 } = validate({ birthday: 12345 }); // No number allowed
const { error: error6 } = validate({ birthday: 'string' });

expect(error.errors[0].code).equal(ERROR_CODES.ERR_PROP_TYPE);
expect(error2.errors[0].code).equal(ERROR_CODES.ERR_PROP_TYPE);
expect(error3.errors[0].code).equal(ERROR_CODES.ERR_PROP_TYPE);
expect(error4.errors[0].code).equal(ERROR_CODES.ERR_PROP_TYPE);
expect(error5.errors[0].code).equal(ERROR_CODES.ERR_PROP_TYPE);
expect(error6.errors[0].code).equal(ERROR_CODES.ERR_PROP_TYPE);
});
Expand Down
14 changes: 6 additions & 8 deletions src/helpers/validation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import moment from 'moment';
import isDateValid from 'date-fns/isValid';
import validator from 'validator';
import is from 'is';
import { Datastore } from '@google-cloud/datastore';
Expand All @@ -8,15 +8,13 @@ import { EntityData } from '../types';
import Schema, { SchemaPathDefinition, Validator } from '../schema';

const isValidDate = (value: any): boolean => {
if (
value.constructor.name !== 'Date' &&
(typeof value !== 'string' ||
!/\d{4}-\d{2}-\d{2}([ ,T])?(\d{2}:\d{2}:\d{2})?(\.\d{1,3})?/.exec(value) ||
!moment(value).isValid())
) {
if (value instanceof Date) {
return true;
}
if (typeof value !== 'string') {
return false;
}
return true;
return isDateValid(new Date(value));
};

const isInt = (n: unknown): boolean => Number(n) === n && n % 1 === 0;
Expand Down
9 changes: 8 additions & 1 deletion src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,10 @@ const extractMetaFromSchema = <T extends object>(schema: Schema<T>): GenericObje
const meta: GenericObject = {};

Object.keys(schema.paths).forEach(k => {
switch (schema.paths[k as keyof T].type) {
const propType = schema.paths[k as keyof T].type as any;
const stringType = propType !== undefined && propType.name ? propType.name : propType;

switch (stringType) {
case 'geoPoint':
// This allows us to automatically convert valid lng/lat objects
// to Datastore.geoPoints
Expand All @@ -273,6 +276,10 @@ const extractMetaFromSchema = <T extends object>(schema: Schema<T>): GenericObje
meta.refProps = meta.refProps || {};
meta.refProps[k] = true;
break;
case 'Date':
meta.dateProps = meta.dateProps || [];
meta.dateProps.push(k);
break;
default:
}
});
Expand Down
Loading

0 comments on commit 268c22e

Please sign in to comment.