First main methods. No events, no buffer yet
This commit is contained in:
parent
48d9fde3b6
commit
265d77d776
@ -1,499 +1,195 @@
|
||||
import makeError from 'make-error';
|
||||
|
||||
const IllegalId = makeError('IllegalId');
|
||||
const OverrideViolation = makeError('OverrideViolation');
|
||||
const NotFound = makeError('NotFound');
|
||||
const TransactionAlreadyOpened = makeError('TransactionAlreadyOpened');
|
||||
const NoTransactionOpened = makeError('NoTransactionOpened');
|
||||
const FailedRollback = makeError('FailedRollback');
|
||||
const FailedReplay = makeError('FailedReplay');
|
||||
const UnrecognizedTransactionItem = makeError('UnrecognizedTransactionItem');
|
||||
const UnexpectedLogFormat = makeError('UnexpectedLogFormat');
|
||||
const UnexpectedLogItemData = makeError('UnexpectedLogItemData');
|
||||
const AlreadyPaused = makeError('AlreadyPaused');
|
||||
const NothingToFlush = makeError('NothingToFlush');
|
||||
const AlreadyBuffering = makeError('AlreadyBuffering');
|
||||
const NotBuffering = makeError('NotBuffering');
|
||||
const IllegalAdd = makeError('IllegalAdd');
|
||||
const DuplicateEntry = makeError('DuplicateEntry');
|
||||
const NoSuchEntry = makeError('NoSuchEntry');
|
||||
|
||||
class Collection {
|
||||
|
||||
constructor() {
|
||||
constructor () {
|
||||
|
||||
this._collection = {};
|
||||
this._transaction = null;
|
||||
this._track = [];
|
||||
this._pause = false;
|
||||
this._map = {};
|
||||
this._buffering = false;
|
||||
this._size = 0;
|
||||
|
||||
}
|
||||
|
||||
pause() {
|
||||
_initBuffer () {
|
||||
|
||||
if (this._pause) {
|
||||
throw new AlreadyPaused('Already paused');
|
||||
this._buffer = {
|
||||
remove: [],
|
||||
add: [],
|
||||
update: []
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
bufferChanges (state = true) {
|
||||
|
||||
if (state && this._buffer) {
|
||||
throw new AlreadyBuffering('Already buffering'); // FIXME Really ?...
|
||||
}
|
||||
this._pause = true;
|
||||
|
||||
}
|
||||
|
||||
flush(callback = undefined) {
|
||||
|
||||
if (!this._pause) {
|
||||
throw new NothingToFlush('NothingToFlush');
|
||||
if (!state && !this._buffer) {
|
||||
throw new NotBuffering('Not buffering'); // FIXME Really ?...
|
||||
}
|
||||
this._buffer = state;
|
||||
|
||||
this._pause = false;
|
||||
let track = this._track;
|
||||
this._track = [];
|
||||
|
||||
return this.replay(track, callback);
|
||||
|
||||
}
|
||||
|
||||
begin(callback = undefined) {
|
||||
|
||||
try {
|
||||
|
||||
if (null !== this._transaction) {
|
||||
throw new TransactionAlreadyOpened('A transaction is already opened');
|
||||
}
|
||||
|
||||
this._transaction = [];
|
||||
|
||||
if ('function' === typeof callback) {
|
||||
callback(null, this);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if ('function' === typeof callback) {
|
||||
callback(err);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
|
||||
if (!this._buffer) {
|
||||
this._initBuffer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
commit(callback = undefined) {
|
||||
flush () {
|
||||
|
||||
try {
|
||||
if (!this._buffer) {
|
||||
throw new NotBuffering('NothingToFlush');
|
||||
}
|
||||
|
||||
if (null === this._transaction) {
|
||||
throw new NoTransactionOpened('No opened transaction to commit.');
|
||||
}
|
||||
this._buffering = false; // FIXME Really ?
|
||||
|
||||
const transactionLog = this._transaction;
|
||||
this._transaction = null;
|
||||
// TODO Throws buffered events
|
||||
|
||||
if ('function' === typeof callback) {
|
||||
callback(null, transactionLog);
|
||||
this._initBuffer();
|
||||
|
||||
}
|
||||
|
||||
_touch (key, action) {
|
||||
|
||||
// TODO Buffers changes or throws an event
|
||||
|
||||
}
|
||||
|
||||
_set (key, value) {
|
||||
|
||||
this._map[key] = value;
|
||||
this._touch(key, 'update');
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
_unset (key) {
|
||||
|
||||
delete this._map[key];
|
||||
this._touch(key, 'remove');
|
||||
return this;
|
||||
}
|
||||
|
||||
getId (item) {
|
||||
return item.id;
|
||||
}
|
||||
|
||||
has (key) {
|
||||
|
||||
return this._map.hasOwnProperty(key);
|
||||
|
||||
}
|
||||
|
||||
resolveEntry (keyOrObjectWithId, valueIfKey = null) {
|
||||
|
||||
let value;
|
||||
let key = (undefined !== keyOrObjectWithId) ?
|
||||
this.getId(keyOrObjectWithId) :
|
||||
undefined;
|
||||
|
||||
if (undefined === key) {
|
||||
if (arguments.length < 2) {
|
||||
throw new IllegalAdd();
|
||||
} else {
|
||||
return transactionLog;
|
||||
key = keyOrObjectWithId;
|
||||
value = valueIfKey;
|
||||
}
|
||||
} else {
|
||||
value = keyOrObjectWithId;
|
||||
}
|
||||
|
||||
return [key, value];
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if ('function' === typeof callback) {
|
||||
callback(err);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
_assertHas(key) {
|
||||
|
||||
if (!this.has(key)) {
|
||||
throw new NoSuchEntry();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rollback(callback = undefined) {
|
||||
|
||||
try {
|
||||
|
||||
if (null === this._transaction) {
|
||||
throw new NoTransactionOpened('No opened transaction to rollback.');
|
||||
}
|
||||
|
||||
const log = this._transaction;
|
||||
this._transaction = null;
|
||||
|
||||
return this._rollback(log, callback);
|
||||
|
||||
} catch(err) {
|
||||
|
||||
if ('function' === typeof callback) {
|
||||
callback(err);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
_assertNotHas(key) {
|
||||
|
||||
if (this.has(key)) {
|
||||
throw new DuplicateEntry();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_rollback(log, callback = undefined) {
|
||||
add (keyOrObjectWithId, valueIfKey = null) {
|
||||
|
||||
try {
|
||||
const [key, value] = this.resolveEntry.apply(this, arguments);
|
||||
|
||||
if (!Array.isArray(log)) {
|
||||
throw new UnexpectedLogFormat('A transaction log must be an Array.');
|
||||
}
|
||||
this._assertNotHas(key);
|
||||
this._size++;
|
||||
|
||||
let item;
|
||||
const done = [];
|
||||
return this._set(key, value);
|
||||
|
||||
while(item = log.pop()) {
|
||||
try {
|
||||
}
|
||||
|
||||
this.checkLogItem(item);
|
||||
set (keyOrObjectWithId, valueIfKey = null) {
|
||||
|
||||
switch (item.action) {
|
||||
case 'insert':
|
||||
this.delete(item.id);
|
||||
break;
|
||||
case 'update':
|
||||
this.update(item.id, item.former);
|
||||
break;
|
||||
case 'delete':
|
||||
this.insert(item.id, item.former);
|
||||
break;
|
||||
default:
|
||||
throw new UnrecognizedTransactionItem(
|
||||
'Unrecognized item action : "' + item.action +
|
||||
'" at index ' + log.lenght + '.'
|
||||
);
|
||||
}
|
||||
|
||||
done.unshift(item);
|
||||
} catch(err) {
|
||||
const exc = new FailedRollback(
|
||||
'Rollback failed on index ' + log.lenght + '.'
|
||||
);
|
||||
exc.undone = log;
|
||||
exc.done = done;
|
||||
exc.internal = err;
|
||||
exc.failedAction = item;
|
||||
exc.index = log.lenght;
|
||||
throw exc;
|
||||
}
|
||||
}
|
||||
|
||||
if ('function' === typeof callback) {
|
||||
callback(null, this);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
|
||||
} catch(err) {
|
||||
|
||||
if ('function' === typeof callback) {
|
||||
callback(err);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
const [key, value] = this.resolveEntry.apply(this, arguments);
|
||||
|
||||
if (!this.has(key)) {
|
||||
this._size++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
replay(log, callback = undefined) {
|
||||
|
||||
try {
|
||||
|
||||
if (!Array.isArray(log)) {
|
||||
throw new UnexpectedLogFormat('A transaction log must be an Array.');
|
||||
}
|
||||
|
||||
let item;
|
||||
const done = [];
|
||||
|
||||
while(item = log.shift()) {
|
||||
try {
|
||||
|
||||
this.checkLogItem(item);
|
||||
|
||||
switch (item.action) {
|
||||
case 'insert':
|
||||
this.insert(item.id, item.item);
|
||||
break;
|
||||
case 'update':
|
||||
this.update(item.id, item.item);
|
||||
break;
|
||||
case 'delete':
|
||||
this.delete(item.id);
|
||||
break;
|
||||
default:
|
||||
throw new UnrecognizedTransactionItem(
|
||||
'Unrecognized item action : "' + item.action +
|
||||
'" at index ' + done.lenght + '.'
|
||||
);
|
||||
}
|
||||
|
||||
done.push(item);
|
||||
} catch(err) {
|
||||
const exc = new FailedReplay(
|
||||
'Replay failed on index ' + done.lenght + '.'
|
||||
);
|
||||
exc.undone = log;
|
||||
exc.done = done;
|
||||
exc.internal = err;
|
||||
exc.failedAction = item;
|
||||
exc.index = done.lenght;
|
||||
throw exc;
|
||||
}
|
||||
}
|
||||
|
||||
if ('function' === typeof callback) {
|
||||
callback(null, this);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
|
||||
} catch(err) {
|
||||
|
||||
if ('function' === typeof callback) {
|
||||
callback(err);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
|
||||
}
|
||||
return this._set(key, value);
|
||||
|
||||
}
|
||||
|
||||
checkLogItem (item) {
|
||||
get (key) {
|
||||
|
||||
if (!item.hasOwnProperty('id')) {
|
||||
throw new UnexpectedLogItemData(
|
||||
'Missing id for ' + item.action + ' object.'
|
||||
);
|
||||
}
|
||||
this._assertHas(key);
|
||||
|
||||
const checkFormer = () => {
|
||||
if (!item.hasOwnProperty('former')) {
|
||||
throw new UnexpectedLogItemData(
|
||||
'Missing former item in ' + item.action + ' object.'
|
||||
);
|
||||
}
|
||||
};
|
||||
return this._map[key];
|
||||
}
|
||||
|
||||
const checkItem = () => {
|
||||
if (!item.hasOwnProperty('item')) {
|
||||
throw new UnexpectedLogItemData(
|
||||
'Missing item in ' + item.action + ' object.'
|
||||
);
|
||||
}
|
||||
};
|
||||
update (keyOrObjectWithId, valueIfKey = null) {
|
||||
|
||||
switch (item.action) {
|
||||
const [key, value] = this.resolveEntry.apply(this, arguments);
|
||||
|
||||
case 'update':
|
||||
checkItem();
|
||||
case 'delete':
|
||||
checkFormer();
|
||||
break;
|
||||
case 'insert':
|
||||
checkItem();
|
||||
break;
|
||||
this._assertHas(key);
|
||||
|
||||
default:
|
||||
throw new UnrecognizedTransactionItem(
|
||||
'Unrecognizes item action : "' + item.action + '.'
|
||||
);
|
||||
}
|
||||
return this._set(key, value);
|
||||
|
||||
}
|
||||
|
||||
insert(id, item, callback = undefined) {
|
||||
remove (keyOrObjectWithId) {
|
||||
|
||||
try {
|
||||
const [key] = this.resolveEntry(keyOrObjectWithId, null);
|
||||
|
||||
this.checkId(id);
|
||||
this._assertHas(key);
|
||||
this._size--;
|
||||
|
||||
if (this._has(id)) {
|
||||
throw new OverrideViolation(
|
||||
'An insertion must not override the pre-existing id ' + id + '. ' +
|
||||
'Consider using update instead depending on your use case.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!this._pause) {
|
||||
this._collection[id] = item;
|
||||
}
|
||||
else {
|
||||
this._track.push({
|
||||
action: 'insert',
|
||||
id,
|
||||
item
|
||||
});
|
||||
}
|
||||
|
||||
if ('function' === typeof callback) {
|
||||
callback(null, this);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if ('function' === typeof callback) {
|
||||
callback(err);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
|
||||
}
|
||||
return this._unset(key);
|
||||
|
||||
}
|
||||
|
||||
update(id, item, callback = undefined) {
|
||||
|
||||
try {
|
||||
|
||||
this.checkId(id);
|
||||
|
||||
if (!this._has(id)) {
|
||||
throw new NotFound(
|
||||
'No item to update at id ' + id + '. ' +
|
||||
'Consider using insert instead depending on your usecase.'
|
||||
);
|
||||
}
|
||||
|
||||
const former = this._collection[id];
|
||||
|
||||
if (!this._pause) {
|
||||
this._collection[id] = item;
|
||||
} else {
|
||||
this._track.push({
|
||||
action: 'update',
|
||||
id,
|
||||
former,
|
||||
item
|
||||
});
|
||||
}
|
||||
|
||||
if ('function' === typeof callback) {
|
||||
callback(null, this);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if ('function' === typeof callback) {
|
||||
callback(err);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
get size () {
|
||||
return this._size;
|
||||
}
|
||||
|
||||
delete(id, callback = undefined) {
|
||||
|
||||
try {
|
||||
|
||||
this.checkId(id);
|
||||
|
||||
if (!this._has(id)) {
|
||||
throw new NotFound(
|
||||
'No item to remove at id' + id + '.'
|
||||
);
|
||||
}
|
||||
|
||||
const former = this._collection[id];
|
||||
|
||||
if (!this._pause) {
|
||||
delete this._collection[id];
|
||||
} else {
|
||||
this._track.push({
|
||||
action:'delete',
|
||||
id,
|
||||
former
|
||||
});
|
||||
}
|
||||
|
||||
if ('function' === typeof callback) {
|
||||
callback(null, this);
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if ('function' === typeof callback) {
|
||||
callback(err);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
get(id, callback = undefined) {
|
||||
|
||||
try {
|
||||
|
||||
this.checkId(id);
|
||||
|
||||
if (!this._has(id)) {
|
||||
throw new NotFound(
|
||||
'No item found at id ' + id
|
||||
);
|
||||
}
|
||||
|
||||
if ('function' === typeof callback) {
|
||||
callback(null, this._collection[id]);
|
||||
} else {
|
||||
return this._collection[id];
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if ('function' === typeof callback) {
|
||||
callback(err);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
checkId (id) {
|
||||
|
||||
if ('string' !== typeof id || id.length < 1) {
|
||||
throw new IllegalId('id must be a non-empty string');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
has(id) {
|
||||
|
||||
return this._has(this.checkId(id));
|
||||
|
||||
}
|
||||
|
||||
_has(id) {
|
||||
|
||||
return this._collection.hasOwnProperty(id);
|
||||
|
||||
get all () {
|
||||
return this._map;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default {
|
||||
Collection,
|
||||
IllegalId,
|
||||
OverrideViolation,
|
||||
NotFound,
|
||||
TransactionAlreadyOpened,
|
||||
NoTransactionOpened,
|
||||
FailedRollback,
|
||||
FailedReplay,
|
||||
UnrecognizedTransactionItem,
|
||||
UnexpectedLogFormat,
|
||||
UnexpectedLogItemData
|
||||
AlreadyBuffering,
|
||||
NotBuffering,
|
||||
IllegalAdd,
|
||||
DuplicateEntry,
|
||||
NoSuchEntry
|
||||
};
|
241
packages/xo-collection/collection.spec.js
Normal file
241
packages/xo-collection/collection.spec.js
Normal file
@ -0,0 +1,241 @@
|
||||
var chai = require('chai');
|
||||
var expect = chai.expect;
|
||||
var dirtyChai = require('dirty-chai');
|
||||
chai.use(dirtyChai);
|
||||
var leche = require('leche');
|
||||
|
||||
console.log(expect);
|
||||
|
||||
var Collection = require('./collection');
|
||||
|
||||
var col = new Collection.Collection();
|
||||
|
||||
describe('collection', function () {
|
||||
|
||||
// ============================================================
|
||||
|
||||
var fixtureValues1 = {
|
||||
'primitive value': ['foo1', 1],
|
||||
'array value': ['bar1', [1,2]],
|
||||
'object value': ['baz1', {a:1, b:2}]
|
||||
};
|
||||
|
||||
describe('add', function () {
|
||||
|
||||
leche.withData(fixtureValues1, function (key, value) {
|
||||
|
||||
it('Adds a new entry to the collection', function () {
|
||||
expect(col.add(key, value)).to.eql(col);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
leche.withData(fixtureValues1, function (key, value) {
|
||||
|
||||
it('We cannot add on a pre-existing key', function () {
|
||||
expect(function () {
|
||||
col.add(key, value);
|
||||
}).to.throw(Collection.DuplicateEntry);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
|
||||
var fixtureValues2 = {
|
||||
'primitive value': ['foo2', 1],
|
||||
'array value': ['bar2', [1,2]],
|
||||
'object value': ['baz2', {a:1, b:2}]
|
||||
};
|
||||
|
||||
describe('set', function () {
|
||||
|
||||
leche.withData(fixtureValues2, function (key, value) {
|
||||
|
||||
it('Sets an entry of the collection...', function () {
|
||||
expect(col.set(key, value)).to.eql(col);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
leche.withData(fixtureValues2, function (key, value) {
|
||||
|
||||
it('...would it already exists or not', function () {
|
||||
expect(col.set(key, value)).to.eql(col);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
|
||||
var fixtureUnexisting = {
|
||||
'Unexisting key/entry': ['wat', 'any']
|
||||
};
|
||||
|
||||
describe('get', function () {
|
||||
|
||||
leche.withData(fixtureValues1, function (key, value) {
|
||||
|
||||
it('Returns the value of an entry of the collection...', function () {
|
||||
expect(col.get(key)).to.eql(value);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
leche.withData(fixtureValues2, function (key, value) {
|
||||
|
||||
it('Returns the value of an entry of the collection...', function () {
|
||||
expect(col.get(key)).to.eql(value);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
leche.withData(fixtureUnexisting, function (key) {
|
||||
|
||||
it('...or throws if it does not exist', function () {
|
||||
expect(function () {
|
||||
col.get(key);
|
||||
}).to.throw(Collection.NoSuchEntry);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
|
||||
var fixtureUpdates = {
|
||||
'primitive value': ['foo2', 3],
|
||||
'array value': ['bar2', [3,4]],
|
||||
'object value': ['baz2', {c:3, d:4}]
|
||||
};
|
||||
|
||||
describe('update', function () {
|
||||
|
||||
leche.withData(fixtureUpdates, function (key, value) {
|
||||
|
||||
it('updates the given entries...', function () {
|
||||
expect(col.update(key, value)).to.eql(col);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
leche.withData(fixtureUpdates, function (key, value) {
|
||||
|
||||
it('...so we can see the values we get have changed accordingly', function () {
|
||||
expect(col.get(key)).to.eql(value);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
leche.withData(fixtureUnexisting, function (key, value) {
|
||||
|
||||
it('If the entry does not exist, updating throws', function () {
|
||||
expect(function () {
|
||||
col.update(key, value);
|
||||
}).to.throw(Collection.NoSuchEntry);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
|
||||
describe('remove', function () {
|
||||
|
||||
leche.withData(fixtureValues2, function (key) {
|
||||
|
||||
it('removes the given entries...', function () {
|
||||
expect(col.remove(key)).to.eql(col);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
leche.withData(fixtureValues2, function (key) {
|
||||
|
||||
it('...so trying to get them again throws...', function () {
|
||||
expect(function () {
|
||||
col.get(key);
|
||||
}).to.throw(Collection.NoSuchEntry);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
leche.withData(fixtureValues2, function (key) {
|
||||
|
||||
it('...and trying to remove them again also throws', function () {
|
||||
expect(function () {
|
||||
col.remove(key);
|
||||
}).to.throw(Collection.NoSuchEntry);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
|
||||
describe('has', function () {
|
||||
|
||||
leche.withData(fixtureValues1, function (key) {
|
||||
|
||||
it('Tells us if an entry exists...', function () {
|
||||
expect(col.has(key)).to.be.true();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
leche.withData(fixtureValues2, function (key) {
|
||||
|
||||
it('...or not', function () {
|
||||
expect(col.has(key)).to.be.false();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
|
||||
describe('size', function () {
|
||||
|
||||
it('Reveals the number of existing entries', function () {
|
||||
expect(col.size).to.eq(Object.keys(fixtureValues1).length);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
|
||||
describe('all', function () {
|
||||
|
||||
leche.withData(fixtureValues1, function (key, value) {
|
||||
|
||||
it('Gives access to the internal collection...', function () {
|
||||
expect(col.all).to.have.ownProperty(key);
|
||||
expect(col.all[key]).to.eq(value);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
leche.withData(fixtureValues2, function (key) {
|
||||
|
||||
it('Gives access to the internal collection...', function () {
|
||||
expect(col.all).to.not.have.ownProperty(key);
|
||||
expect(col.all[key]).to.eq(undefined);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('Gives access to the internal collection...', function () {
|
||||
expect(col.size).to.eq(Object.keys(col.all).length);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
@ -6,9 +6,15 @@
|
||||
"dependencies": {
|
||||
"make-error": "^0.3.0"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"devDependencies": {
|
||||
"babel": "^4.7.16",
|
||||
"chai": "^2.2.0",
|
||||
"dirty-chai": "^1.2.0",
|
||||
"leche": "^2.1.1",
|
||||
"mocha": "^2.2.1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "mocha --require babel/register *.spec.js"
|
||||
},
|
||||
"author": "Fabrice Marsaud <fabrice.marsaud@vates.fr>",
|
||||
"license": "aGPLv3"
|
||||
|
@ -1,65 +1,81 @@
|
||||
import Collection from './collection';
|
||||
|
||||
var co = new Collection.Collection();
|
||||
let col = new Collection.Collection();
|
||||
|
||||
co.begin();
|
||||
col.add('foo', 1);
|
||||
|
||||
// An object with id property
|
||||
|
||||
// ====================
|
||||
// Jouer sur le passage par référence, et la convention d'objets avec une prop ID
|
||||
|
||||
let obj = {id: 'bar', content: 2};
|
||||
col.add(obj);
|
||||
console.log(obj.get('bar'));
|
||||
// > {id: 'bar', content: 2}
|
||||
|
||||
col.bufferChanges(true);
|
||||
col.update('bar').content = 4;
|
||||
// update accesses obj at bar key and marks bar as updated. No event emitted.
|
||||
|
||||
col.get('bar').content = 5;
|
||||
obj.content = 6;
|
||||
// bar is already marked as updated, so ...
|
||||
|
||||
col.flush();
|
||||
// ...Emits an update as bar has been "updated to 6"
|
||||
|
||||
col.bufferChanges(true);
|
||||
col.update(obj).content = 7; // Short writing without knowing ID
|
||||
// WARNING, do not change ID after adding ...
|
||||
|
||||
col.bufferChanges(false);
|
||||
col.flush();
|
||||
// No event emitted ... exception thrown ?...
|
||||
col.bufferChanges(true);
|
||||
col.update(obj);
|
||||
col.flush();
|
||||
// Emits an update event as bar has been "updated to 7"
|
||||
|
||||
// ------------------------------------------------------------
|
||||
// Special cases :
|
||||
let foo = {id: 'foo'};
|
||||
let bar = {id: 'bar'};
|
||||
col.add(foo);
|
||||
|
||||
co.insert('a', 1000);
|
||||
console.log('a', co.get('a'));
|
||||
co.update('a', 2000);
|
||||
console.log('a', co.get('a'));
|
||||
co.delete('a');
|
||||
try {
|
||||
console.log(co.get('a'));
|
||||
col.update(foo, bar);
|
||||
} catch(e) {
|
||||
// Throws an instant exception on ID violation
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
console.log(co.commit());
|
||||
|
||||
console.log('=====');
|
||||
|
||||
co.insert('b', 100);
|
||||
console.log('b', co.get('b'));
|
||||
co.begin();
|
||||
co.update('b', 200);
|
||||
console.log('b', co.get('b'));
|
||||
co.insert('c', 300);
|
||||
co.update('b', 400);
|
||||
console.log('b', co.get('b'), 'c', co.get('c'));
|
||||
co.delete('b');
|
||||
try {
|
||||
console.log(co.get('b'));
|
||||
col.udpate('foo', bar);
|
||||
} catch(e) {
|
||||
// Same
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
co.rollback();
|
||||
|
||||
console.log('b', co.get('b'));
|
||||
try {
|
||||
console.log(co.get('c'));
|
||||
} catch(e) {
|
||||
col.update(foo).id = 'bar';
|
||||
} catch (e) {
|
||||
// Throws an exception at Event emission (key !== content.id)
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
console.log('=====');
|
||||
col.bufferChanges(true);
|
||||
col.remove(foo);
|
||||
col.add(foo);
|
||||
col.bufferChanges(false);
|
||||
// Silent...(No events)
|
||||
|
||||
var coa = new Collection.Collection();
|
||||
coa.insert('x', 999);
|
||||
coa.begin();
|
||||
coa.insert('a', 100);
|
||||
coa.update('a', 150);
|
||||
coa.insert('b', 200);
|
||||
console.log('a', coa.get('a'), 'b', coa.get('b'), 'x', coa.get('x'));
|
||||
var log = coa.commit();
|
||||
var cob = new Collection.Collection();
|
||||
cob.replay(log);
|
||||
console.log('a', cob.get('a'), 'b', cob.get('b'));
|
||||
col.bufferChanges(true);
|
||||
col.update(foo).id = 'bar';
|
||||
// Nothing happens
|
||||
try {
|
||||
console.log(cob.get('x'));
|
||||
} catch(e) {
|
||||
console.error(e);
|
||||
col.flush();
|
||||
} catch (e) {
|
||||
// Throws
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
|
Loading…
Reference in New Issue
Block a user