Can now use with any nedb query

pull/2/head
Louis Chatriot 11 years ago
parent 04dd0d3a9c
commit af426c5141
  1. 8
      README.md
  2. 30
      lib/model.js
  3. 89
      test/model.test.js

@ -350,11 +350,15 @@ db.update({ _id: 'id6' }, { $addToSet: { fruits: 'apple' } }, {}, function () {
// If we had used a fruit not in the array, e.g. 'banana', it would have been added to the array // If we had used a fruit not in the array, e.g. 'banana', it would have been added to the array
}); });
// $pull removes all instances of a value from an existing array // $pull removes all values matching a value or even any NeDB query from the array
// Equality is deep-checked
db.update({ _id: 'id6' }, { $pull: { fruits: 'apple' } }, {}, function () { db.update({ _id: 'id6' }, { $pull: { fruits: 'apple' } }, {}, function () {
// Now the fruits array is ['orange', 'pear'] // Now the fruits array is ['orange', 'pear']
}); });
db.update({ _id: 'id6' }, { $pull: { fruits: $in: ['apple', 'pear'] } }, {}, function () {
// Now the fruits array is ['orange']
});
// $each can be used to $push or $addToSet multiple values at once // $each can be used to $push or $addToSet multiple values at once
// This example works the same way with $addToSet // This example works the same way with $addToSet

