nedb
Advanced tools
Comparing version 1.6.1 to 1.6.2
@@ -25,2 +25,5 @@ var customUtils = require('./customUtils') | ||
* @param {Function} options.compareStrings Optional, string comparison function that overrides default for sorting | ||
* | ||
* Event Emitter - Events | ||
* * compaction.done - Fired whenever a compaction operation was finished | ||
*/ | ||
@@ -78,3 +81,5 @@ function Datastore (options) { | ||
util.inherits(Datastore, require('events')); | ||
/** | ||
@@ -81,0 +86,0 @@ * Load the database from the datafile, and trigger the execution of buffered commands if any |
@@ -492,3 +492,3 @@ /** | ||
// undefined (no match since they mean field doesn't exist and can't be serialized) | ||
if (util.isArray(a) || util.isArray(b) || a === undefined || b === undefined) { return false; } | ||
if ((!(util.isArray(a) && util.isArray(b)) && (util.isArray(a) || util.isArray(b))) || a === undefined || b === undefined) { return false; } | ||
@@ -712,2 +712,7 @@ // General objects (check for deep equality) | ||
if (util.isArray(objValue) && !treatObjAsValue) { | ||
// If the queryValue is an array, try to perform an exact match | ||
if (util.isArray(queryValue)) { | ||
return matchQueryPart(obj, queryKey, queryValue, true); | ||
} | ||
// Check if we are using an array-specific comparison function | ||
@@ -730,3 +735,3 @@ if (queryValue !== null && typeof queryValue === 'object' && !util.isRegExp(queryValue)) { | ||
// or only normal fields. Mixed objects are not allowed | ||
if (queryValue !== null && typeof queryValue === 'object' && !util.isRegExp(queryValue)) { | ||
if (queryValue !== null && typeof queryValue === 'object' && !util.isRegExp(queryValue) && !util.isArray(queryValue)) { | ||
keys = Object.keys(queryValue); | ||
@@ -733,0 +738,0 @@ firstChars = _.map(keys, function (item) { return item[0]; }); |
@@ -137,3 +137,7 @@ /** | ||
storage.crashSafeWriteFile(this.filename, toPersist, callback); | ||
storage.crashSafeWriteFile(this.filename, toPersist, function (err) { | ||
if (err) { return callback(err); } | ||
self.db.emit('compaction.done'); | ||
return callback(null); | ||
}); | ||
}; | ||
@@ -140,0 +144,0 @@ |
{ | ||
"name": "nedb", | ||
"version": "1.6.1", | ||
"version": "1.6.2", | ||
"author": { | ||
@@ -5,0 +5,0 @@ "name": "Louis Chatriot", |
@@ -10,3 +10,3 @@ <img src="http://i.imgur.com/9O1xHFb.png" style="width: 25%; height: 25%; float: left;"> | ||
## Support NeDB development | ||
No time to <a href="#help-out">help out</a>? You can support NeDB development by sending money or bitcoins! | ||
No time to <a href="#pull-requests">help out</a>? You can support NeDB development by sending money or bitcoins! | ||
@@ -112,3 +112,3 @@ Money: [![Donate to author](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=louis%2echatriot%40gmail%2ecom&lc=US¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHostedGuest) | ||
You can manually call the compaction function with `yourDatabase.persistence.compactDatafile` which takes no argument. It queues a compaction of the datafile in the executor, to be executed sequentially after all pending operations. | ||
You can manually call the compaction function with `yourDatabase.persistence.compactDatafile` which takes no argument. It queues a compaction of the datafile in the executor, to be executed sequentially after all pending operations. The datastore will fire a `compaction.done` event once compaction is finished. | ||
@@ -276,6 +276,13 @@ You can also set automatic compaction at regular intervals with `yourDatabase.persistence.setAutocompactionInterval(interval)`, `interval` in milliseconds (a minimum of 5s is enforced), and stop automatic compaction with `yourDatabase.persistence.stopAutocompaction()`. | ||
#### Array fields | ||
When a field in a document is an array, NeDB first tries to see if there is an array-specific comparison function (for now there is only `$size`) being used | ||
and tries it first. If there isn't, the query is treated as a query on every element and there is a match if at least one element matches. | ||
When a field in a document is an array, NeDB first tries to see if the query value is an array to perform an exact match, then whether there is an array-specific comparison function (for now there is only `$size`) being used. If not, the query is treated as a query on every element and there is a match if at least one element matches. | ||
```javascript | ||
// Exact match | ||
db.find({ satellites: ['Phobos', 'Deimos'] }, function (err, docs) { | ||
// docs contains Mars | ||
}) | ||
db.find({ satellites: ['Deimos', 'Phobos'] }, function (err, docs) { | ||
// docs is empty | ||
}) | ||
// Using an array-specific comparison function | ||
@@ -636,2 +643,10 @@ // Note: you can't use nested comparison functions, e.g. { $size: { $lt: 5 } } will throw an error | ||
## Pull requests | ||
If you submit a pull request, thanks! There are a couple rules to follow though to make it manageable: | ||
* The pull request should be atomic, i.e. contain only one feature. If it contains more, please submit multiple pull requests. Reviewing massive, 1000 loc+ pull requests is extremely hard. | ||
* Likewise, if for one unique feature the pull request grows too large (more than 200 loc tests not included), please get in touch first. | ||
* Please stick to the current coding style. It's important that the code uses a coherent style for readability. | ||
* Do not include sylistic improvements ("housekeeping"). If you think one part deserves lots of housekeeping, use a separate pull request so as not to pollute the code. | ||
* Don't forget tests for your new feature. Also don't forget to run the whole test suite before submitting to make sure you didn't introduce regressions. | ||
* Do not build the browser version in your branch, I'll take care of it once the code is merged. | ||
@@ -638,0 +653,0 @@ ## Bug reporting guidelines |
@@ -136,12 +136,12 @@ var model = require('../lib/model') | ||
}); | ||
it('Can serialize string fields with a new line without breaking the DB', function (done) { | ||
var db1, db2 | ||
, badString = "world\r\nearth\nother\rline" | ||
; | ||
; | ||
if (fs.existsSync('workspace/test1.db')) { fs.unlinkSync('workspace/test1.db'); } | ||
fs.existsSync('workspace/test1.db').should.equal(false); | ||
db1 = new Datastore({ filename: 'workspace/test1.db' }); | ||
db1.loadDatabase(function (err) { | ||
@@ -151,3 +151,3 @@ assert.isNull(err); | ||
assert.isNull(err); | ||
db2 = new Datastore({ filename: 'workspace/test1.db' }); | ||
@@ -1130,49 +1130,55 @@ db2.loadDatabase(function (err) { | ||
describe('Query operator array $size', function () { | ||
it('Can query on the size of an array field', function () { | ||
// Non nested documents | ||
model.match({ childrens: [ { name: "Huey", age: 3 }, { name: "Dewey", age: 7 }, { name: "Louie", age: 12 } ] }, { "childrens": { $size: 0 } }).should.equal(false); | ||
model.match({ childrens: [ { name: "Huey", age: 3 }, { name: "Dewey", age: 7 }, { name: "Louie", age: 12 } ] }, { "childrens": { $size: 1 } }).should.equal(false); | ||
model.match({ childrens: [ { name: "Huey", age: 3 }, { name: "Dewey", age: 7 }, { name: "Louie", age: 12 } ] }, { "childrens": { $size: 2 } }).should.equal(false); | ||
model.match({ childrens: [ { name: "Huey", age: 3 }, { name: "Dewey", age: 7 }, { name: "Louie", age: 12 } ] }, { "childrens": { $size: 3 } }).should.equal(true); | ||
// Nested documents | ||
model.match({ hello: 'world', description: { satellites: ['Moon', 'Hubble'], diameter: 6300 } }, { "description.satellites": { $size: 0 } }).should.equal(false); | ||
model.match({ hello: 'world', description: { satellites: ['Moon', 'Hubble'], diameter: 6300 } }, { "description.satellites": { $size: 1 } }).should.equal(false); | ||
model.match({ hello: 'world', description: { satellites: ['Moon', 'Hubble'], diameter: 6300 } }, { "description.satellites": { $size: 2 } }).should.equal(true); | ||
model.match({ hello: 'world', description: { satellites: ['Moon', 'Hubble'], diameter: 6300 } }, { "description.satellites": { $size: 3 } }).should.equal(false); | ||
describe('Comparing on arrays', function () { | ||
// Using a projected array | ||
model.match({ childrens: [ { name: "Huey", age: 3 }, { name: "Dewey", age: 7 }, { name: "Louie", age: 12 } ] }, { "childrens.names": { $size: 0 } }).should.equal(false); | ||
model.match({ childrens: [ { name: "Huey", age: 3 }, { name: "Dewey", age: 7 }, { name: "Louie", age: 12 } ] }, { "childrens.names": { $size: 1 } }).should.equal(false); | ||
model.match({ childrens: [ { name: "Huey", age: 3 }, { name: "Dewey", age: 7 }, { name: "Louie", age: 12 } ] }, { "childrens.names": { $size: 2 } }).should.equal(false); | ||
model.match({ childrens: [ { name: "Huey", age: 3 }, { name: "Dewey", age: 7 }, { name: "Louie", age: 12 } ] }, { "childrens.names": { $size: 3 } }).should.equal(true); | ||
}); | ||
it("Can perform a direct array match", function () { | ||
model.match({ planets: ['Earth', 'Mars', 'Pluto'], something: 'else' }, { planets: ['Earth', 'Mars'] }).should.equal(false); | ||
model.match({ planets: ['Earth', 'Mars', 'Pluto'], something: 'else' }, { planets: ['Earth', 'Mars', 'Pluto'] }).should.equal(true); | ||
model.match({ planets: ['Earth', 'Mars', 'Pluto'], something: 'else' }, { planets: ['Earth', 'Pluto', 'Mars'] }).should.equal(false); | ||
}); | ||
it('$size operator works with empty arrays', function () { | ||
model.match({ childrens: [] }, { "childrens": { $size: 0 } }).should.equal(true); | ||
model.match({ childrens: [] }, { "childrens": { $size: 2 } }).should.equal(false); | ||
model.match({ childrens: [] }, { "childrens": { $size: 3 } }).should.equal(false); | ||
}); | ||
it('Can query on the size of an array field', function () { | ||
// Non nested documents | ||
model.match({ childrens: [ { name: "Huey", age: 3 }, { name: "Dewey", age: 7 }, { name: "Louie", age: 12 } ] }, { "childrens": { $size: 0 } }).should.equal(false); | ||
model.match({ childrens: [ { name: "Huey", age: 3 }, { name: "Dewey", age: 7 }, { name: "Louie", age: 12 } ] }, { "childrens": { $size: 1 } }).should.equal(false); | ||
model.match({ childrens: [ { name: "Huey", age: 3 }, { name: "Dewey", age: 7 }, { name: "Louie", age: 12 } ] }, { "childrens": { $size: 2 } }).should.equal(false); | ||
model.match({ childrens: [ { name: "Huey", age: 3 }, { name: "Dewey", age: 7 }, { name: "Louie", age: 12 } ] }, { "childrens": { $size: 3 } }).should.equal(true); | ||
it('Should throw an error if a query operator is used without comparing to an integer', function () { | ||
(function () { model.match({ a: [1, 5] }, { a: { $size: 1.4 } }); }).should.throw(); | ||
(function () { model.match({ a: [1, 5] }, { a: { $size: 'fdf' } }); }).should.throw(); | ||
(function () { model.match({ a: [1, 5] }, { a: { $size: { $lt: 5 } } }); }).should.throw(); | ||
}); | ||
// Nested documents | ||
model.match({ hello: 'world', description: { satellites: ['Moon', 'Hubble'], diameter: 6300 } }, { "description.satellites": { $size: 0 } }).should.equal(false); | ||
model.match({ hello: 'world', description: { satellites: ['Moon', 'Hubble'], diameter: 6300 } }, { "description.satellites": { $size: 1 } }).should.equal(false); | ||
model.match({ hello: 'world', description: { satellites: ['Moon', 'Hubble'], diameter: 6300 } }, { "description.satellites": { $size: 2 } }).should.equal(true); | ||
model.match({ hello: 'world', description: { satellites: ['Moon', 'Hubble'], diameter: 6300 } }, { "description.satellites": { $size: 3 } }).should.equal(false); | ||
it('Using $size operator on a non-array field should prevent match but not throw', function () { | ||
model.match({ a: 5 }, { a: { $size: 1 } }).should.equal(false); | ||
}); | ||
it('Can use $size several times in the same matcher', function () { | ||
model.match({ childrens: [ 'Riri', 'Fifi', 'Loulou' ] }, { "childrens": { $size: 3, $size: 3 } }).should.equal(true); | ||
model.match({ childrens: [ 'Riri', 'Fifi', 'Loulou' ] }, { "childrens": { $size: 3, $size: 4 } }).should.equal(false); // Of course this can never be true | ||
}); | ||
// Using a projected array | ||
model.match({ childrens: [ { name: "Huey", age: 3 }, { name: "Dewey", age: 7 }, { name: "Louie", age: 12 } ] }, { "childrens.names": { $size: 0 } }).should.equal(false); | ||
model.match({ childrens: [ { name: "Huey", age: 3 }, { name: "Dewey", age: 7 }, { name: "Louie", age: 12 } ] }, { "childrens.names": { $size: 1 } }).should.equal(false); | ||
model.match({ childrens: [ { name: "Huey", age: 3 }, { name: "Dewey", age: 7 }, { name: "Louie", age: 12 } ] }, { "childrens.names": { $size: 2 } }).should.equal(false); | ||
model.match({ childrens: [ { name: "Huey", age: 3 }, { name: "Dewey", age: 7 }, { name: "Louie", age: 12 } ] }, { "childrens.names": { $size: 3 } }).should.equal(true); | ||
}); | ||
it('$size operator works with empty arrays', function () { | ||
model.match({ childrens: [] }, { "childrens": { $size: 0 } }).should.equal(true); | ||
model.match({ childrens: [] }, { "childrens": { $size: 2 } }).should.equal(false); | ||
model.match({ childrens: [] }, { "childrens": { $size: 3 } }).should.equal(false); | ||
}); | ||
it('Should throw an error if a query operator is used without comparing to an integer', function () { | ||
(function () { model.match({ a: [1, 5] }, { a: { $size: 1.4 } }); }).should.throw(); | ||
(function () { model.match({ a: [1, 5] }, { a: { $size: 'fdf' } }); }).should.throw(); | ||
(function () { model.match({ a: [1, 5] }, { a: { $size: { $lt: 5 } } }); }).should.throw(); | ||
}); | ||
it('Using $size operator on a non-array field should prevent match but not throw', function () { | ||
model.match({ a: 5 }, { a: { $size: 1 } }).should.equal(false); | ||
}); | ||
it('Can use $size several times in the same matcher', function () { | ||
model.match({ childrens: [ 'Riri', 'Fifi', 'Loulou' ] }, { "childrens": { $size: 3, $size: 3 } }).should.equal(true); | ||
model.match({ childrens: [ 'Riri', 'Fifi', 'Loulou' ] }, { "childrens": { $size: 3, $size: 4 } }).should.equal(false); // Of course this can never be true | ||
}); | ||
}); | ||
describe('Logical operators $or, $and, $not', function () { | ||
@@ -1179,0 +1185,0 @@ |
@@ -147,3 +147,3 @@ var should = require('chai').should() | ||
_.isEqual(treatedData[1], { _id: "3", today: now }).should.equal(true); | ||
}); | ||
}); | ||
@@ -303,3 +303,12 @@ it('Compact database on load', function (done) { | ||
it("Can listen to compaction events", function (done) { | ||
d.on('compaction.done', function () { | ||
d.removeAllListeners('compaction.done'); // Tidy up for next tests | ||
done(); | ||
}); | ||
d.persistence.compactDatafile(); | ||
}); | ||
describe('Serialization hooks', function () { | ||
@@ -306,0 +315,0 @@ var as = function (s) { return "before_" + s + "_after"; } |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
1269792
28582
663