Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

In-memory adapter

  • Loading branch information...
commit c249c435d1b89714ac032af223529a19480c9df2 1 parent 366b9c8
mde authored
View
162 lib/adapters/memory/index.js
@@ -0,0 +1,162 @@
+var model = require('../../index')
+ , utils = require('utilities')
+ , mr = require('../transformers/mr')
+ , operation = require('../../query/operation')
+ , comparison = require('../../query/comparison')
+ , datatypes = require('../../datatypes')
+ , request = utils.request
+ , BaseAdapter = require('../base_adapter').BaseAdapter
+ , _baseConfig
+ , _data = {};
+
+_baseConfig = {};
+
+var Adapter = function (options) {
+ var opts = options || {}
+ , config;
+
+ this.name = 'memory';
+ this.config = _baseConfig;
+ this.client = null;
+
+ utils.mixin(this.config, opts);
+
+ this.init.apply(this, arguments);
+};
+
+Adapter.prototype = new BaseAdapter();
+Adapter.prototype.constructor = Adapter;
+
+utils.mixin(Adapter.prototype, new (function () {
+
+ this.init = function () {};
+
+ this.load = function (query, callback) {
+ var key = query.model.modelName
+ , id = query.byId
+ , conditions
+ , sort
+ , items = _data[key]
+ , item
+ , filter
+ , res = [];
+ if (id) {
+ item = _data[key][id];
+ callback(null, item);
+ }
+ else {
+ conditions = this.transformConditions(query.conditions);
+ sort = this.transformSortOrder(query.opts.sort);
+
+ filter = new Function('data', 'return (' + conditions + ')');
+ for (var p in items) {
+ item = items[p];
+ if (filter(item)) {
+ res.push(item);
+ }
+ }
+ if (sort) {
+ sort(res);
+ }
+
+ callback(null, res);
+ }
+ };
+
+ this.update = function (data, query, callback) {
+ var key = query.model.modelName
+ , id = query.byId
+ , ids;
+ if (id) {
+ ids = [id];
+ }
+ else {
+ ids = query.rawConditions.id;
+ // Mapreduce for the list of ids
+ if (!ids) {
+ ids = [];
+ this.load(query, function (err, items) {
+ if (err) {
+ callback(err, null);
+ }
+ else {
+ items.forEach(function (item) {
+ ids.push(item.id);
+ });
+ }
+ });
+ }
+ }
+ ids.forEach(function (id) {
+ var item = _data[key][id];
+ item.updateProperties(data);
+ _data[key][id] = item;
+
+ });
+ callback(null, true);
+ };
+
+ this.remove = function (query, callback) {
+ var key = query.model.modelName
+ , id = query.byId
+ , ids;
+ if (id) {
+ ids = [id];
+ }
+ else {
+ ids = query.rawConditions.id;
+ // Mapreduce for the list of ids
+ if (!ids) {
+ ids = [];
+ this.load(query, function (err, items) {
+ if (err) {
+ callback(err, null);
+ }
+ else {
+ items.forEach(function (item) {
+ ids.push(item.id);
+ });
+ }
+ });
+ }
+ }
+ ids.forEach(function (id) {
+ delete _data[key][id];
+ });
+ callback(null, true);
+ };
+
+ this.insert = function (data, opts, callback) {
+ var items = Array.isArray(data) ? data.slice() : [data]
+ , key = items[0].type;
+ items.forEach(function (item) {
+ var id = utils.string.uuid();
+ item.id = id;
+ item._saved = true;
+ _data[key][id] = item;
+ });
+ callback(null, true);
+ }
+
+ this.createTable = function (names, callback) {
+ var arr = Array.isArray(names) ? names.slice() : [names];
+ arr.forEach(function (item) {
+ _data[item] = {};
+ });
+ callback(null, true);
+ };
+
+ this.dropTable = function (names, callback) {
+ var arr = Array.isArray(names) ? names.slice() : [names];
+ arr.forEach(function (item) {
+ delete _data[item];
+ });
+ callback(null, true);
+ };
+
+})());
+
+utils.mixin(Adapter.prototype, mr);
+
+module.exports.Adapter = Adapter;
+
View
15 lib/adapters/riak/index.js
@@ -38,7 +38,7 @@ _bucketizeModelName = function (name) {
// This function is special -- its source is transformed into
// a JSON-safe string and posted as the reduce-sort to Riak
-_reduceFunction = function (values, arg) {
+_reduceFunction = function (values) {
// Dummy value to replace with real sort data -- will look
// like {'foo': 'asc', 'bar': 'desc'}
var sort = '__sort__'
@@ -81,15 +81,7 @@ _mapReduceQuery = function (bucket, conditions, sort) {
// function-source into a JSON-safe string
// 2. Insert the actual sort info, replace the dummy __sort__
if (sort) {
- reduceSource = _reduceFunction.toString() // Get the function source
- // Strip comments
- .replace(/\/\/.*(\n)/g, '')
- // Strip linebreaks
- .replace(/\n/g, ' ')
- // Reduce multiple spaces to single space
- .replace(/ {2,}/g, ' ')
- // Replace placeholder with real sort, e.g., {'foo': 'asc'}
- .replace('\'__sort__\'', sort);
+ reduceSource = sort.toString(); // Get the function source
reduce = ', {"reduce": {"language": "javascript", "source": "' +
reduceSource + '"}}';
}
@@ -197,6 +189,7 @@ utils.mixin(Adapter.prototype, new (function () {
}
};
+ // TODO: Eventually should update properties instead of simple overwrite
this.update = function (data, query, callback) {
var bucket = _bucketizeModelName(query.model.modelName)
, id = query.byId
@@ -299,7 +292,7 @@ utils.mixin(Adapter.prototype, new (function () {
}
else {
items.forEach(function (item) {
- id.push(item.id);
+ ids.push(item.id);
});
remove();
}
View
65 lib/adapters/transformers/mr.js
@@ -1,7 +1,8 @@
var operation = require('../../query/operation')
, comparison = require('../../query/comparison')
, datatypes = require('../../datatypes')
- , _serializeForDataType;
+ , _serializeForDataType
+ , _sortFunction;
_serializeForDataType = function (datatype, val) {
var ret;
@@ -24,6 +25,44 @@ _serializeForDataType = function (datatype, val) {
return ret;
};
+// This function is special -- its source is transformed by
+// replacing the __sort__ variable. It's also converted into
+// a JSON-safe string in the Riak adapter and posted as the
+// reduce-sort
+_sortFunction = function (values) {
+ // Dummy value to replace with real sort data -- will look
+ // like {'foo': 'asc', 'bar': 'desc'}
+ var sort = '__sort__'
+ // Directional sort, returns explicit zero if equal
+ , baseSort = function (a, b, dir) {
+ if (a == b) {
+ return 0;
+ }
+ if (dir == 'asc') {
+ return a > b ? 1 : -1;
+ }
+ else {
+ return a > b ? -1 : 1;
+ }
+ }
+ // Iterates each of the sort columns until it finds a
+ // pair of values that are not the same
+ , columnSort = function (a, b) {
+ var ret;
+ for (var p in sort) {
+ // Call the directional sort for the two values
+ // in this property
+ ret = baseSort(a[p], b[p], sort[p]);
+ // -1 and 1 are truthy
+ if (ret) {
+ return ret;
+ }
+ }
+ return 1;
+ };
+ return values.sort(columnSort);
+};
+
var mr = new (function () {
var _operationSymbols = {
@@ -32,7 +71,29 @@ var mr = new (function () {
};
this.transformSortOrder = function (sort) {
- return sort ? JSON.stringify(sort).replace(/"/g, "'") : '';
+ var sortString
+ , sortSource;
+
+ if (!sort) {
+ return null;
+ }
+
+ sortString = JSON.stringify(sort).replace(/"/g, "'")
+ sortSource = _sortFunction.toString()
+ // Strip comments
+ .replace(/\/\/.*(\n)/g, '')
+ // Strip linebreaks
+ .replace(/\n/g, ' ')
+ // Reduce multiple spaces to single space
+ .replace(/ {2,}/g, ' ')
+ // Replace placeholder with real sort, e.g., {'foo': 'asc'}
+ .replace('\'__sort__\'', sortString);
+
+ // Get the function body
+ sortSource = sortSource.replace('function (values) { ', '');
+ sortSource = sortSource.substr(0, sortSource.length - 1);
+
+ return new Function('values', sortSource);
};
this.transformConditions = function (conditions) {
View
43 test/adapters/memory/index.js
@@ -0,0 +1,43 @@
+var utils = require('utilities')
+ , model = require('../../../lib')
+ , Adapter = require('../../../lib/adapters/memory').Adapter
+ , adapter
+ , assert = require('assert')
+ , tests
+ , Zooby = require('../../fixtures/zooby').Zooby
+ , User = require('../../fixtures/user').User
+ , Profile = require('../../fixtures/profile').Profile
+ , Account = require('../../fixtures/account').Account
+ , shared = require('../shared');
+
+tests = {
+ 'before': function (next) {
+ adapter = new Adapter();
+
+ model.adapters = {
+ 'Zooby': adapter
+ , 'User': adapter
+ , 'Profile': adapter
+ , 'Account': adapter
+ };
+
+ adapter.createTable(Object.keys(model.adapters), next)
+ }
+
+, 'after': function () {
+ }
+
+, 'test create adapter': function () {
+ assert.ok(adapter instanceof Adapter);
+ }
+
+
+};
+
+for (var p in shared) {
+ tests[p + ' (Memory)'] = shared[p];
+}
+
+module.exports = tests;
+
+
View
3  test/adapters/mongo/index.js
@@ -1,13 +1,10 @@
var utils = require('utilities')
, model = require('../../../lib')
, Adapter = require('../../../lib/adapters/mongo').Adapter
- , Query = require('../../../lib/query/query').Query
, generator = require('../../../lib/generators/sql')
, adapter
, assert = require('assert')
- , currentId
, tests
- , testItems = []
, Zooby = require('../../fixtures/zooby').Zooby
, User = require('../../fixtures/user').User
, Profile = require('../../fixtures/profile').Profile
View
11 test/adapters/sql/postgres.js
@@ -1,17 +1,6 @@
-/*
-Notes:
-id, createdAt, updatedAt are auto-fields -- if not defined, handle
- transparently. If defined, make sure it's present and valid before using
-
-Allow auto-increment setting for id
-
-Relies on 'saved' property to know if an instanced is new or existing
-*/
-
var utils = require('utilities')
, model = require('../../../lib')
, Adapter = require('../../../lib/adapters/sql/postgres').Adapter
- , Query = require('../../../lib/query/query').Query
, generator = require('../../../lib/generators/sql')
, adapter
, assert = require('assert')
Please sign in to comment.
Something went wrong with that request. Please try again.