diff --git a/lib/model.js b/lib/model.js index 798a96c..83f3535 100644 --- a/lib/model.js +++ b/lib/model.js @@ -754,11 +754,22 @@ validate(cb) { let errors = {}; - var self = this; - var schema = this.schema; + const self = this; + const schema = this.schema; + + let skip; + let schemaHasProperty; + let propertyValue; + let isRequired; Object.keys(this.entityData).forEach((k) => { - let skip = false; + skip = false; + schemaHasProperty = schema.paths.hasOwnProperty(k); + propertyValue = self.entityData[k]; + + if (typeof propertyValue === 'string') { + propertyValue = propertyValue.trim(); + } if (schema.virtuals.hasOwnProperty(k)) { // Virtual, remove it and skip the rest @@ -767,55 +778,54 @@ } // Properties dict - if (!schema.paths.hasOwnProperty(k) && schema.options.explicitOnly === false) { + if (!schemaHasProperty && schema.options.explicitOnly === false) { // No more validation, key does not exist but it is allowed skip = true; } - if (!skip && !schema.paths.hasOwnProperty(k)) { + if (!skip && !schemaHasProperty) { errors.properties = new Error ('Property not allowed {' + k + '} for ' + this.entityKind + ' Entity'); } // Properties type - if (!skip && schema.paths.hasOwnProperty(k) && self.entityData[k] !== null && schema.paths[k].hasOwnProperty('type')) { + if (!skip && schemaHasProperty && propertyValue !== null && schema.paths[k].hasOwnProperty('type')) { var typeValid = true; if (schema.paths[k].type === 'datetime') { // Validate datetime "format" - let error = validateDateTime(self.entityData[k], k); + let error = validateDateTime(propertyValue, k); if (error !== null) { errors.datetime = error; } } else { - let value = self.entityData[k]; if (schema.paths[k].type === 'array') { // Array - typeValid = is.array(value); + typeValid = is.array(propertyValue); } else if (schema.paths[k].type === 'int') { // Integer - let isIntInstance = value.constructor.name === 'Int'; + let isIntInstance = propertyValue.constructor.name === 'Int'; if (isIntInstance) { - typeValid = !isNaN(parseInt(value.value)); + typeValid = !isNaN(parseInt(propertyValue.value)); } else { - typeValid = isInt(value); + typeValid = isInt(propertyValue); } } else if (schema.paths[k].type === 'double') { // Double - let isIntInstance = value.constructor.name === 'Double'; + let isIntInstance = propertyValue.constructor.name === 'Double'; if (isIntInstance) { - typeValid = isFloat(parseFloat(value.value, 10)) || isInt(parseFloat(value.value, 10)); + typeValid = isFloat(parseFloat(propertyValue.value, 10)) || isInt(parseFloat(propertyValue.value, 10)); } else { - typeValid = isFloat(value) || isInt(value); + typeValid = isFloat(propertyValue) || isInt(propertyValue); } } else if (schema.paths[k].type === 'buffer') { // Double - typeValid = value instanceof Buffer; + typeValid = propertyValue instanceof Buffer; } else if (schema.paths[k].type === 'geoPoint') { // GeoPoint - typeValid = value.constructor.name === 'GeoPoint'; + typeValid = propertyValue.constructor.name === 'GeoPoint'; } else { // Other - typeValid = typeof value === schema.paths[k].type; + typeValid = typeof propertyValue === schema.paths[k].type; } if (!typeValid) { @@ -827,7 +837,18 @@ } // Value Validation - if (!skip && schema.paths.hasOwnProperty(k) && schema.paths[k].hasOwnProperty('validate') && self.entityData[k] && self.entityData[k] !== '' && self.entityData[k] !== null) { + + // ...Required + isRequired = schemaHasProperty && schema.paths[k].hasOwnProperty('required') && schema.paths[k].required === true; + + if (!skip && isRequired && !!propertyValue === false) { + errors[k] = new GstoreError.ValidatorError({ + message: 'Property {' + k + '} is required' + }); + } + + // ...Wrong format + if (!skip && schemaHasProperty && schema.paths[k].hasOwnProperty('validate') && self.entityData[k] && self.entityData[k] !== '' && self.entityData[k] !== null) { if (!validator[schema.paths[k].validate](self.entityData[k])) { errors[k] = new GstoreError.ValidatorError({ message: 'Wrong format for property {' + k + '}' @@ -836,7 +857,7 @@ } // Preset values - if (!skip && schema.paths.hasOwnProperty(k) && schema.paths[k].hasOwnProperty('values') && self.entityData[k] !== '') { + if (!skip && schemaHasProperty && schema.paths[k].hasOwnProperty('values') && self.entityData[k] !== '') { if (schema.paths[k].values.indexOf(self.entityData[k]) < 0) { errors[k] = new Error('Value not allowed for ' + k + '. It must be in the range: ' + schema.paths[k].values); } diff --git a/test/model-test.js b/test/model-test.js index 3030476..ffbae48 100644 --- a/test/model-test.js +++ b/test/model-test.js @@ -1609,6 +1609,30 @@ describe('Model', function() { expect(valid.success).be.true; }); + it('required property', () => { + schema = new Schema({ + name: {type: 'string'}, + email: {type: 'string', required:true} + }); + + ModelInstance = Model.compile('Blog', schema, gstore); + + let model = new ModelInstance({name:'John Snow'}); + let model2 = new ModelInstance({name:'John Snow', email:''}); + let model3 = new ModelInstance({name:'John Snow', email:' '}); + let model4 = new ModelInstance({name:'John Snow', email: null}); + + let valid = model.validate(); + let valid2 = model2.validate(); + let valid3 = model3.validate(); + let valid4 = model4.validate(); + + expect(valid.success).be.false; + expect(valid2.success).be.false; + expect(valid3.success).be.false; + expect(valid4.success).be.false; + }); + it ('no type validation', () => { let model = new ModelInstance({street:123}); let model2 = new ModelInstance({street:'123'}); @@ -1794,7 +1818,7 @@ describe('Model', function() { expect(valid6.success).be.false; }); - it ('--> is URL ok', () => { + it ('--> is URL ok', () => { let model = new ModelInstance({website:'http://google.com'}); let model2 = new ModelInstance({website:'google.com'});