2017-01-10 18:05:01 +01:00
|
|
|
# xo-collection [](https://travis-ci.org/vatesfr/xen-orchestra)
|
2015-04-07 18:01:33 +02:00
|
|
|
|
|
|
|
|
> Generic in-memory collection with events
|
|
|
|
|
|
|
|
|
|
## Install
|
|
|
|
|
|
2015-04-10 11:51:54 +02:00
|
|
|
Installation of the [npm package](https://npmjs.org/package/xo-collection):
|
2015-04-07 18:01:33 +02:00
|
|
|
|
|
|
|
|
```
|
2015-04-10 11:51:54 +02:00
|
|
|
> npm install --save xo-collection
|
2015-04-07 18:01:33 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Usage
|
|
|
|
|
|
|
|
|
|
```javascript
|
2015-04-10 11:51:54 +02:00
|
|
|
var Collection = require('xo-collection')
|
2015-04-07 18:01:33 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Creation
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
// Creates a new collection.
|
|
|
|
|
var col = new Collection()
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Manipulation
|
|
|
|
|
|
2015-04-08 11:49:25 +02:00
|
|
|
**Inserting a new item**
|
2015-04-07 18:01:33 +02:00
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
col.add('foo', true)
|
|
|
|
|
```
|
|
|
|
|
|
2015-05-19 15:25:44 +02:00
|
|
|
- **Throws** `DuplicateItem` if the item is already in the collection.
|
|
|
|
|
|
2015-04-08 11:49:25 +02:00
|
|
|
**Updating an existing item**
|
2015-04-07 18:01:33 +02:00
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
col.update('foo', false)
|
|
|
|
|
```
|
|
|
|
|
|
2015-05-19 15:25:44 +02:00
|
|
|
- **Throws** `NoSuchItem` if the item is not in the collection.
|
|
|
|
|
|
2015-04-08 11:49:25 +02:00
|
|
|
**Inserting or updating an item**
|
2015-04-07 18:01:33 +02:00
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
col.set('bar', true)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Notifying an external update**
|
|
|
|
|
|
2015-04-08 11:49:25 +02:00
|
|
|
> If an item is an object, it can be updated directly without using
|
2015-04-07 18:01:33 +02:00
|
|
|
> the `set`/`update` methods.
|
|
|
|
|
>
|
2015-04-07 18:06:17 +02:00
|
|
|
> To make sure the collection stays in sync and the correct events are
|
2015-04-07 18:01:33 +02:00
|
|
|
> sent, the `touch` method can be used to notify the change.
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
var baz = {}
|
|
|
|
|
|
|
|
|
|
col.add('baz', baz)
|
|
|
|
|
|
|
|
|
|
baz.prop = true
|
|
|
|
|
col.touch('baz')
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-08 11:49:25 +02:00
|
|
|
> Because this is a much used pattern, `touch` returns the item to
|
2015-04-07 18:01:33 +02:00
|
|
|
> allow its direct modification.
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
col.touch('baz').prop = false
|
|
|
|
|
```
|
|
|
|
|
|
2015-05-19 15:25:44 +02:00
|
|
|
- **Throws** `NoSuchItem` if the item is not in the collection.
|
|
|
|
|
- **Throws** `IllegalTouch` if the item is not an object.
|
|
|
|
|
|
2015-04-08 11:49:25 +02:00
|
|
|
**Removing an existing item**
|
2015-04-07 18:01:33 +02:00
|
|
|
|
|
|
|
|
```javascript
|
2015-04-07 18:49:20 +02:00
|
|
|
col.remove('bar')
|
2015-04-07 18:01:33 +02:00
|
|
|
```
|
|
|
|
|
|
2015-05-19 15:25:44 +02:00
|
|
|
- **Throws** `NoSuchItem` if the item is not in the collection.
|
|
|
|
|
|
2015-06-26 11:20:50 +02:00
|
|
|
**Removing an item without error**
|
|
|
|
|
|
|
|
|
|
This is the symmetric method of `set()`: it removes the item if it
|
|
|
|
|
exists otherwise does nothing.
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
col.unset('bar')
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-08 11:49:25 +02:00
|
|
|
**Removing all items**
|
2015-04-07 18:01:33 +02:00
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
col.clear()
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Query
|
|
|
|
|
|
2015-04-08 11:49:25 +02:00
|
|
|
**Checking the existence of an item**
|
2015-04-07 18:01:33 +02:00
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
var hasBar = col.has('bar')
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-08 11:49:25 +02:00
|
|
|
**Getting an existing item**
|
2015-04-07 18:01:33 +02:00
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
var foo = col.get('foo')
|
|
|
|
|
|
|
|
|
|
// The second parameter can be used to specify a fallback in case the
|
2015-04-08 11:49:25 +02:00
|
|
|
// item does not exist.
|
2015-04-07 18:01:33 +02:00
|
|
|
var bar = col.get('bar', 6.28)
|
|
|
|
|
```
|
|
|
|
|
|
2015-05-19 15:25:44 +02:00
|
|
|
- **Throws** `NoSuchItem` if the item is not in the collection and no
|
|
|
|
|
fallback has been passed.
|
|
|
|
|
|
2015-04-07 18:15:38 +02:00
|
|
|
**Getting a read-only view of the collection**
|
|
|
|
|
|
|
|
|
|
> This property is useful for example to iterate over the collection
|
|
|
|
|
> or to make advanced queries with the help of utility libraries such
|
|
|
|
|
> as lodash.
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
var _ = require('lodash')
|
|
|
|
|
|
2015-04-08 11:49:25 +02:00
|
|
|
// Prints all the items.
|
2015-04-07 18:15:38 +02:00
|
|
|
_.forEach(col.all, function (value, key) {
|
|
|
|
|
console.log('- %s: %j', key, value)
|
|
|
|
|
})
|
|
|
|
|
|
2015-04-08 11:49:25 +02:00
|
|
|
// Finds all the items which are objects and have a property
|
2015-04-07 18:15:38 +02:00
|
|
|
// `active` which equals `true`.
|
|
|
|
|
var results = _.where(col.all, { active: true })
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-08 11:49:25 +02:00
|
|
|
**Getting the number of items**
|
2015-04-07 18:01:33 +02:00
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
var size = col.size
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Events
|
|
|
|
|
|
|
|
|
|
> The events are emitted asynchronously (at the next turn/tick of the
|
|
|
|
|
> event loop) and are deduplicated which means, for instance, that an
|
|
|
|
|
> addition followed by an update will result only in a single
|
|
|
|
|
> addition.
|
|
|
|
|
|
2015-04-08 11:49:25 +02:00
|
|
|
**New items**
|
2015-04-07 18:01:33 +02:00
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
col.on('add', (added) => {
|
|
|
|
|
forEach(added, (value, key) => {
|
|
|
|
|
console.log('+ %s: %j', key, value)
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-08 11:49:25 +02:00
|
|
|
**Updated items**
|
2015-04-07 18:01:33 +02:00
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
col.on('update', (updated) => {
|
|
|
|
|
forEach(updated, (value, key) => {
|
2015-04-08 10:04:58 +02:00
|
|
|
console.log('± %s: %j', key, value)
|
2015-04-07 18:01:33 +02:00
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-08 11:49:25 +02:00
|
|
|
**Removed items**
|
2015-04-07 18:01:33 +02:00
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
col.on('remove', (removed) => {
|
2015-04-08 10:04:58 +02:00
|
|
|
// For consistency, `removed` is also a map but contrary to `added`
|
2015-04-07 18:01:33 +02:00
|
|
|
// and `updated`, the values associated to the keys are not
|
2015-04-08 11:49:25 +02:00
|
|
|
// significant since the items have already be removed.
|
2015-04-07 18:01:33 +02:00
|
|
|
|
|
|
|
|
forEach(removed, (value, key) => {
|
2015-04-08 10:04:58 +02:00
|
|
|
console.log('- %s', key)
|
2015-04-07 18:01:33 +02:00
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
2015-05-19 15:25:30 +02:00
|
|
|
**End of update**
|
|
|
|
|
|
|
|
|
|
> Emitted when all the update process is finished and all the update
|
|
|
|
|
> events has been emitted.
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
col.on('finish', () => {
|
|
|
|
|
console.log('the collection has been updated')
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-18 22:33:32 +02:00
|
|
|
### Iteration
|
|
|
|
|
|
|
|
|
|
```javascript
|
2015-10-01 18:25:01 +02:00
|
|
|
for (const [key, value] of col) {
|
2015-04-18 22:33:32 +02:00
|
|
|
console.log('- %s: %j', key, value)
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-01 18:25:01 +02:00
|
|
|
for (const key of col.keys()) {
|
2015-04-18 22:33:32 +02:00
|
|
|
console.log('- %s', key)
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-01 18:25:01 +02:00
|
|
|
for (const value of col.values()) {
|
2015-04-18 22:33:32 +02:00
|
|
|
console.log('- %j', value)
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-28 17:06:37 +02:00
|
|
|
### Views
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
const View = require('xo-collection/view')
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
> A view is a read-only collection which contains only the items of a
|
|
|
|
|
> parent collection which satisfy a predicate.
|
|
|
|
|
>
|
|
|
|
|
> It is updated at most once per turn of the event loop and therefore
|
|
|
|
|
> can be briefly invalid.
|
|
|
|
|
|
|
|
|
|
```javascript
|
|
|
|
|
const myView = new View(parentCollection, function predicate (value, key) {
|
|
|
|
|
// This function should return a boolean indicating whether the
|
|
|
|
|
// current item should be in this view.
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
2015-04-07 18:01:33 +02:00
|
|
|
## Development
|
|
|
|
|
|
|
|
|
|
```
|
2016-11-02 15:03:45 +01:00
|
|
|
# Install dependencies
|
2015-04-07 18:01:33 +02:00
|
|
|
> npm install
|
|
|
|
|
|
2016-11-02 15:03:45 +01:00
|
|
|
# Run the tests
|
|
|
|
|
> npm test
|
2015-04-07 18:01:33 +02:00
|
|
|
|
2016-11-02 15:03:45 +01:00
|
|
|
# Continuously compile
|
2015-04-07 18:01:33 +02:00
|
|
|
> npm run dev
|
|
|
|
|
|
2016-11-02 15:03:45 +01:00
|
|
|
# Continuously run the tests
|
|
|
|
|
> npm run dev-test
|
2015-04-07 18:01:33 +02:00
|
|
|
|
2016-11-02 15:03:45 +01:00
|
|
|
# Build for production (automatically called by npm install)
|
|
|
|
|
> npm run build
|
2015-04-07 18:01:33 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Contributions
|
|
|
|
|
|
|
|
|
|
Contributions are *very* welcomed, either on the documentation or on
|
|
|
|
|
the code.
|
|
|
|
|
|
|
|
|
|
You may:
|
|
|
|
|
|
2018-02-07 10:40:09 +01:00
|
|
|
- report any [issue](https://github.com/vatesfr/xen-orchestra/issues)
|
2015-04-07 18:01:33 +02:00
|
|
|
you've encountered;
|
|
|
|
|
- fork and create a pull request.
|
|
|
|
|
|
|
|
|
|
## License
|
|
|
|
|
|
|
|
|
|
ISC © [Vates SAS](http://vates.fr)
|