summaryrefslogtreecommitdiff
path: root/app/node_modules/okresource/index.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/node_modules/okresource/index.js')
-rw-r--r--app/node_modules/okresource/index.js204
1 files changed, 129 insertions, 75 deletions
diff --git a/app/node_modules/okresource/index.js b/app/node_modules/okresource/index.js
index 94d8cfb..c1f2509 100644
--- a/app/node_modules/okresource/index.js
+++ b/app/node_modules/okresource/index.js
@@ -1,4 +1,6 @@
+var format = require('util').format
var assign = require('object-assign');
+var cloneDeep = require('lodash.clonedeep');
var Q = require('q');
/**
@@ -18,27 +20,44 @@ function OKResource(options) {
throw new Error('No DB provided to OKResource');
var schema = options.schema;
- // Iterate through spec to find field which will act as the
- // resource id in da db.
- var idField = Object.keys(schema.spec).reduce(function(idField, prop) {
- var spec = schema.spec[prop];
- if (spec.id)
- idField = prop;
- return idField;
- // If schema has a prop called 'id', default to that one
- }, schema.spec.id && 'id');
- if (!idField)
- throw new Error('Bad schema: no ID field');
+ var spec = schema.spec;
var type = options.type;
+ var hasForeignKey = false
this._db = options.db;
this._schema = schema;
+ var foreignKeys = Object.keys(spec).reduce(function(acc, field) {
+ var fieldSpec = spec[field]
+ if (fieldSpec.type === 'foreign-key') {
+ hasForeignKey = true
+ acc[field] = fieldSpec.key
+ }
+ return acc
+ }, {})
+
+ // Will store references to other resources referenced via foreign keys
+ this._foreignKeyedResources = {}
+
// Define properties which are part of the API
+
+ // Should be treated as read-only
+ Object.defineProperty(this, 'foreignKeys', {
+ get: function() {
+ return foreignKeys
+ }
+ })
+
+ Object.defineProperty(this, 'hasForeignKey', {
+ get: function() {
+ return hasForeignKey
+ }
+ })
Object.defineProperty(this, 'spec', {
- value: schema.spec,
- writable: false,
+ get: function() {
+ return schema.spec;
+ },
enumerable: true
});
@@ -48,12 +67,6 @@ function OKResource(options) {
enumerable: true
});
- Object.defineProperty(this, 'idField', {
- value: idField,
- writable: false,
- enumerable: true
- });
-
// Whether this resource represents a specific data point
// or a whole class of data
Object.defineProperty(this, 'bound', {
@@ -63,6 +76,30 @@ function OKResource(options) {
});
}
+OKResource.prototype._linkForeignKey = function(field, resource) {
+ this._foreignKeyedResources[field] = resource
+}
+
+/**
+ * Fetch all related resources for the given field
+ */
+OKResource.prototype.related = function(field) {
+ var resource = this._foreignKeyedResources[field]
+ return Q.promise(function(resolve, reject) {
+ if (!resource) {
+ return error(reject, new Error(format(
+ "No related resource for field '%s'", field)))
+ }
+ resource.all().then(resolve).fail(reject)
+ })
+
+ function error(reject, err) {
+ setTimeout(function() {
+ reject(err)
+ }, 0)
+ }
+}
+
/**
* Throws an error if data does not conform to schema
*/
@@ -71,31 +108,34 @@ OKResource.prototype.assertValid = function(data) {
};
OKResource.prototype.all = function() {
- return this._db.getAll(this.type);
+ return this._db.all(this.type);
};
-OKResource.prototype.create = function(data) {
+OKResource.prototype.getID = function(data) {
data = data || {};
+ return data[this._schema.idField];
+};
+
+OKResource.prototype.create = function(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'));
+ if (!data) {
+ reject(new Error('No data provided'));
} else {
- db.create(type, data).then(resolve).fail(reject);
+ db.insert(type, data).then(resolve).fail(reject);
}
});
};
-OKResource.prototype.destroy = function(data) {
- data = data || {};
- var id = data[this.idField];
+OKResource.prototype.destroy = function(id) {
+ var db = this._db;
+ var type = this.type;
return Q.promise(function(resolve, reject) {
if (!id) {
- reject(new Error('Data does not contain ID property'));
+ reject(new Error('No ID provided'));
} else {
- this._db.remove(this.type, data.id, data).then(resolve).fail(reject);
+ db.remove(type, id).then(resolve).fail(reject);
}
});
};
@@ -106,7 +146,7 @@ OKResource.prototype.find = function(query) {
var type = this.type;
return Q.promise(function(resolve, reject) {
if (!query) {
- throw new Error('No query given');
+ throw new Error('No query provided');
} else {
db.find(type, query).then(resolve).fail(reject);
}
@@ -116,53 +156,65 @@ OKResource.prototype.find = function(query) {
OKResource.prototype.get = function(id) {
var db = this._db;
var type = this.type;
- var idField = this.idField;
return Q.promise(function(resolve, reject) {
if (!id) {
- throw new Error('No ID given');
+ throw new Error('No ID provided');
} else {
- // We have the id, but we still need
- // to resolve which field is the id field
- // to match
- var query = {};
- query[idField] = id;
- db.get(type, query).then(resolve).fail(reject);
+ db.get(type, id).then(resolve).fail(reject);
}
});
};
OKResource.prototype.update = function(id, data) {
- data = data || {};
var db = this._db;
var type = this.type;
- var idField = this.idField;
return Q.promise(function(resolve, reject) {
if (!id) {
reject(new Error('No resource ID provided'));
+ } else if (!data) {
+ reject(new Error('No data provided'));
} else {
- var query = {};
- query[idField] = id;
- db.put(type, query, data).then(resolve).fail(reject);;
+ db.update(type, id, data).then(resolve).fail(reject);;
}
});
};
+OKResource.prototype.updateBatch = function(ids, datas) {
+ var self = this;
+ var db = this._db;
+ var type = this.type;
+ return Q.promise(function(resolve, reject) {
+ if (!ids || !ids.length || !datas || !datas.length ||
+ ids.length !== datas.length) {
+ reject(new Error('Bad input'));
+ } else {
+ db.updateBatch(type, ids, datas).then(resolve).fail(reject);
+ }
+ });
+}
+
+
+/**
+ * Get all documents in collection sorted by property,
+ * optionally in descending order
+ */
+OKResource.prototype.sortBy = function(prop, descend) {
+ return this._db.sortBy(this.type, prop, descend);
+};
+
OKResource.prototype.updateOrCreate = function(id, data) {
data = 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('No resource ID provided'));
+ reject(new Error('No ID provided'));
} else {
- db.get(type, query).then(function(persisted) {
+ db.get(type, id).then(function(persisted) {
if (persisted) {
- db.put(type, query, data).then(resolve).fail(reject);
+ db.update(type, id, data).then(resolve).fail(reject);
} else {
- db.create(type, data).then(resolve).fail(reject);
+ db.insert(type, data).then(resolve).fail(reject);
}
}).fail(reject);
}
@@ -179,6 +231,9 @@ OKResource.prototype.instance = function(options) {
});
};
+/**
+ * TODO This class is such bullshit. Refactor out
+ */
function OKResourceInstance(resource, options) {
if (!(this instanceof OKResourceInstance)) return new OKResourceInstance(options);
// Only support static data instances for now
@@ -190,12 +245,16 @@ function OKResourceInstance(resource, options) {
// 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];
+ var staticData = cloneDeep(options.static);
+ var id = resource.getID(staticData);
if (!id)
throw new Error(
'Cannot create static OKResourceInstance without an ID field');
+ this.getID = function() {
+ return id;
+ };
+
/**
* Ensure that static data is provided on get
*/
@@ -204,9 +263,9 @@ function OKResourceInstance(resource, options) {
resource.get(id).then(function(data) {
// Note the assign call. Don't expose private references!
if (data) {
- resolve(assign({}, data, staticData));
+ resolve(assign(data, cloneDeep(staticData)));
} else {
- resolve(assign({}, staticData));
+ resolve(cloneDeep(staticData));
}
}).fail(reject);
});
@@ -274,6 +333,18 @@ function OKResourceInstance(resource, options) {
resource.assertValid(data);
};
+ Object.defineProperty(this, 'foreignKeys', {
+ get: function() {
+ return []
+ }
+ })
+
+ Object.defineProperty(this, 'hasForeignKey', {
+ get: function() {
+ return false
+ }
+ })
+
Object.defineProperty(this, 'parent', {
value: resource,
writable: false,
@@ -281,14 +352,9 @@ function OKResourceInstance(resource, options) {
});
Object.defineProperty(this, 'spec', {
- value: resource.spec,
- writable: false,
- enumerable: true
- });
-
- Object.defineProperty(this, 'id', {
- value: id,
- writable: false,
+ get: function() {
+ return resource.spec
+ },
enumerable: true
});
@@ -298,23 +364,11 @@ function OKResourceInstance(resource, options) {
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;