diff options
Diffstat (limited to 'app/node_modules/okschema/index.js')
| -rw-r--r-- | app/node_modules/okschema/index.js | 178 |
1 files changed, 160 insertions, 18 deletions
diff --git a/app/node_modules/okschema/index.js b/app/node_modules/okschema/index.js index 8871a99..0048fc5 100644 --- a/app/node_modules/okschema/index.js +++ b/app/node_modules/okschema/index.js @@ -1,4 +1,4 @@ -var assign = require('object-assign'); +var cloneDeep = require('lodash.clonedeep'); var mschema = require('mschema'); var v = require('validator'); @@ -41,36 +41,99 @@ var types = { } }, 'captioned-image-list': { + isArray: true, parent: [{ uri: { type: 'string' }, // TODO Implement URI type caption: { type: 'string' } }], - assertValid: function(spec, value) { - var message; - var actual; - if (!value || !value.length) { - throw [{ - message: 'Not an array', - expected: JSON.stringify(this.parent), - actual: value - }]; - } - } + assertValid: function(spec, value) {} + }, + 'gallery': { + isArray: true, + parent: [{ + uri: { type: 'string' }, // TODO Implement URI type + caption: { type: 'string' } + }], + assertValid: function(spec, value) {} + }, + // Special type for resource meta information + 'meta': { + parent: 'string', + assertValid: function(spec, value) {} + }, + 'link-list': { + isArray: true, + parent: [{ + uri: { type: 'string' }, + text: { type: 'string' } + }], + assertValid: function(spec, value) {} + }, + 'date': { + parent: 'string', + assertValid: function(spec, value) {} + }, + 'flag': { + parent: 'boolean', + assertValid: function(spec, value) {} + }, + 'foreign-key': { + parent: 'enum', + assertValid: function(spec, value) {} + }, + 'media-list': { + isArray: true, + parent: [], + assertValid: function(spec, value) {} + }, + 'media': { + isArray: true, + parent: [], + assertValid: function(spec, value) {} + }, + 'double-captioned-image-list': { + isArray: true, + parent: [], + assertValid: function(spec, value) {} + }, + 'triple-captioned-image-list': { + isArray: true, + parent: [], + assertValid: function(spec, value) {} + }, +} + +/* +function checkArrayLength (spec, value) { + var message; + var actual; + if (!value || !value.length) { + throw [{ + message: 'Not an array', + expected: JSON.stringify(this.parent), + actual: value + }]; } } +*/ + /** * OKSchema! * Meant as a thin wrapper around some existing schema validation * module, mostly to allow for the extension of types. + * + * NOTE: Currently just assumes spec is valid. If you give a bad spec + * strange things may or may not happen */ function OKSchema(spec) { if (!(this instanceof OKSchema)) return new OKSchema(spec); if (!spec) throw new Error('No spec provided to OKSchema'); - spec = assign({}, spec); + spec = cloneDeep(spec); + var specKeys = Object.keys(spec); // Cache the mschema version of our spec - this._mschemaSpec = Object.keys(spec).reduce(function(cache, prop) { + this._mschemaSpec = specKeys.reduce(function(cache, prop) { // If custom type, return its parent spec var type = spec[prop].type; if (types[type]) { @@ -82,25 +145,104 @@ function OKSchema(spec) { return cache; }, {}); + // Find ID field + var idField; + specKeys.every(function(prop) { + if (prop === 'id' || spec[prop].id) { + idField = prop; + return false; + } else { + return true; + } + }); + + // Register autoincrement fields + // NOTE Does not work for nested fields + var autoIncrementFields = specKeys.reduce(function(arr, prop) { + var specProp = spec[prop]; + if (specProp.autoincrement) { + arr.push(prop); + } + return arr; + }, []); + Object.defineProperty(this, 'spec', { - value: spec, - writable: false + get: function() { + return cloneDeep(spec); + }, + enumerable: true + }); + + Object.defineProperty(this, 'idField', { + value: idField, + writable: true, + enumerable: true }); + + Object.defineProperty(this, 'autoIncrementFields',{ + get: function() { + return cloneDeep(autoIncrementFields); + }, + enumerable: true + }); +} + +OKSchema.prototype.fixMissingLists = function(data) { + var spec = this.spec; + + // The qs body-parser module does not have a way to represent + // empty lists. If you delete all elements from a list, + // check against the spec so we know to replace with an empty list. + Object.keys(spec).forEach(function(prop){ + var type = spec[prop].type; + if (types[type] && types[type].isArray && ! data[prop]) { + data[prop] = [] + } + }) +} + +OKSchema.prototype.fixIndexField = function(data) { + // Likewise numbers always come in as strings. The field used to sort + // records, __index, is of type "meta", so the parseFloat in + // assertValid (below) never fires and we end up with sorting issues. + if (data.__index && typeof data.__index == "string") { + var __index = parseInt(data.__index) + if (! isNaN(__index)) { + data.__index = __index + } + } } OKSchema.prototype.assertValid = function(data) { data = data || {}; var spec = this.spec; + // Run through custom validators, they'll throw if invalid Object.keys(data).forEach(function(prop) { var type = spec[prop].type; - if (types[type]) { + + // Check if it's a number/boolean and try to cast it + // otherwise pass and let mschema handle + if (type === 'number') { + try { + data[prop] = parseFloat(data[prop]); + } catch (err) {} + } else if (type === 'flag') { + data[prop] = data[prop] == "true" ? true : false + } else if (types[type]) { types[type].assertValid(spec[prop], data[prop]); } }); var result = mschema.validate(data, this.toMschema()); - if (!result.valid) + if (!result.valid) { throw result.errors; + } + + // Fix various issues with our data, having to do + // with use of the "qs" body-parser module. + // TODO: just send JSON? + this.fixMissingLists(data) + this.fixIndexField(data) }; /** |
