diff --git a/package.json b/package.json index 20cad91..5cc64b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "functional-models", - "version": "3.0.12", + "version": "3.0.16", "description": "Functional models is ooey gooey framework for building and using awesome models EVERYWHERE.", "main": "index.js", "types": "index.d.ts", diff --git a/src/orm/query.ts b/src/orm/query.ts index 8d97aad..a081a99 100644 --- a/src/orm/query.ts +++ b/src/orm/query.ts @@ -94,7 +94,7 @@ const _builderV2 = (data: OrmSearch): InnerBuilderV2 => { const thisDatesBefore = ( key: string, jsDate: Date | string, - { valueType = DatastoreValueType.string, equalToAndBefore = true } = {} + { valueType = DatastoreValueType.date, equalToAndBefore = true } = {} ) => { const p = datesBefore(key, jsDate, { valueType, equalToAndBefore }) return _link(merge(data, { query: data.query.concat(p) })) @@ -103,7 +103,7 @@ const _builderV2 = (data: OrmSearch): InnerBuilderV2 => { const thisDatesAfter = ( key: string, jsDate: Date | string, - { valueType = DatastoreValueType.string, equalToAndAfter = true } = {} + { valueType = DatastoreValueType.date, equalToAndAfter = true } = {} ) => { const p = datesAfter(key, jsDate, { valueType, equalToAndAfter }) return _link(merge(data, { query: data.query.concat(p) })) @@ -235,11 +235,11 @@ const datesAfter = ( key: string, jsDate: Date | string, options: { valueType: DatastoreValueType; equalToAndAfter: boolean } = { - valueType: DatastoreValueType.string, + valueType: DatastoreValueType.date, equalToAndAfter: true, } ): DatesAfterQuery => { - const { valueType = DatastoreValueType.string, equalToAndAfter = true } = + const { valueType = DatastoreValueType.date, equalToAndAfter = true } = options return { type: 'datesAfter', @@ -271,11 +271,11 @@ const datesBefore = ( key: string, jsDate: Date | string, options: { valueType: DatastoreValueType; equalToAndBefore: boolean } = { - valueType: DatastoreValueType.string, + valueType: DatastoreValueType.date, equalToAndBefore: true, } ): DatesBeforeQuery => { - const { valueType = DatastoreValueType.string, equalToAndBefore = true } = + const { valueType = DatastoreValueType.date, equalToAndBefore = true } = options return { type: 'datesBefore', diff --git a/src/orm/types.ts b/src/orm/types.ts index 34c4637..060e005 100644 --- a/src/orm/types.ts +++ b/src/orm/types.ts @@ -745,6 +745,7 @@ type InnerBuilderV2 = { complex: (subBuilderFunc: SubBuilderFunction) => BuilderV2Link /** * Searches for elements that are after the given date. + * NOTE: It can be very important to set the valueType to either string or Date depending on what datastore you are using. * @param key - The property name/key to use. * @param jsDate - The date to search. * @param options - Additional options. @@ -756,6 +757,7 @@ type InnerBuilderV2 = { ) => BuilderV2Link /** * Searches for elements that are before the given date. + * NOTE: It can be very important to set the valueType to either string or Date depending on what datastore you are using. * @param key - The property name/key to use. * @param jsDate - The date to search. * @param options - Additional options. diff --git a/src/properties.ts b/src/properties.ts index 825d310..df47148 100644 --- a/src/properties.ts +++ b/src/properties.ts @@ -192,7 +192,7 @@ type DatePropertyConfig> = { formatFunction?: (date: Date, format?: string) => string /** * The format the date should be in. This is a framework agnostic format, and should be based on your format function. - * NOTE: If a formatFunction is not provided, this is completely ignored. For dates YYYY/MM/DD is the default and for Datetimes it is ISOString() + * NOTE: If a formatFunction is not provided, this is completely ignored. For dates YYYY-MM-DD is the default and for Datetimes it is ISOString() */ format?: string } & PropertyConfig diff --git a/src/types.ts b/src/types.ts index c52305e..f8b804a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -29,7 +29,7 @@ type Arrayable = T | readonly T[] * A JSON compliant object. */ type JsonObj = Readonly<{ - [s: string]: JsonAble | null + [s: string]: JsonAble | null | undefined }> /** @@ -42,6 +42,7 @@ type JsonAble = | string | boolean | null + | undefined /** * This is a fully Json compliant version of a DataDescription diff --git a/src/validation.ts b/src/validation.ts index cc67e02..c513900 100644 --- a/src/validation.ts +++ b/src/validation.ts @@ -1,6 +1,7 @@ import isEmpty from 'lodash/isEmpty' import merge from 'lodash/merge' import flatMap from 'lodash/flatMap' +import get from 'lodash/get' import { DataDescription, ModelInstance, @@ -417,8 +418,17 @@ const referenceTypeMatch = ( any > => { return (value?: ModelInstance) => { - if (!value) { - return 'Must include a value' + const theType = typeof value + switch (theType) { + case 'string': + case 'number': + case 'undefined': + return undefined + default: + break + } + if (value === null) { + return undefined } // This needs to stay here, as it delays the creation long enough for // self referencing types. @@ -436,16 +446,22 @@ const referenceTypeMatch = ( } } +/** + * A validator that can validate an entire object. + * + * @param required - If this object is required. + * @param keyToValidators - An object that has a dotted path key to the property to validate, and one or more validators for it. + */ const objectValidator = ({ required, keyToValidators, }: { required?: boolean - keyToValidators: { - [s: string]: - | ValuePropertyValidatorComponent - | ValuePropertyValidatorComponent[] - } + keyToValidators: Record< + string, + | ValuePropertyValidatorComponent + | ValuePropertyValidatorComponent[] + > }): ValuePropertyValidatorComponent => { return (obj: T) => { if (!obj) { @@ -459,16 +475,13 @@ const objectValidator = ({ return isNotObj } return ( - Object.entries(obj) - .reduce((acc, [key, value]) => { - const validators = keyToValidators[key] - if (!validators) { - return acc - } - const validator = Array.isArray(validators) - ? multiValidator(validators) - : validators - const error = validator(value) + Object.entries(keyToValidators) + .reduce((acc, [key, validator]) => { + const theValidator = Array.isArray(validator) + ? multiValidator(validator) + : (validator as ValuePropertyValidatorComponent) + const value = get(obj, key) + const error = theValidator(value) if (error) { return acc.concat(`${key}: ${error}`) } diff --git a/test/src/orm/query.test.ts b/test/src/orm/query.test.ts index 4357ced..e485372 100644 --- a/test/src/orm/query.test.ts +++ b/test/src/orm/query.test.ts @@ -446,7 +446,7 @@ describe('/src/orm/query.ts', () => { type: 'datesBefore', key: 'my-key', date: '2025-01-01T00:00:00.000Z', - valueType: DatastoreValueType.string, + valueType: DatastoreValueType.date, options: { equalToAndBefore: true, }, @@ -497,7 +497,7 @@ describe('/src/orm/query.ts', () => { type: 'datesAfter', key: 'my-key', date: '2025-01-01T00:00:00.000Z', - valueType: DatastoreValueType.string, + valueType: DatastoreValueType.date, options: { equalToAndAfter: true, }, @@ -725,7 +725,7 @@ describe('/src/orm/query.ts', () => { type: 'datesBefore', key: 'my-key', date: '2020-01-01', - valueType: 'string', + valueType: 'date', options: { equalToAndBefore: true, }, @@ -746,7 +746,7 @@ describe('/src/orm/query.ts', () => { type: 'datesAfter', key: 'my-key', date: '2020-01-01', - valueType: 'string', + valueType: 'date', options: { equalToAndAfter: true, }, diff --git a/test/src/validation.test.ts b/test/src/validation.test.ts index 34e4dd3..f6a80fc 100644 --- a/test/src/validation.test.ts +++ b/test/src/validation.test.ts @@ -769,7 +769,7 @@ describe('/src/validation.ts', () => { }) }) describe('#referenceTypeMatch()', () => { - it('should return an error if undefined is passed as a value', () => { + it('should return undefined if undefined is passed as a value', () => { const myModel = TestModel1.create({}) const actual = referenceTypeMatch(TestModel1)( // @ts-ignore @@ -778,9 +778,9 @@ describe('/src/validation.ts', () => { {}, {} ) - assert.isOk(actual) + assert.isUndefined(actual) }) - it('should return an error if null is passed as a value', () => { + it('should return undefined if null is passed as a value', () => { const myModel = TestModel1.create({}) const actual = referenceTypeMatch(TestModel1)( // @ts-ignore @@ -789,7 +789,7 @@ describe('/src/validation.ts', () => { {}, {} ) - assert.isOk(actual) + assert.isUndefined(actual) }) it('should allow a function for a model', async () => { const myModel = EMPTY_MODEL.create({})