summaryrefslogtreecommitdiff
path: root/app/node_modules
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
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')
-rw-r--r--app/node_modules/okquery/index.js26
-rw-r--r--app/node_modules/okresource/index.js178
-rw-r--r--app/node_modules/okresource/package.json1
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"
}
}