Comparing version 0.3.6 to 0.3.7
@@ -19,2 +19,6 @@ 'use strict'; | ||
var _lodashCollectionSize = require('lodash/collection/size'); | ||
var _lodashCollectionSize2 = _interopRequireDefault(_lodashCollectionSize); | ||
var _Cursor2 = require('./Cursor'); | ||
@@ -24,2 +28,6 @@ | ||
var _EJSON = require('./EJSON'); | ||
var _EJSON2 = _interopRequireDefault(_EJSON); | ||
/** | ||
@@ -163,5 +171,4 @@ * Observable cursor is used for making request auto-updatable | ||
* | ||
* TODO improve performance, we should be smarter | ||
* and don't emit fully request update in many | ||
* cases | ||
* TODO we should update _latestResult by hands in some cases | ||
* without a calling of `update` method | ||
* | ||
@@ -174,6 +181,17 @@ * @param {Object} newDoc | ||
value: function maybeUpdate(newDoc, oldDoc) { | ||
// 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 insertedInResult = removedFromResult || newDoc && this._matcher.documentMatches(newDoc).result; | ||
// When it's an update operation we check three things | ||
// 1. Is a new doc or old doc matched by a query? | ||
// 2. Is a new doc has different number of fields then an old doc? | ||
// 3. Is a new doc has a greater updatedAt time then an old doc? | ||
// 4. Is a new doc not equals to an old doc? | ||
var updatedInResult = removedFromResult || newDoc && oldDoc && (this._matcher.documentMatches(newDoc).result || this._matcher.documentMatches(oldDoc).result) && ((0, _lodashCollectionSize2['default'])(newDoc) !== (0, _lodashCollectionSize2['default'])(oldDoc) || newDoc.updatedAt && (!oldDoc.updatedAt || oldDoc.updatedAt && newDoc.updatedAt > oldDoc.updatedAt) || !_EJSON2['default'].equals(newDoc, oldDoc)); | ||
// When it's an insert operation we just check | ||
// it's match a query | ||
var insertedInResult = updatedInResult || newDoc && !oldDoc && this._matcher.documentMatches(newDoc).result; | ||
if (insertedInResult) { | ||
@@ -180,0 +198,0 @@ return this.update(); |
@@ -21,2 +21,6 @@ 'use strict'; | ||
var _eventemitter3 = require('eventemitter3'); | ||
var _eventemitter32 = _interopRequireDefault(_eventemitter3); | ||
var _PromiseQueue = require('./PromiseQueue'); | ||
@@ -26,5 +30,5 @@ | ||
var _eventemitter3 = require('eventemitter3'); | ||
var _EJSON = require('./EJSON'); | ||
var _eventemitter32 = _interopRequireDefault(_eventemitter3); | ||
var _EJSON2 = _interopRequireDefault(_EJSON); | ||
@@ -81,3 +85,3 @@ /** | ||
return this._loadedPromise.then(function () { | ||
_this3._storage[key] = value; | ||
_this3._storage[key] = _EJSON2['default'].clone(value); | ||
}); | ||
@@ -100,3 +104,3 @@ } | ||
return this._loadedPromise.then(function () { | ||
return _this5._storage[key]; | ||
return _EJSON2['default'].clone(_this5._storage[key]); | ||
}); | ||
@@ -113,3 +117,3 @@ } | ||
(0, _lodashObjectKeys2['default'])(_this6._storage).forEach(function (k) { | ||
emitter.emit('data', { value: _this6._storage[k] }); | ||
emitter.emit('data', { value: _EJSON2['default'].clone(_this6._storage[k]) }); | ||
}); | ||
@@ -116,0 +120,0 @@ emitter.emit('end'); |
@@ -10,2 +10,3 @@ var Collection = require('./dist/Collection').default; | ||
module.exports = { | ||
__esModule: true, | ||
default: Collection, | ||
@@ -12,0 +13,0 @@ Random: Random, |
@@ -0,2 +1,4 @@ | ||
import _size from 'lodash/collection/size'; | ||
import Cursor from './Cursor'; | ||
import EJSON from './EJSON'; | ||
@@ -107,5 +109,4 @@ | ||
* | ||
* TODO improve performance, we should be smarter | ||
* and don't emit fully request update in many | ||
* cases | ||
* TODO we should update _latestResult by hands in some cases | ||
* without a calling of `update` method | ||
* | ||
@@ -116,2 +117,4 @@ * @param {Object} newDoc | ||
maybeUpdate(newDoc, oldDoc) { | ||
// When it's remove operation we just check | ||
// that it's in our latest result ids list | ||
const removedFromResult = ( | ||
@@ -122,6 +125,28 @@ !newDoc && oldDoc && | ||
const insertedInResult = removedFromResult || ( | ||
newDoc && this._matcher.documentMatches(newDoc).result | ||
// When it's an update operation we check three things | ||
// 1. Is a new doc or old doc matched by a query? | ||
// 2. Is a new doc has different number of fields then an old doc? | ||
// 3. Is a new doc has a greater updatedAt time then an old doc? | ||
// 4. Is a new doc not equals to an old doc? | ||
const updatedInResult = removedFromResult || (newDoc && oldDoc && ( | ||
this._matcher.documentMatches(newDoc).result || | ||
this._matcher.documentMatches(oldDoc).result | ||
) && ( | ||
_size(newDoc) !== _size(oldDoc) || ( | ||
newDoc.updatedAt && ( | ||
!oldDoc.updatedAt || | ||
(oldDoc.updatedAt && newDoc.updatedAt > oldDoc.updatedAt) | ||
) | ||
) || ( | ||
!EJSON.equals(newDoc, oldDoc) | ||
) | ||
) | ||
); | ||
// When it's an insert operation we just check | ||
// it's match a query | ||
const insertedInResult = updatedInResult || (newDoc && !oldDoc && ( | ||
this._matcher.documentMatches(newDoc).result | ||
)); | ||
if (insertedInResult) { | ||
@@ -128,0 +153,0 @@ return this.update(); |
import _keys from 'lodash/object/keys'; | ||
import _defer from 'lodash/function/defer'; | ||
import EventEmitter from 'eventemitter3'; | ||
import PromiseQueue from './PromiseQueue'; | ||
import EventEmitter from 'eventemitter3'; | ||
import EJSON from './EJSON'; | ||
@@ -43,3 +44,3 @@ | ||
return this._loadedPromise.then(() => { | ||
this._storage[key] = value; | ||
this._storage[key] = EJSON.clone(value); | ||
}); | ||
@@ -56,3 +57,3 @@ } | ||
return this._loadedPromise.then(() => { | ||
return this._storage[key]; | ||
return EJSON.clone(this._storage[key]); | ||
}); | ||
@@ -66,3 +67,3 @@ } | ||
_keys(this._storage).forEach((k) => { | ||
emitter.emit('data', {value: this._storage[k]}); | ||
emitter.emit('data', {value: EJSON.clone(this._storage[k])}); | ||
}); | ||
@@ -69,0 +70,0 @@ emitter.emit('end'); |
{ | ||
"name": "marsdb", | ||
"version": "0.3.6", | ||
"version": "0.3.7", | ||
"author": { | ||
@@ -5,0 +5,0 @@ "name": "Artem Artemev", |
@@ -12,3 +12,3 @@ <div style="text-align:center"><img src="https://static.studytime.me/marsdb.png" /></div> | ||
MarsDB is a lightweight client-side database. | ||
It based on a Meteor’s `minimongo` mathing/modifying implementation. It carefully written on `ES6`, usess `modular lodash`, have a `Promise` based interface and may be backed with any storage implementation (LevelUP, LocalStorage, IndexedDB, etc). For now implemented only LocalStorage and [LocalForage](https://github.com/mozilla/localForage) storage managers. It also supports `observable` cursors. | ||
It's based on a Meteor’s `minimongo` matching/modifying implementation. It's carefully written on `ES6`, usess `modular lodash`, have a `Promise` based interface and may be backed with any storage implementation (LevelUP, LocalStorage, IndexedDB, etc). For now implemented only LocalStorage and [LocalForage](https://github.com/mozilla/localForage) storage managers. It's also supports `observable` cursors. | ||
@@ -23,3 +23,3 @@ MarsDB supports any kind of find/update/remove operations that Meteor’s minimongo does. So, go to the Meteor docs for supported query/modifier operations. | ||
* **Carefully written on ES6** | ||
* **Supports many of MongoDB query/modify operations** – thanks to Meteor’s minimongo | ||
* **Supports many of MongoDB query/modify operations** – thanks to a Meteor’s minimongo | ||
* **Flexible pipeline** – map, reduce, custom sorting function, filtering. All with a sexy JS interface (no ugly mongo’s aggregation language) | ||
@@ -26,0 +26,0 @@ * **Persistence API** – all collections can be stored (and restored) with any kind of storage (in-memory, LocalStorage, LevelUP, etc) |
@@ -299,2 +299,19 @@ import Collection from '../../lib/Collection'; | ||
it('should not change object in a storage', function () { | ||
return db.find().sort({b: 1}).join(d => { | ||
return db.find({g: d.g}).then((result) => { | ||
d.groupObjs = result; | ||
}); | ||
}).then((docs) => { | ||
docs.should.have.length(7); | ||
docs[0].groupObjs.should.have.length(4); | ||
docs[1].groupObjs.should.have.length(4); | ||
docs[6].groupObjs.should.have.length(3); | ||
return db.find().sort({b: 1}); | ||
}).then((docs) => { | ||
docs.should.have.length(7); | ||
docs[0].should.not.have.ownProperty('groupObjs'); | ||
}); | ||
}); | ||
it('should throw an error if join is not a function', function () { | ||
@@ -301,0 +318,0 @@ const cursor = new Cursor(db); |
@@ -125,4 +125,96 @@ import Collection from '../../lib/Collection'; | ||
}); | ||
it('should not update a cursor when updated dcc does not match a query', function (done) { | ||
var calls = 0; | ||
db.find({$or: [{f: 1}, {f: 2}]}).observe(result => { | ||
if (calls === 0) { | ||
expect(result).to.be.an('array'); | ||
result.should.have.length(2); | ||
calls++; | ||
} else { | ||
done(new Error('Called when document does not match query')); | ||
} | ||
}).then(() => { | ||
return db.update({f: 3}, {$set: {some: 'field'}}); | ||
}).then(() => { | ||
setTimeout(() => {done()}, 40); | ||
}); | ||
}); | ||
it('should not update a cursor when updated doc is equals to an old doc', function (done) { | ||
var calls = 0; | ||
db.find({$or: [{f: 1}, {f: 2}]}).observe(result => { | ||
if (calls === 0) { | ||
expect(result).to.be.an('array'); | ||
result.should.have.length(2); | ||
calls++; | ||
} else { | ||
done(new Error('Called when an updated doc is equals to an old doc')); | ||
} | ||
}).then(() => { | ||
return db.update({f: 1}, {$set: {b: 1}}); | ||
}).then(() => { | ||
setTimeout(() => {done()}, 40); | ||
}); | ||
}); | ||
it('should update a cursor when updatedAt is different', function (done) { | ||
var calls = 0; | ||
db.update({f: 1}, {$set: {updatedAt: new Date(0)}}).then(() => { | ||
return db.find({$or: [{f: 1}, {f: 2}]}).observe(result => { | ||
if (calls === 0) { | ||
expect(result).to.be.an('array'); | ||
result.should.have.length(2); | ||
calls++; | ||
} else { | ||
result[0].updatedAt.should.not.be.deep.equals(new Date(0)); | ||
result[0].updatedAt.should.be.deep.equals(new Date(1)); | ||
done(); | ||
} | ||
}).then(() => { | ||
return db.update({f: 1}, {$set: {updatedAt: new Date(1)}}); | ||
}); | ||
}); | ||
}); | ||
it('should not update a cursor when updatedAt is equals', function (done) { | ||
var calls = 0; | ||
db.update({f: 1}, {$set: {updatedAt: new Date(0)}}).then(() => { | ||
return db.find({$or: [{f: 1}, {f: 2}]}).observe(result => { | ||
if (calls === 0) { | ||
expect(result).to.be.an('array'); | ||
result.should.have.length(2); | ||
calls++; | ||
} else { | ||
done(new Error()); | ||
} | ||
}).then(() => { | ||
return db.update({f: 1}, {$set: {updatedAt: new Date(0)}}); | ||
}).then(() => { | ||
setTimeout(() => {done()}, 40); | ||
}); | ||
}); | ||
}); | ||
it('should update when not matching old doc will match by update', function (done) { | ||
var calls = 0; | ||
db.find({$or: [{f: 1}, {f: 2}]}).observe(result => { | ||
if (calls === 0) { | ||
expect(result).to.be.an('array'); | ||
result.should.have.length(2); | ||
calls++; | ||
} else { | ||
result.should.have.length(3); | ||
done(); | ||
} | ||
}).then(() => { | ||
return db.update({f: 20}, {$set: {f: 2}}); | ||
}); | ||
}); | ||
}); | ||
describe('#debounce', function () { | ||
@@ -129,0 +221,0 @@ it('should change debounce wait time', function (done) { |
@@ -20,2 +20,31 @@ import StorageManager from '../../lib/StorageManager'; | ||
it('should clone object when getting', () => { | ||
const db = new StorageManager(); | ||
return db.persist('a', {_id: 'a', a: 1}).then(() => { | ||
return db.get('a'); | ||
}).then(doc => { | ||
doc.a = 2; | ||
return db.get('a'); | ||
}).then(doc => { | ||
doc.a.should.be.equal(1); | ||
}); | ||
}); | ||
it('should clone objects when streaming', (done) => { | ||
const db = new StorageManager(); | ||
db.persist('a', {_id: 'a', a: 1}).then(() => { | ||
db.createReadStream() | ||
.on('data', (doc) => doc.value.a = 2) | ||
.on('end', () => { | ||
db.createReadStream() | ||
.on('data', (doc) => { | ||
doc.value.a.should.be.equal(1); | ||
}) | ||
.on('end', () => { | ||
done(); | ||
}) | ||
}) | ||
}); | ||
}); | ||
it('should be a able to persist with replace by id', () => { | ||
@@ -22,0 +51,0 @@ const db = new StorageManager(); |
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
1069306
24934