Smart objects collection.
This commit is contained in:
parent
da99f3bc2a
commit
f1d359b3e7
141
packages/xo-lib/collection.js
Normal file
141
packages/xo-lib/collection.js
Normal 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;
|
@ -11,6 +11,8 @@ var makeError = require('make-error');
|
||||
var MethodNotFound = require('json-rpc/errors').MethodNotFound;
|
||||
var WebSocket = require('ws');
|
||||
|
||||
var createCollection = require('./collection');
|
||||
|
||||
//====================================================================
|
||||
|
||||
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.
|
||||
//
|
||||
@ -189,7 +200,7 @@ function Xo(opts) {
|
||||
this._api = new Api(opts.url);
|
||||
this._auth = opts.auth;
|
||||
this._backOff = fibonacci(1e3);
|
||||
this._objects = Object.create(null);
|
||||
this.objects = createCollection(objectsOptions);
|
||||
this.user = null;
|
||||
|
||||
// Promise representing the connection status.
|
||||
@ -200,17 +211,19 @@ function Xo(opts) {
|
||||
email: self._auth.email,
|
||||
password: self._auth.password,
|
||||
}).then(function (user) {
|
||||
this.user = user;
|
||||
self.user = user;
|
||||
|
||||
return self._api.call('xo.getAllObjects');
|
||||
}).then(function (objects) {
|
||||
self._objects = objects;
|
||||
self.objects.setMultiple(objects);
|
||||
});
|
||||
|
||||
return self._connection;
|
||||
};
|
||||
|
||||
self._api.on('disconnected', function () {
|
||||
self._connection = null;
|
||||
self._objects = Object.create(null);
|
||||
self.objects.clear();
|
||||
});
|
||||
|
||||
self._api.on('notification', function (notification) {
|
||||
@ -218,14 +231,23 @@ function Xo(opts) {
|
||||
return;
|
||||
}
|
||||
|
||||
var method = (
|
||||
notification.params.type === 'exit' ?
|
||||
'unset' :
|
||||
'set'
|
||||
) + 'Multiple';
|
||||
|
||||
self.objects[method](notification.params.items);
|
||||
});
|
||||
}
|
||||
|
||||
assign(Xo.prototype, {
|
||||
connect: function () {
|
||||
var self = this;
|
||||
if (this._connection) {
|
||||
return this._connection;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
return this._api.connect().then(this._onConnection).catch(function () {
|
||||
return Bluebird.delay(self._backOff.next().value).then(function () {
|
||||
return self.connect();
|
||||
|
@ -22,12 +22,15 @@
|
||||
"test": "mocha index.spec.js"
|
||||
},
|
||||
"files": [
|
||||
"index.js"
|
||||
"index.js",
|
||||
"collection.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"bluebird": "^2.9.6",
|
||||
"json-rpc": "git://github.com/julien-f/js-json-rpc",
|
||||
"lodash.assign": "^3.0.0",
|
||||
"lodash.foreach": "^3.0.1",
|
||||
"lodash.indexof": "^3.0.0",
|
||||
"make-error": "^0.3.0",
|
||||
"ws": "^0.7.1"
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user