Comparing version 0.5.7 to 0.5.8
@@ -175,3 +175,2 @@ 'use strict'; | ||
value: function skip(_skip) { | ||
this._ensureNotExecuting(); | ||
(0, _invariant2.default)(_skip >= 0 || typeof _skip === 'undefined', 'skip(...): skip must be a positive number'); | ||
@@ -185,3 +184,2 @@ | ||
value: function limit(_limit) { | ||
this._ensureNotExecuting(); | ||
(0, _invariant2.default)(_limit >= 0 || typeof _limit === 'undefined', 'limit(...): limit must be a positive number'); | ||
@@ -195,3 +193,2 @@ | ||
value: function find(query) { | ||
this._ensureNotExecuting(); | ||
this._query = query; | ||
@@ -204,3 +201,2 @@ this._ensureMatcherSorter(); | ||
value: function project(projection) { | ||
this._ensureNotExecuting(); | ||
if (projection) { | ||
@@ -216,3 +212,2 @@ this._projector = new _DocumentProjector2.default(projection); | ||
value: function sort(sortObj) { | ||
this._ensureNotExecuting(); | ||
(0, _invariant2.default)((typeof sortObj === 'undefined' ? 'undefined' : _typeof(sortObj)) === 'object' || typeof sortObj === 'undefined' || Array.isArray(sortObj), 'sort(...): argument must be an object'); | ||
@@ -297,3 +292,2 @@ | ||
value: function addPipeline(type, val) { | ||
this._ensureNotExecuting(); | ||
(0, _invariant2.default)(type && PIPELINE_TYPE[type], 'Unknown pipeline processor type %s', type); | ||
@@ -344,46 +338,8 @@ | ||
if (!this._executing) { | ||
this._executing = this._doExec(); | ||
this.whenNotExecuting().then(function () { | ||
_this3._executing = null; | ||
}); | ||
} else if (!this._execPending) { | ||
this._execPending = true; | ||
this._executing = this.whenNotExecuting().then(function () { | ||
_this3._execPending = false; | ||
return _this3.exec(); | ||
}); | ||
} | ||
return this._executing; | ||
} | ||
}, { | ||
key: 'then', | ||
value: function then(resolve, reject) { | ||
return this.exec().then(resolve, reject); | ||
} | ||
}, { | ||
key: 'whenNotExecuting', | ||
value: function whenNotExecuting() { | ||
return Promise.resolve(this._executing).then(function (value) { | ||
return Promise.resolve().then(function () { | ||
return value; | ||
}); | ||
}, function (err) { | ||
return Promise.resolve().then(function () { | ||
throw err; | ||
}); | ||
}); | ||
} | ||
}, { | ||
key: '_doExec', | ||
value: function _doExec() { | ||
var _this4 = this; | ||
return this._matchObjects().then(function (docs) { | ||
var clonned = undefined; | ||
if (_this4.options.noClone) { | ||
if (_this3.options.noClone) { | ||
clonned = docs; | ||
} else { | ||
if (!_this4._projector) { | ||
if (!_this3._projector) { | ||
clonned = (0, _map3.default)(docs, function (doc) { | ||
@@ -393,23 +349,28 @@ return _EJSON2.default.clone(doc); | ||
} else { | ||
clonned = _this4._projector.project(docs); | ||
clonned = _this3._projector.project(docs); | ||
} | ||
} | ||
return _this4.processPipeline(clonned); | ||
return _this3.processPipeline(clonned); | ||
}); | ||
} | ||
}, { | ||
key: 'then', | ||
value: function then(resolve, reject) { | ||
return this.exec().then(resolve, reject); | ||
} | ||
}, { | ||
key: '_matchObjects', | ||
value: function _matchObjects() { | ||
var _this5 = this; | ||
var _this4 = this; | ||
return new _DocumentRetriver2.default(this.db).retriveForQeury(this._query).then(function (docs) { | ||
var results = []; | ||
var withFastLimit = _this5._limit && !_this5._skip && !_this5._sorter; | ||
var withFastLimit = _this4._limit && !_this4._skip && !_this4._sorter; | ||
(0, _forEach2.default)(docs, function (d) { | ||
var match = _this5._matcher.documentMatches(d); | ||
var match = _this4._matcher.documentMatches(d); | ||
if (match.result) { | ||
results.push(d); | ||
} | ||
if (withFastLimit && results.length === _this5._limit) { | ||
if (withFastLimit && results.length === _this4._limit) { | ||
return false; | ||
@@ -423,8 +384,8 @@ } | ||
if (_this5._sorter) { | ||
var comparator = _this5._sorter.getComparator(); | ||
if (_this4._sorter) { | ||
var comparator = _this4._sorter.getComparator(); | ||
results.sort(comparator); | ||
} | ||
return _this5.processSkipLimits(results); | ||
return _this4.processSkipLimits(results); | ||
}); | ||
@@ -442,12 +403,2 @@ } | ||
} | ||
}, { | ||
key: '_ensureNotExecuting', | ||
value: function _ensureNotExecuting() { | ||
(0, _invariant2.default)(!this.isExecuting, '_ensureNotExecuting(...): cursor is executing, cursor is immutable!'); | ||
} | ||
}, { | ||
key: 'isExecuting', | ||
get: function get() { | ||
return !!this._executing; | ||
} | ||
}]); | ||
@@ -454,0 +405,0 @@ |
@@ -22,2 +22,6 @@ 'use strict'; | ||
var _forEach = require('fast.js/forEach'); | ||
var _forEach2 = _interopRequireDefault(_forEach); | ||
var _keys2 = require('fast.js/object/keys'); | ||
@@ -66,4 +70,7 @@ | ||
_this.maybeUpdate = (0, _bind3.default)(_this.maybeUpdate, _this); | ||
_this._latestResult = null; | ||
_this._childrenCursors = {}; | ||
_this._parentCursors = {}; | ||
_this._observers = 0; | ||
return _this; | ||
@@ -108,11 +115,4 @@ } | ||
* | ||
* if `options.declare` is true, then initial update of | ||
* the cursor is not initiated and function will return | ||
* `this` instead promise. It means, that you can't stop | ||
* observer by a stopper object. Use `stopObservers()` | ||
* function instead. | ||
* | ||
* @param {Function} | ||
* @param {Object} options | ||
* @param {Boolean} options.declare | ||
* @return {Stopper} | ||
@@ -137,11 +137,20 @@ */ | ||
var running = true; | ||
var stopper = function stopper() { | ||
_this2.db.removeListener('insert', updateWrapper); | ||
_this2.db.removeListener('update', updateWrapper); | ||
_this2.db.removeListener('remove', updateWrapper); | ||
_this2.removeListener('update', listener); | ||
_this2.removeListener('stop', stopper); | ||
_this2.emit('stopped', listener); | ||
if (running) { | ||
_this2.db.removeListener('insert', updateWrapper); | ||
_this2.db.removeListener('update', updateWrapper); | ||
_this2.db.removeListener('remove', updateWrapper); | ||
_this2.removeListener('update', listener); | ||
_this2.removeListener('stop', stopper); | ||
running = false; | ||
_this2._observers -= 1; | ||
if (_this2._observers === 0) { | ||
_this2.emit('stopped'); | ||
} | ||
} | ||
}; | ||
this._observers += 1; | ||
listener = this._prepareListener(listener); | ||
@@ -151,6 +160,6 @@ this.on('update', listener); | ||
var parentSetter = function parentSetter(cursor) { | ||
_this2._parentCursor = cursor; | ||
if (cursor._trackChildCursor) { | ||
cursor._trackChildCursor(cursor); | ||
var parentSetter = function parentSetter(parentCursor) { | ||
_this2._trackParentCursor(parentCursor); | ||
if (parentCursor._trackChildCursor) { | ||
parentCursor._trackChildCursor(_this2); | ||
} | ||
@@ -174,16 +183,8 @@ }; | ||
if (options.declare) { | ||
return this; | ||
} else { | ||
if (this._latestResult != null) { | ||
var propagatePromise = this.whenNotExecuting().then(function () { | ||
_this2._propagateUpdate(true); | ||
return _this2._latestResult; | ||
}); | ||
return createStoppablePromise(propagatePromise); | ||
} else { | ||
var firstUpdatePromise = this.update.func(true); | ||
return createStoppablePromise(firstUpdatePromise); | ||
} | ||
if (!this._updatePromise) { | ||
this.update.func(true); | ||
} else if (this._latestResult !== null) { | ||
listener(this._latestResult); | ||
} | ||
return createStoppablePromise(this._updatePromise); | ||
} | ||
@@ -218,8 +219,11 @@ | ||
return this.exec().then(function (result) { | ||
_this3._latestResult = result; | ||
_this3._updateLatestIds(); | ||
_this3._propagateUpdate(firstRun); | ||
return result; | ||
this._updatePromise = Promise.resolve(this._updatePromise).then(function () { | ||
return _this3.exec().then(function (result) { | ||
_this3._latestResult = result; | ||
_this3._updateLatestIds(); | ||
_this3._propagateUpdate(firstRun); | ||
return result; | ||
}); | ||
}); | ||
return this._updatePromise; | ||
} | ||
@@ -244,5 +248,10 @@ | ||
value: function maybeUpdate(newDoc, oldDoc) { | ||
// When no newDoc and no oldDoc provided then | ||
// it's a special case when no data about update | ||
// available and we always need to update a cursor | ||
var alwaysUpdateCursor = newDoc === null && oldDoc === null; | ||
// When it's remove operation we just check | ||
// that it's in our latest result ids list | ||
var removedFromResult = !newDoc && oldDoc && (!this._latestIds || this._latestIds.has(oldDoc._id)); | ||
var removedFromResult = alwaysUpdateCursor || !newDoc && oldDoc && (!this._latestIds || this._latestIds.has(oldDoc._id)); | ||
@@ -295,4 +304,9 @@ // When it's an update operation we check four things | ||
this.emit('update', this._latestResult, firstRun); | ||
if (!firstRun && this._parentCursor && this._parentCursor._propagateUpdate) { | ||
this._parentCursor._propagateUpdate(false); | ||
if (!firstRun) { | ||
(0, _forEach2.default)(this._parentCursors, function (v, k) { | ||
if (v._propagateUpdate) { | ||
v._propagateUpdate(false); | ||
} | ||
}); | ||
} | ||
@@ -326,10 +340,28 @@ } | ||
key: '_trackChildCursor', | ||
value: function _trackChildCursor(cursor) { | ||
value: function _trackChildCursor(childCursor) { | ||
var _this4 = this; | ||
this._childrenCursors[cursor._id] = cursor; | ||
cursor.once('stopped', function () { | ||
return delete _this4._childrenCursors[cursor._id]; | ||
}); | ||
this._childrenCursors[childCursor._id] = childCursor; | ||
var cleaner = function cleaner() { | ||
return delete _this4._childrenCursors[childCursor._id]; | ||
}; | ||
childCursor.once('stopped', cleaner); | ||
} | ||
/** | ||
* Tracks a parent cursor for propagating update event | ||
* @param {Cursor} cursor | ||
*/ | ||
}, { | ||
key: '_trackParentCursor', | ||
value: function _trackParentCursor(parentCursor) { | ||
var _this5 = this; | ||
this._parentCursors[parentCursor._id] = parentCursor; | ||
var cleaner = function cleaner() { | ||
return delete _this5._parentCursors[parentCursor._id]; | ||
}; | ||
parentCursor.once('stopped', cleaner); | ||
} | ||
}], [{ | ||
@@ -336,0 +368,0 @@ key: 'defaultDebounce', |
@@ -115,8 +115,3 @@ import _bind from 'fast.js/function/bind'; | ||
get isExecuting() { | ||
return !!this._executing; | ||
} | ||
skip(skip) { | ||
this._ensureNotExecuting(); | ||
invariant( | ||
@@ -132,3 +127,2 @@ skip >= 0 || typeof skip === 'undefined', | ||
limit(limit) { | ||
this._ensureNotExecuting(); | ||
invariant( | ||
@@ -144,3 +138,2 @@ limit >= 0 || typeof limit === 'undefined', | ||
find(query) { | ||
this._ensureNotExecuting(); | ||
this._query = query; | ||
@@ -152,3 +145,2 @@ this._ensureMatcherSorter(); | ||
project(projection) { | ||
this._ensureNotExecuting(); | ||
if (projection) { | ||
@@ -163,3 +155,2 @@ this._projector = new DocumentProjector(projection); | ||
sort(sortObj) { | ||
this._ensureNotExecuting(); | ||
invariant( | ||
@@ -261,3 +252,2 @@ typeof sortObj === 'object' || typeof sortObj === 'undefined' || Array.isArray(sortObj), | ||
addPipeline(type, val, ...args) { | ||
this._ensureNotExecuting(); | ||
invariant( | ||
@@ -301,32 +291,2 @@ type && PIPELINE_TYPE[type], | ||
exec() { | ||
if (!this._executing) { | ||
this._executing = this._doExec(); | ||
this.whenNotExecuting().then(() => { | ||
this._executing = null; | ||
}); | ||
} else if (!this._execPending) { | ||
this._execPending = true; | ||
this._executing = this.whenNotExecuting().then(() => { | ||
this._execPending = false; | ||
return this.exec(); | ||
}); | ||
} | ||
return this._executing; | ||
} | ||
then(resolve, reject) { | ||
return this.exec().then(resolve, reject); | ||
} | ||
whenNotExecuting() { | ||
return Promise.resolve(this._executing).then( | ||
(value) => Promise.resolve().then(() => value), | ||
(err) => Promise.resolve().then(() => { | ||
throw err; | ||
}) | ||
); | ||
} | ||
_doExec() { | ||
return this._matchObjects() | ||
@@ -348,2 +308,6 @@ .then(docs => { | ||
then(resolve, reject) { | ||
return this.exec().then(resolve, reject); | ||
} | ||
_matchObjects() { | ||
@@ -389,11 +353,4 @@ return new DocumentRetriver(this.db) | ||
} | ||
_ensureNotExecuting() { | ||
invariant( | ||
!this.isExecuting, | ||
'_ensureNotExecuting(...): cursor is executing, cursor is immutable!' | ||
); | ||
} | ||
} | ||
export default Cursor; |
import _bind from 'fast.js/function/bind'; | ||
import _check from 'check-types'; | ||
import _map from 'fast.js/map'; | ||
import _each from 'fast.js/forEach'; | ||
import _keys from 'fast.js/object/keys'; | ||
@@ -21,10 +22,10 @@ import Cursor from './Cursor'; | ||
super(db, query, options); | ||
this.update = debounce( | ||
_bind(this.update, this), | ||
_defaultDebounce, | ||
_defaultBatchSize | ||
); | ||
this.update = debounce(_bind(this.update, this), | ||
_defaultDebounce, _defaultBatchSize); | ||
this.maybeUpdate = _bind(this.maybeUpdate, this); | ||
this._latestResult = null; | ||
this._childrenCursors = {}; | ||
this._parentCursors = {}; | ||
this._observers = 0; | ||
} | ||
@@ -78,11 +79,4 @@ | ||
* | ||
* if `options.declare` is true, then initial update of | ||
* the cursor is not initiated and function will return | ||
* `this` instead promise. It means, that you can't stop | ||
* observer by a stopper object. Use `stopObservers()` | ||
* function instead. | ||
* | ||
* @param {Function} | ||
* @param {Object} options | ||
* @param {Boolean} options.declare | ||
* @return {Stopper} | ||
@@ -98,11 +92,20 @@ */ | ||
let running = true; | ||
const stopper = () => { | ||
this.db.removeListener('insert', updateWrapper); | ||
this.db.removeListener('update', updateWrapper); | ||
this.db.removeListener('remove', updateWrapper); | ||
this.removeListener('update', listener); | ||
this.removeListener('stop', stopper); | ||
this.emit('stopped', listener); | ||
if (running) { | ||
this.db.removeListener('insert', updateWrapper); | ||
this.db.removeListener('update', updateWrapper); | ||
this.db.removeListener('remove', updateWrapper); | ||
this.removeListener('update', listener); | ||
this.removeListener('stop', stopper); | ||
running = false; | ||
this._observers -= 1; | ||
if (this._observers === 0) { | ||
this.emit('stopped'); | ||
} | ||
} | ||
}; | ||
this._observers += 1; | ||
listener = this._prepareListener(listener); | ||
@@ -112,6 +115,6 @@ this.on('update', listener); | ||
const parentSetter = (cursor) => { | ||
this._parentCursor = cursor; | ||
if (cursor._trackChildCursor) { | ||
cursor._trackChildCursor(cursor); | ||
const parentSetter = (parentCursor) => { | ||
this._trackParentCursor(parentCursor); | ||
if (parentCursor._trackChildCursor) { | ||
parentCursor._trackChildCursor(this); | ||
} | ||
@@ -135,16 +138,8 @@ }; | ||
if (options.declare) { | ||
return this; | ||
} else { | ||
if (this._latestResult != null) { | ||
const propagatePromise = this.whenNotExecuting().then(() => { | ||
this._propagateUpdate(true); | ||
return this._latestResult; | ||
}); | ||
return createStoppablePromise(propagatePromise); | ||
} else { | ||
const firstUpdatePromise = this.update.func(true); | ||
return createStoppablePromise(firstUpdatePromise); | ||
} | ||
if (!this._updatePromise) { | ||
this.update.func(true); | ||
} else if (this._latestResult !== null) { | ||
listener(this._latestResult); | ||
} | ||
return createStoppablePromise(this._updatePromise); | ||
} | ||
@@ -169,8 +164,12 @@ | ||
update(firstRun = false) { | ||
return this.exec().then((result) => { | ||
this._latestResult = result; | ||
this._updateLatestIds(); | ||
this._propagateUpdate(firstRun); | ||
return result; | ||
}); | ||
this._updatePromise = Promise.resolve(this._updatePromise) | ||
.then(() => | ||
this.exec().then((result) => { | ||
this._latestResult = result; | ||
this._updateLatestIds(); | ||
this._propagateUpdate(firstRun); | ||
return result; | ||
}) | ||
); | ||
return this._updatePromise; | ||
} | ||
@@ -192,5 +191,10 @@ | ||
maybeUpdate(newDoc, oldDoc) { | ||
// When no newDoc and no oldDoc provided then | ||
// it's a special case when no data about update | ||
// available and we always need to update a cursor | ||
const alwaysUpdateCursor = newDoc === null && oldDoc === null; | ||
// When it's remove operation we just check | ||
// that it's in our latest result ids list | ||
const removedFromResult = ( | ||
const removedFromResult = alwaysUpdateCursor || ( | ||
!newDoc && oldDoc && | ||
@@ -247,4 +251,9 @@ (!this._latestIds || this._latestIds.has(oldDoc._id)) | ||
this.emit('update', this._latestResult, firstRun); | ||
if (!firstRun && this._parentCursor && this._parentCursor._propagateUpdate) { | ||
this._parentCursor._propagateUpdate(false); | ||
if (!firstRun) { | ||
_each(this._parentCursors, (v, k) => { | ||
if (v._propagateUpdate) { | ||
v._propagateUpdate(false); | ||
} | ||
}); | ||
} | ||
@@ -270,10 +279,19 @@ } | ||
*/ | ||
_trackChildCursor(cursor) { | ||
this._childrenCursors[cursor._id] = cursor; | ||
cursor.once('stopped', () => | ||
delete this._childrenCursors[cursor._id] | ||
); | ||
_trackChildCursor(childCursor) { | ||
this._childrenCursors[childCursor._id] = childCursor; | ||
const cleaner = () => delete this._childrenCursors[childCursor._id]; | ||
childCursor.once('stopped', cleaner); | ||
} | ||
/** | ||
* Tracks a parent cursor for propagating update event | ||
* @param {Cursor} cursor | ||
*/ | ||
_trackParentCursor(parentCursor) { | ||
this._parentCursors[parentCursor._id] = parentCursor; | ||
const cleaner = () => delete this._parentCursors[parentCursor._id]; | ||
parentCursor.once('stopped', cleaner); | ||
} | ||
} | ||
export default CursorObservable; |
{ | ||
"name": "marsdb", | ||
"version": "0.5.7", | ||
"version": "0.5.8", | ||
"author": { | ||
@@ -5,0 +5,0 @@ "name": "Artem Artemev", |
@@ -44,3 +44,3 @@ <div style="text-align:center"><img src="https://static.studytime.me/marsdb.png" /></div> | ||
* **Meteor compitable** [Cleint](https://github.com/c58/marsdb-sync-client) / [Server](https://github.com/c58/marsdb-sync-server) | ||
* **Meteor compatible** [Client](https://github.com/c58/marsdb-sync-client) / [Server](https://github.com/c58/marsdb-sync-server) | ||
* REST (pull-request if you need it ;)) | ||
@@ -47,0 +47,0 @@ |
@@ -28,25 +28,11 @@ import Collection from '../../lib/Collection'; | ||
describe('#exec', function () { | ||
it('should on first call execute query, on next calls wait until first executed', function () { | ||
it('should create new execution on each call', function () { | ||
const cursor = new Cursor(db); | ||
cursor.find({b: {$gt: 4}}).skip(1).sort({b: 1}); | ||
const promise = cursor.exec(); | ||
const pendingPromise = cursor.exec(); | ||
promise.should.be.not.equal(pendingPromise); | ||
cursor.exec().should.be.equal(pendingPromise); | ||
cursor.exec().should.be.equal(pendingPromise); | ||
cursor.exec().should.be.equal(pendingPromise); | ||
cursor.exec().should.be.equal(pendingPromise); | ||
cursor.exec().should.not.be.equal(promise); | ||
return promise.then(() => { | ||
const anotherPromise = cursor.exec() | ||
anotherPromise.should.not.be.equal(promise); | ||
anotherPromise.should.be.equal(pendingPromise); | ||
return anotherPromise; | ||
}).then(() => { | ||
const anotherPromise = cursor.exec() | ||
anotherPromise.should.not.be.equal(pendingPromise); | ||
cursor.exec().should.be.equal(anotherPromise); | ||
cursor.exec().should.be.equal(anotherPromise); | ||
cursor.exec().should.be.equal(anotherPromise); | ||
cursor.exec().should.be.equal(anotherPromise); | ||
return anotherPromise; | ||
}) | ||
@@ -53,0 +39,0 @@ }); |
@@ -53,29 +53,2 @@ import Collection from '../../lib/Collection'; | ||
describe('#whenNotExecuting', function () { | ||
it('should wait until request processed', function (done) { | ||
const cursor = db.find({a: 1}); | ||
cursor.then(() => { | ||
cursor._query.should.be.deep.equals({a: 1}); | ||
}); | ||
cursor.whenNotExecuting().then(() => { | ||
cursor.find({a: 2}).then(() => { | ||
cursor._query.should.be.deep.equals({a: 2}); | ||
done(); | ||
}); | ||
}) | ||
}); | ||
it('should rise an exception when try to change cursor while executing', function () { | ||
const cursor = db.find({a: 1}); | ||
cursor.then(() => { | ||
cursor._query.should.be.deep.equals({a: 1}); | ||
}); | ||
expect(() => { | ||
cursor.find({a: 2}).then(() => { | ||
cursor._query.should.be.deep.equals({a: 2}); | ||
}); | ||
}).to.throw(Error); | ||
}); | ||
}); | ||
describe('#stopObservers', function () { | ||
@@ -114,2 +87,14 @@ it('should stop all listeners', function () { | ||
describe('#observe', function () { | ||
it('should generate `stopped` event when all observers stopped', function () { | ||
const cursor = db.find({b: 1}) | ||
const cb = sinon.spy(); | ||
cursor.on('stopped', cb); | ||
const obs1 = cursor.observe(() => {}); | ||
const obs2 = cursor.observe(() => {}); | ||
obs1.stop(); | ||
cb.should.have.callCount(0); | ||
obs2.stop(); | ||
cb.should.have.callCount(1); | ||
}); | ||
it('should return result of previous execution', function () { | ||
@@ -129,20 +114,2 @@ const cursor = db.find({b: 1}) | ||
it('should support multiple declarative style observing', function (done) { | ||
let calls = 0; | ||
const obsFn = () => { | ||
calls += 1; | ||
if (calls > 1) { | ||
done(); | ||
} | ||
} | ||
const cursor = db.find({b: 1}) | ||
.observe(obsFn, {declare: true}) | ||
.observe(obsFn, {declare: true}) | ||
cursor.then(() => { | ||
calls.should.be.equals(0); | ||
cursor.update(true); | ||
}) | ||
}); | ||
it('should observe insert without debounce and batchSize eq 1', function (done) { | ||
@@ -149,0 +116,0 @@ var calls = 0; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
895279
20904