diff options
Diffstat (limited to 'app/node_modules')
| -rw-r--r-- | app/node_modules/okquery/index.js | 26 | ||||
| -rw-r--r-- | app/node_modules/okresource/index.js | 178 | ||||
| -rw-r--r-- | app/node_modules/okresource/package.json | 1 |
3 files changed, 186 insertions, 19 deletions
diff --git a/app/node_modules/okquery/index.js b/app/node_modules/okquery/index.js index a64f0f2..9748067 100644 --- a/app/node_modules/okquery/index.js +++ b/app/node_modules/okquery/index.js @@ -14,14 +14,19 @@ function OKQuery(options) { var resource = options.resource; var type = resource.type; var query = options.query || '*'; + Object.defineProperty(this, 'resource', { value: resource, - writable: false + writable: false, + enumerable: true }); + Object.defineProperty(this, 'type', { value: resource.type, - writable: false + writable: false, + enumerable: true }); + this.get = createQuery(resource, query, { default: options.default }); @@ -29,8 +34,9 @@ function OKQuery(options) { function createQuery(resource, query, options) { options = options || {}; - var query; - if (isDynamic(query)) { + if (resource.bound) { + query = queryBound(resource); + } else if (isDynamic(query)) { query = queryDynamic(resource); } else if (isSet(query)) { query = queryAll(resource); @@ -46,19 +52,25 @@ function createQuery(resource, query, options) { function queryDynamic(resource) { return function(id) { return resource.get(id); - } + }; } function queryAll(resource) { return function() { return resource.all(); - } + }; } function querySingle(resource, id) { return function() { return resource.get(id); - } + }; +} + +function queryBound(resource) { + return function() { + return resource.get(); + }; } function withDefault(queryFn, resultDefault) { diff --git a/app/node_modules/okresource/index.js b/app/node_modules/okresource/index.js index 7cd51c7..0e99883 100644 --- a/app/node_modules/okresource/index.js +++ b/app/node_modules/okresource/index.js @@ -1,3 +1,4 @@ +var assign = require('object-assign'); var Q = require('q'); /** @@ -31,15 +32,10 @@ function OKResource(options) { var type = options.type; this._db = options.db; + this._schema = schema; // Define properties which are part of the API - Object.defineProperty(this, 'schema', { - value: schema, - writable: false, - enumerable: true - }); - Object.defineProperty(this, 'spec', { value: schema.spec, writable: false, @@ -57,13 +53,21 @@ function OKResource(options) { writable: false, enumerable: true }); + + // Whether this resource represents a specific data point + // or a whole class of data + Object.defineProperty(this, 'bound', { + value: false, + writable: false, + enumerable: true + }); } /** * Throws an error if data does not conform to schema */ OKResource.prototype.assertValid = function(data) { - this.schema.assertValid(data); + this._schema.assertValid(data); }; OKResource.prototype.all = function() { @@ -72,12 +76,14 @@ OKResource.prototype.all = function() { OKResource.prototype.create = function(data) { data = data || {}; + var type = this.type; + var db = this._db; var id = data[this.idField]; return Q.promise(function(resolve, reject) { if (!id) { reject(new Error('Data does not contain ID property')); } else { - this._db.create(this.type, data).then(resolve, reject); + db.create(type, data).then(resolve, reject); } }); }; @@ -145,14 +151,14 @@ OKResource.prototype.updateOrCreate = function(data) { var type = this.type; var db = this._db; var idField = this.idField; + var query = {}; + query[idField] = id; return Q.promise(function(resolve, reject) { if (!id) { reject(new Error('Cannot updateOrCreate without ID')); } else { - db.get(type, data.id).then(function(cached) { - var query = {}; - query[idField] = id; - if (cached) + db.get(type, query).then(function(persisted) { + if (persisted) db.put(type, query, data).then(resolve, reject); else db.create(type, data).then(resolve, reject); @@ -161,4 +167,152 @@ OKResource.prototype.updateOrCreate = function(data) { }); }; +/** + * Create special resource which is bound to particular data point + * and has custom validation and query properties. + */ +OKResource.prototype.instance = function(options) { + return new OKResourceInstance(this, { + static: options.static + }); +}; + +function OKResourceInstance(resource, options) { + if (!(this instanceof OKResourceInstance)) return new OKResourceInstance(options); + // Only support static data instances for now + if (!options.static) + throw new Error( + 'Cannot create OKResourceInstance without static data'); + + // Resources with static data are a special case. They exist + // conceptually at all times since they are derived from app + // configuration, but may not actually be present + // in the database and need custom logic to handle this. + var staticData = assign({}, options.static); + var id = staticData[resource.idField]; + if (!id) + throw new Error( + 'Cannot create static OKResourceInstance without an ID field'); + + /** + * Ensure that static data is provided on get + */ + this.get = function() { + return Q.promise(function(resolve, reject) { + resource.get(id).then(function(data) { + // Note the assign call. Don't expose private references! + if (data) { + resolve(assign({}, data, staticData)); + } else { + resolve(assign({}, staticData)); + } + }).fail(reject); + }); + }; + + this.update = function(data) { + return Q.promise(function(resolve, reject) { + var valid = Object.keys(staticData).every(function(prop) { + return staticData[prop] === data[prop]; + }); + if (!valid) { + reject(new Error('Cannot update resource\'s static data')); + } else { + // When updating static resources, we create them if + // they don't actually exist in the DB + resource.updateOrCreate(data).then(resolve).fail(reject); + } + }); + }; + + this.updateOrCreate = function(id) { + return Q.promise(function(resolve, reject) { + reject(new Error('Cannot updateOrCreate static resource')); + }); + }; + + this.destroy = function(id) { + return Q.promise(function(resolve, reject) { + reject(new Error('Cannot destroy static resource')); + }); + }; + + this.all = function(id) { + return Q.promise(function(resolve, reject) { + reject(new Error('Cannot get all for static resource')); + }); + }; + + this.create = function(id) { + return Q.promise(function(resolve, reject) { + reject(new Error('Cannot create static resource')); + }); + }; + + this.find = function(id) { + return Q.promise(function(resolve, reject) { + reject(new Error('Cannot perform find on static resource')); + }); + }; + + this.assertValid = function(data) { + data = data || {}; + Object.keys(staticData).forEach(function(prop) { + if (staticData[prop] !== data[prop]) { + // Validation error is in mschema error format + throw [{ + property: prop, + constraint: 'static', + expected: staticData[prop], + actual: data[prop], + message: 'Data does not match static data' + }]; + } + }); + resource.assertValid(data); + }; + + Object.defineProperty(this, 'parent', { + value: resource, + writable: false, + enumerable: true + }); + + Object.defineProperty(this, 'spec', { + value: resource.spec, + writable: false, + enumerable: true + }); + + Object.defineProperty(this, 'id', { + value: id, + writable: false, + enumerable: true + }); + + Object.defineProperty(this, 'type', { + value: resource.type, + writable: false, + enumerable: true + }); + + Object.defineProperty(this, 'idField', { + value: resource.idField, + writable: false, + enumerable: true + }); + + Object.defineProperty(this, 'bound', { + value: true, + writable: false, + enumerable: true + }); + + Object.defineProperty(this, 'class', { + value: resource, + writable: false, + enumerable: true + }); +} + module.exports = OKResource; diff --git a/app/node_modules/okresource/package.json b/app/node_modules/okresource/package.json index da9dfe0..7f19c9b 100644 --- a/app/node_modules/okresource/package.json +++ b/app/node_modules/okresource/package.json @@ -9,6 +9,7 @@ "author": "OKFocus", "license": "None", "dependencies": { + "object-assign": "^2.0.0", "q": "^1.2.0" } } |