@ -141,7 +141,7 @@ function isPrimitiveType (obj) {
typeof obj === 'string' || typeof obj === 'string' ||
obj === null || obj === null ||
util.isDate(obj) || util.isDate(obj) ||
util.isArray(obj)); util.isArray(obj));
} }
@ -619,21 +619,27 @@ logicalOperators.$not = function (obj, query) {
* @param {Object} query * @param {Object} query
*/ */
function match (obj, query) { function match (obj, query) {
var queryKeys = Object.keys(query) var queryKeys, queryKey, queryValue, i;
, queryKey, queryValue
, i
;
// Primitive query against a primitive type
// This is a bit of a hack since we construct an object with an arbitrary key only to dereference it later
// But I don't have time for a cleaner implementation now
if (isPrimitiveType(obj) || isPrimitiveType(query)) {
return matchQueryPart({ needAKey: obj }, 'needAKey', query);
}
// Normal query
queryKeys = Object.keys(query);
for (i = 0; i < queryKeys.length; i += 1) { for (i = 0; i < queryKeys.length; i += 1) {
queryKey = queryKeys[i]; queryKey = queryKeys[i];
queryValue = query[queryKey]; queryValue = query[queryKey];
if (queryKey[0] === '$') { if (queryKey[0] === '$') {
if (!logicalOperators[queryKey]) { throw "Unknown logical operator " + queryKey; } if (!logicalOperators[queryKey]) { throw "Unknown logical operator " + queryKey; }
if (!logicalOperators[queryKey](obj, queryValue)) { return false; } if (!logicalOperators[queryKey](obj, queryValue)) { return false; }
} else { } else {
if (!matchQueryPart(obj, queryKey, queryValue)) { return false; } if (!matchQueryPart(obj, queryKey, queryValue)) { return false; }
} }
} }
return true; return true;
@ -645,8 +651,7 @@ function match (obj, query) {
*/ */
function matchQueryPart (obj, queryKey, queryValue) { function matchQueryPart (obj, queryKey, queryValue) {
var objValue = getDotValue(obj, queryKey) var objValue = getDotValue(obj, queryKey)
, i, keys, firstChars, dollarFirstChars , i, keys, firstChars, dollarFirstChars;
;
// Check if the object value is an array treat it as an array of { obj, query } // Check if the object value is an array treat it as an array of { obj, query }
// Where there needs to be at least one match // Where there needs to be at least one match
@ -695,6 +700,7 @@ module.exports.serialize = serialize;
module.exports.deserialize = deserialize; module.exports.deserialize = deserialize;
module.exports.deepCopy = deepCopy; module.exports.deepCopy = deepCopy;
module.exports.checkObject = checkObject; module.exports.checkObject = checkObject;
module.exports.isPrimitiveType = isPrimitiveType;
module.exports.modify = modify; module.exports.modify = modify;
module.exports.getDotValue = getDotValue; module.exports.getDotValue = getDotValue;
module.exports.match = match; module.exports.match = match;

@ -165,10 +165,21 @@ describe('Model', function () {
model.checkObject(obj); model.checkObject(obj);
}); });
it.only('Can check if an object is a primitive or not', function () { it('Can check if an object is a primitive or not', function () {
model.isPrimitiveType(5).should.equal(true);
}); model.isPrimitiveType('sdsfdfs').should.equal(true);
model.isPrimitiveType(0).should.equal(true);
model.isPrimitiveType(true).should.equal(true);
model.isPrimitiveType(false).should.equal(true);
model.isPrimitiveType(new Date()).should.equal(true);
model.isPrimitiveType([]).should.equal(true);
model.isPrimitiveType([3, 'try']).should.equal(true);
model.isPrimitiveType(null).should.equal(true);
model.isPrimitiveType({}).should.equal(false);
model.isPrimitiveType({ a: 42 }).should.equal(false);
});
}); // ==== End of 'Object checking' ==== // }); // ==== End of 'Object checking' ==== //
@ -300,48 +311,48 @@ describe('Model', function () {
_.isEqual(modified, { yup: { subfield: 'changed', yop: 'yes indeed' }, totally: { doesnt: { exist: 'now it does' } } }).should.equal(true); _.isEqual(modified, { yup: { subfield: 'changed', yop: 'yes indeed' }, totally: { doesnt: { exist: 'now it does' } } }).should.equal(true);
}); });
}); // End of '$set modifier' }); // End of '$set modifier'
describe('$unset modifier', function () { describe('$unset modifier', function () {
it('Can delete a field, not throwing an error if the field doesnt exist', function () { it('Can delete a field, not throwing an error if the field doesnt exist', function () {
var obj, updateQuery, modified; var obj, updateQuery, modified;
obj = { yup: 'yes', other: 'also' } obj = { yup: 'yes', other: 'also' }
updateQuery = { $unset: { yup: true } } updateQuery = { $unset: { yup: true } }
modified = model.modify(obj, updateQuery); modified = model.modify(obj, updateQuery);
assert.deepEqual(modified, { other: 'also' }); assert.deepEqual(modified, { other: 'also' });
obj = { yup: 'yes', other: 'also' } obj = { yup: 'yes', other: 'also' }
updateQuery = { $unset: { nope: true } } updateQuery = { $unset: { nope: true } }
modified = model.modify(obj, updateQuery); modified = model.modify(obj, updateQuery);
assert.deepEqual(modified, obj); assert.deepEqual(modified, obj);
obj = { yup: 'yes', other: 'also' } obj = { yup: 'yes', other: 'also' }
updateQuery = { $unset: { nope: true, other: true } } updateQuery = { $unset: { nope: true, other: true } }
modified = model.modify(obj, updateQuery); modified = model.modify(obj, updateQuery);
assert.deepEqual(modified, { yup: 'yes' }); assert.deepEqual(modified, { yup: 'yes' });
}); });
it('Can unset sub-fields and entire nested documents', function () { it('Can unset sub-fields and entire nested documents', function () {
var obj, updateQuery, modified; var obj, updateQuery, modified;
obj = { yup: 'yes', nested: { a: 'also', b: 'yeah' } } obj = { yup: 'yes', nested: { a: 'also', b: 'yeah' } }
updateQuery = { $unset: { nested: true } } updateQuery = { $unset: { nested: true } }
modified = model.modify(obj, updateQuery); modified = model.modify(obj, updateQuery);
assert.deepEqual(modified, { yup: 'yes' }); assert.deepEqual(modified, { yup: 'yes' });
obj = { yup: 'yes', nested: { a: 'also', b: 'yeah' } } obj = { yup: 'yes', nested: { a: 'also', b: 'yeah' } }
updateQuery = { $unset: { 'nested.a': true } } updateQuery = { $unset: { 'nested.a': true } }
modified = model.modify(obj, updateQuery); modified = model.modify(obj, updateQuery);
assert.deepEqual(modified, { yup: 'yes', nested: { b: 'yeah' } }); assert.deepEqual(modified, { yup: 'yes', nested: { b: 'yeah' } });
obj = { yup: 'yes', nested: { a: 'also', b: 'yeah' } } obj = { yup: 'yes', nested: { a: 'also', b: 'yeah' } }
updateQuery = { $unset: { 'nested.a': true, 'nested.b': true } } updateQuery = { $unset: { 'nested.a': true, 'nested.b': true } }
modified = model.modify(obj, updateQuery); modified = model.modify(obj, updateQuery);
assert.deepEqual(modified, { yup: 'yes', nested: {} }); assert.deepEqual(modified, { yup: 'yes', nested: {} });
}); });
}); // End of '$unset modifier' }); // End of '$unset modifier'
describe('$inc modifier', function () { describe('$inc modifier', function () {
it('Throw an error if you try to use it with a non-number or on a non number field', function () { it('Throw an error if you try to use it with a non-number or on a non number field', function () {
@ -545,7 +556,7 @@ describe('Model', function () {
}); // End of '$pop modifier' }); // End of '$pop modifier'
describe.skip('$pull modifier', function () { describe('$pull modifier', function () {
it('Can remove an element from a set', function () { it('Can remove an element from a set', function () {
var obj = { arr: ['hello', 'world'] } var obj = { arr: ['hello', 'world'] }
@ -587,19 +598,19 @@ describe('Model', function () {
modified = model.modify(obj, { $pull: { arr: { b: 3 } } }); modified = model.modify(obj, { $pull: { arr: { b: 3 } } });
assert.deepEqual(modified, { arr: [{ b: 2 }] }); assert.deepEqual(modified, { arr: [{ b: 2 }] });
}); });
it('Can use any kind of nedb query with $pull', function () { it('Can use any kind of nedb query with $pull', function () {
var obj = { arr: [4, 7, 12, 2], other: 'yup' } var obj = { arr: [4, 7, 12, 2], other: 'yup' }
, modified , modified
; ;
// modified = model.modify(obj, { $pull: { arr: { $gte: 5 } } }); modified = model.modify(obj, { $pull: { arr: { $gte: 5 } } });
// assert.deepEqual(modified, { arr: [4, 2], other: 'yup' }); assert.deepEqual(modified, { arr: [4, 2], other: 'yup' });
// obj = { arr: [{ b: 4 }, { b: 7 }, { b: 1 }], other: 'yeah' }; obj = { arr: [{ b: 4 }, { b: 7 }, { b: 1 }], other: 'yeah' };
// modified = model.modify(obj, { $pull: { arr: { b: { $gte: 5} } } }); modified = model.modify(obj, { $pull: { arr: { b: { $gte: 5} } } });
// assert.deepEqual(modified, { arr: [{ b: 4 }, { b: 1 }], other: 'yeah' }); assert.deepEqual(modified, { arr: [{ b: 4 }, { b: 1 }], other: 'yeah' });
}); });
}); // End of '$pull modifier' }); // End of '$pull modifier'

Loading…
Cancel
Save