Smart objects collection.

This commit is contained in:
Julien Fontanet 2015-02-10 14:42:56 +01:00
parent da99f3bc2a
commit f1d359b3e7
3 changed files with 173 additions and 7 deletions

View File

@ -0,0 +1,141 @@
'use strict';
//====================================================================
var forEach = require('lodash.foreach');
var indexOf = require('lodash.indexof');
//====================================================================
function defaultKey(item) {
return item.id || item._id || item;
}
//====================================================================
function Collection(opts) {
if (!opts) {
opts = {};
}
this._key = opts.key || defaultKey;
this._indexes = Object.create(null);
if (opts.indexes) {
forEach(opts.indexes, function (field) {
this[field] = Object.create(null);
}, this._indexes);
}
this._data = Object.create(null);
}
function createIndex(_, field) {
/* jshint validthis: true */
this[field] = Object.create(null);
}
Collection.prototype.clear = function () {
this._data = Object.create(null);
forEach(this._indexes, createIndex, this._indexes);
};
Collection.prototype.get = function (key) {
return this._data[key];
};
Collection.prototype.where = function (field, value) {
var index = this._indexes[field];
if (!index) {
throw new Error('no such index');
}
return index[value];
};
function unsetItemFromIndex(index, field) {
/* jshint validthis: true */
var prop = this[field];
if (!prop) {
return;
}
var items = index[prop];
var i = indexOf(items, this);
if (i === -1) {
return;
}
// The index contains only this one item for this prop.
if (items.length === 1) {
delete index[prop];
return;
}
// Remove this item.
items.splice(i, 1);
}
// Internal unset method.
function unset(item, key) {
/* jshint validthis: true */
delete this._data[key];
forEach(this._indexes, unsetItemFromIndex, item);
}
function setItemToIndex(index, field) {
/* jshint validthis: true */
var prop = this[field];
if (!prop) {
return;
}
var items = index[prop];
if (items) {
// Update the items list.
items.push(this);
} else {
// Create the items list.
index[prop] = [this];
}
}
Collection.prototype.set = function (item) {
var key = this._key(item);
if (!key) {
// Ignore empty keys.
return;
}
var previous = this._data[key];
if (previous) {
unset.call(this, previous, key);
}
this._data[key] = item;
forEach(this._indexes, setItemToIndex, item);
};
Collection.prototype.unset = function (item) {
unset.call(this, item, this._key(item));
};
Collection.prototype.setMultiple = function (items) {
forEach(items, this.set, this);
};
Collection.prototype.unsetMultiple = function (items) {
forEach(items, this.unset, this);
};
//====================================================================
function createCollection(opts) {
return new Collection(opts);
}
module.exports = createCollection;

View File

@ -11,6 +11,8 @@ var makeError = require('make-error');
var MethodNotFound = require('json-rpc/errors').MethodNotFound; var MethodNotFound = require('json-rpc/errors').MethodNotFound;
var WebSocket = require('ws'); var WebSocket = require('ws');
var createCollection = require('./collection');
//==================================================================== //====================================================================
function makeDeferred() { function makeDeferred() {
@ -178,7 +180,16 @@ exports.Api = Api;
//==================================================================== //====================================================================
var objectsOptions = {
indexes: [
'ref',
'type',
'UUID',
],
key: function (item) {
return item.UUID || item.ref;
},
};
// High level interface to Xo. // High level interface to Xo.
// //
@ -189,7 +200,7 @@ function Xo(opts) {
this._api = new Api(opts.url); this._api = new Api(opts.url);
this._auth = opts.auth; this._auth = opts.auth;
this._backOff = fibonacci(1e3); this._backOff = fibonacci(1e3);
this._objects = Object.create(null); this.objects = createCollection(objectsOptions);
this.user = null; this.user = null;
// Promise representing the connection status. // Promise representing the connection status.
@ -200,17 +211,19 @@ function Xo(opts) {
email: self._auth.email, email: self._auth.email,
password: self._auth.password, password: self._auth.password,
}).then(function (user) { }).then(function (user) {
this.user = user; self.user = user;
return self._api.call('xo.getAllObjects'); return self._api.call('xo.getAllObjects');
}).then(function (objects) { }).then(function (objects) {
self._objects = objects; self.objects.setMultiple(objects);
}); });
return self._connection;
}; };
self._api.on('disconnected', function () { self._api.on('disconnected', function () {
self._connection = null; self._connection = null;
self._objects = Object.create(null); self.objects.clear();
}); });
self._api.on('notification', function (notification) { self._api.on('notification', function (notification) {
@ -218,14 +231,23 @@ function Xo(opts) {
return; return;
} }
var method = (
notification.params.type === 'exit' ?
'unset' :
'set'
) + 'Multiple';
self.objects[method](notification.params.items);
}); });
} }
assign(Xo.prototype, { assign(Xo.prototype, {
connect: function () { connect: function () {
var self = this; if (this._connection) {
return this._connection;
}
var self = this;
return this._api.connect().then(this._onConnection).catch(function () { return this._api.connect().then(this._onConnection).catch(function () {
return Bluebird.delay(self._backOff.next().value).then(function () { return Bluebird.delay(self._backOff.next().value).then(function () {
return self.connect(); return self.connect();

View File

@ -22,12 +22,15 @@
"test": "mocha index.spec.js" "test": "mocha index.spec.js"
}, },
"files": [ "files": [
"index.js" "index.js",
"collection.js"
], ],
"dependencies": { "dependencies": {
"bluebird": "^2.9.6", "bluebird": "^2.9.6",
"json-rpc": "git://github.com/julien-f/js-json-rpc", "json-rpc": "git://github.com/julien-f/js-json-rpc",
"lodash.assign": "^3.0.0", "lodash.assign": "^3.0.0",
"lodash.foreach": "^3.0.1",
"lodash.indexof": "^3.0.0",
"make-error": "^0.3.0", "make-error": "^0.3.0",
"ws": "^0.7.1" "ws": "^0.7.1"
}, },