summaryrefslogtreecommitdiff
path: root/app/node_modules/okresource/index.js
diff options
context:
space:
mode:
authorSean Fridman <fridman@mail.sfsu.edu>2015-04-08 14:06:30 -0400
committerSean Fridman <fridman@mail.sfsu.edu>2015-04-08 14:06:39 -0400
commit0fc380788157779a39fe630b2464280eea9f5088 (patch)
treef4f2f88c3bd098dd8ec083e56ec64f5340e2c445 /app/node_modules/okresource/index.js
parentb91c88be52170a7c9a8b133ef72052bec8caccba (diff)
Add resource instance concept
Can now define resource classes bound to particular data points, in particular they can be static data defined by app config and not even in DB
Diffstat (limited to 'app/node_modules/okresource/index.js')
-rw-r--r--app/node_modules/okresource/index.js178
1 files changed, 166 insertions, 12 deletions
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;