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 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();
|
||||||
|
@ -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"
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user