mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Removed underscore from minimongo.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
// arrays.
|
||||
// XXX maybe this should be EJSON.isArray
|
||||
isArray = function (x) {
|
||||
return _.isArray(x) && !EJSON.isBinary(x);
|
||||
return Array.isArray(x) && !EJSON.isBinary(x);
|
||||
};
|
||||
|
||||
// XXX maybe this should be EJSON.isObject, though EJSON doesn't know about
|
||||
@@ -24,7 +24,7 @@ isOperatorObject = function (valueSelector, inconsistentOK) {
|
||||
return false;
|
||||
|
||||
var theseAreOperators = undefined;
|
||||
_.each(valueSelector, function (value, selKey) {
|
||||
Object.keys(valueSelector).forEach(function (selKey) {
|
||||
var thisIsOperator = selKey.substr(0, 1) === '$';
|
||||
if (theseAreOperators === undefined) {
|
||||
theseAreOperators = thisIsOperator;
|
||||
@@ -42,4 +42,4 @@ isOperatorObject = function (valueSelector, inconsistentOK) {
|
||||
// string can be converted to integer
|
||||
isNumericKey = function (s) {
|
||||
return /^[0-9]+$/.test(s);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -170,7 +170,7 @@ LocalCollection.Cursor.prototype.forEach = function (callback, thisArg) {
|
||||
movedBefore: true});
|
||||
}
|
||||
|
||||
_.each(objects, function (elt, i) {
|
||||
objects.forEach(function (elt, i) {
|
||||
// This doubles as a clone operation.
|
||||
elt = self._projectionFn(elt);
|
||||
|
||||
@@ -298,7 +298,7 @@ LocalCollection.ObserveHandle = function () {};
|
||||
// XXX maybe callbacks should take a list of objects, to expose transactions?
|
||||
// XXX maybe support field limiting (to limit what you're notified on)
|
||||
|
||||
_.extend(LocalCollection.Cursor.prototype, {
|
||||
Object.assign(LocalCollection.Cursor.prototype, {
|
||||
/**
|
||||
* @summary Watch a query. Receive callbacks as the result set changes.
|
||||
* @locus Anywhere
|
||||
@@ -388,11 +388,9 @@ _.extend(LocalCollection.Cursor.prototype, {
|
||||
}
|
||||
|
||||
if (!options._suppress_initial && !self.collection.paused) {
|
||||
// XXX unify ordered and unordered interface
|
||||
var each = ordered
|
||||
? _.bind(_.each, null, query.results)
|
||||
: _.bind(query.results.forEach, query.results);
|
||||
each(function (doc) {
|
||||
var results = query.results._map || query.results;
|
||||
Object.keys(results).forEach(function (key) {
|
||||
var doc = results[key];
|
||||
var fields = EJSON.clone(doc);
|
||||
|
||||
delete fields._id;
|
||||
@@ -403,7 +401,7 @@ _.extend(LocalCollection.Cursor.prototype, {
|
||||
}
|
||||
|
||||
var handle = new LocalCollection.ObserveHandle;
|
||||
_.extend(handle, {
|
||||
Object.assign(handle, {
|
||||
collection: self.collection,
|
||||
stop: function () {
|
||||
if (self.reactive)
|
||||
@@ -525,17 +523,16 @@ LocalCollection.Cursor.prototype._depend = function (changers, _allow_unordered)
|
||||
if (Tracker.active) {
|
||||
var v = new Tracker.Dependency;
|
||||
v.depend();
|
||||
var notifyChange = _.bind(v.changed, v);
|
||||
var notifyChange = v.changed.bind(v);
|
||||
|
||||
var options = {
|
||||
_suppress_initial: true,
|
||||
_allow_unordered: _allow_unordered
|
||||
};
|
||||
_.each(['added', 'changed', 'removed', 'addedBefore', 'movedBefore'],
|
||||
function (fnName) {
|
||||
if (changers[fnName])
|
||||
options[fnName] = notifyChange;
|
||||
});
|
||||
['added', 'changed', 'removed', 'addedBefore', 'movedBefore'].forEach(function (fnName) {
|
||||
if (changers[fnName])
|
||||
options[fnName] = notifyChange;
|
||||
});
|
||||
|
||||
// observeChanges will stop() when this computation is invalidated
|
||||
self.observeChanges(options);
|
||||
@@ -550,7 +547,7 @@ LocalCollection.prototype.insert = function (doc, callback) {
|
||||
|
||||
assertHasValidFieldNames(doc);
|
||||
|
||||
if (!_.has(doc, '_id')) {
|
||||
if (!doc.hasOwnProperty('_id')) {
|
||||
// if you really want to use ObjectIDs, set this global.
|
||||
// Mongo.Collection specifies its own ids and does not use this code.
|
||||
doc._id = LocalCollection._useOID ? new MongoID.ObjectID()
|
||||
@@ -580,7 +577,7 @@ LocalCollection.prototype.insert = function (doc, callback) {
|
||||
}
|
||||
}
|
||||
|
||||
_.each(queriesToRecompute, function (qid) {
|
||||
queriesToRecompute.forEach(function (qid) {
|
||||
if (self.queries[qid])
|
||||
self._recomputeResults(self.queries[qid]);
|
||||
});
|
||||
@@ -626,7 +623,8 @@ LocalCollection.prototype.remove = function (selector, callback) {
|
||||
if (self.paused && !self._savedOriginals && EJSON.equals(selector, {})) {
|
||||
var result = self._docs.size();
|
||||
self._docs.clear();
|
||||
_.each(self.queries, function (query) {
|
||||
Object.keys(self.queries).forEach(function (qid) {
|
||||
var query = self.queries[qid];
|
||||
if (query.ordered) {
|
||||
query.results = [];
|
||||
} else {
|
||||
@@ -653,7 +651,8 @@ LocalCollection.prototype.remove = function (selector, callback) {
|
||||
for (var i = 0; i < remove.length; i++) {
|
||||
var removeId = remove[i];
|
||||
var removeDoc = self._docs.get(removeId);
|
||||
_.each(self.queries, function (query, qid) {
|
||||
Object.keys(self.queries).forEach(function (qid) {
|
||||
var query = self.queries[qid];
|
||||
if (query.dirty) return;
|
||||
|
||||
if (query.matcher.documentMatches(removeDoc).result) {
|
||||
@@ -668,14 +667,14 @@ LocalCollection.prototype.remove = function (selector, callback) {
|
||||
}
|
||||
|
||||
// run live query callbacks _after_ we've removed the documents.
|
||||
_.each(queryRemove, function (remove) {
|
||||
queryRemove.forEach(function (remove) {
|
||||
var query = self.queries[remove.qid];
|
||||
if (query) {
|
||||
query.distances && query.distances.remove(remove.doc._id);
|
||||
LocalCollection._removeFromResults(query, remove.doc);
|
||||
}
|
||||
});
|
||||
_.each(queriesToRecompute, function (qid) {
|
||||
queriesToRecompute.forEach(function (qid) {
|
||||
var query = self.queries[qid];
|
||||
if (query)
|
||||
self._recomputeResults(query);
|
||||
@@ -711,7 +710,8 @@ LocalCollection.prototype.update = function (selector, mod, options, callback) {
|
||||
var docMap = new LocalCollection._IdMap;
|
||||
var idsMatchedBySelector = LocalCollection._idsMatchedBySelector(selector);
|
||||
|
||||
_.each(self.queries, function (query, qid) {
|
||||
Object.keys(self.queries).forEach(function (qid) {
|
||||
var query = self.queries[qid];
|
||||
if ((query.cursor.skip || query.cursor.limit) && ! self.paused) {
|
||||
// Catch the case of a reactive `count()` on a cursor with skip
|
||||
// or limit, which registers an unordered observe. This is a
|
||||
@@ -737,7 +737,7 @@ LocalCollection.prototype.update = function (selector, mod, options, callback) {
|
||||
} else {
|
||||
var docToMemoize;
|
||||
|
||||
if (idsMatchedBySelector && !_.any(idsMatchedBySelector, function(id) {
|
||||
if (idsMatchedBySelector && !idsMatchedBySelector.some(function(id) {
|
||||
return EJSON.equals(id, doc._id);
|
||||
})) {
|
||||
docToMemoize = doc;
|
||||
@@ -770,7 +770,7 @@ LocalCollection.prototype.update = function (selector, mod, options, callback) {
|
||||
return true;
|
||||
});
|
||||
|
||||
_.each(recomputeQids, function (dummy, qid) {
|
||||
Object.keys(recomputeQids).forEach(function (qid) {
|
||||
var query = self.queries[qid];
|
||||
if (query)
|
||||
self._recomputeResults(query, qidToOriginalResults[qid]);
|
||||
@@ -783,8 +783,8 @@ LocalCollection.prototype.update = function (selector, mod, options, callback) {
|
||||
var insertedId;
|
||||
if (updateCount === 0 && options.upsert) {
|
||||
|
||||
let selectorModifier = LocalCollection._selectorIsId(selector)
|
||||
? { _id: selector }
|
||||
let selectorModifier = LocalCollection._selectorIsId(selector)
|
||||
? { _id: selector }
|
||||
: selector;
|
||||
|
||||
selectorModifier = LocalCollection._removeDollarOperators(selectorModifier);
|
||||
@@ -795,7 +795,7 @@ LocalCollection.prototype.update = function (selector, mod, options, callback) {
|
||||
delete selectorModifier._id;
|
||||
}
|
||||
|
||||
// This double _modify call is made to help work around an issue where collection
|
||||
// This double _modify call is made to help work around an issue where collection
|
||||
// upserts won't work properly, with nested properties (see issue #8631).
|
||||
LocalCollection._modify(newDoc, {$set: selectorModifier});
|
||||
LocalCollection._modify(newDoc, mod, {isInsert: true});
|
||||
@@ -836,7 +836,7 @@ LocalCollection.prototype.upsert = function (selector, mod, options, callback) {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
return self.update(selector, mod, _.extend({}, options, {
|
||||
return self.update(selector, mod, Object.assign({}, options, {
|
||||
upsert: true,
|
||||
_returnObject: true
|
||||
}), callback);
|
||||
@@ -945,7 +945,7 @@ LocalCollection._updateInResults = function (query, doc, old_doc) {
|
||||
projectionFn(doc), projectionFn(old_doc));
|
||||
|
||||
if (!query.ordered) {
|
||||
if (!_.isEmpty(changedFields)) {
|
||||
if (Object.keys(changedFields).length) {
|
||||
query.changed(doc._id, changedFields);
|
||||
query.results.set(doc._id, doc);
|
||||
}
|
||||
@@ -954,7 +954,7 @@ LocalCollection._updateInResults = function (query, doc, old_doc) {
|
||||
|
||||
var orig_idx = LocalCollection._findInOrderedResults(query, doc);
|
||||
|
||||
if (!_.isEmpty(changedFields))
|
||||
if (Object.keys(changedFields).length)
|
||||
query.changed(doc._id, changedFields);
|
||||
if (!query.sorter)
|
||||
return;
|
||||
|
||||
@@ -241,7 +241,11 @@ Tinytest.add("minimongo - transform", function (test) {
|
||||
});
|
||||
|
||||
// transformed documents get _id field transplanted if not present
|
||||
var transformWithoutId = function (doc) { return _.omit(doc, '_id'); };
|
||||
var transformWithoutId = function (doc) {
|
||||
var docWithoutId = Object.assign({}, doc);
|
||||
delete docWithoutId._id;
|
||||
return docWithoutId;
|
||||
};
|
||||
test.equal(c.findOne({}, {transform: transformWithoutId})._id,
|
||||
c.findOne()._id);
|
||||
});
|
||||
@@ -333,8 +337,8 @@ Tinytest.add("minimongo - selector_compiler", function (test) {
|
||||
}
|
||||
};
|
||||
|
||||
var match = _.bind(matches, null, true);
|
||||
var nomatch = _.bind(matches, null, false);
|
||||
var match = matches.bind(null, true);
|
||||
var nomatch = matches.bind(null, false);
|
||||
|
||||
// XXX blog post about what I learned while writing these tests (weird
|
||||
// mongo edge cases)
|
||||
@@ -513,14 +517,14 @@ Tinytest.add("minimongo - selector_compiler", function (test) {
|
||||
nomatch({a: {$mod: [10, 1]}}, {a: 12});
|
||||
match({a: {$mod: [10, 1]}}, {a: [10, 11, 12]});
|
||||
nomatch({a: {$mod: [10, 1]}}, {a: [10, 12]});
|
||||
_.each([
|
||||
[
|
||||
5,
|
||||
[10],
|
||||
[10, 1, 2],
|
||||
"foo",
|
||||
{bar: 1},
|
||||
[]
|
||||
], function (badMod) {
|
||||
].forEach(function (badMod) {
|
||||
test.throws(function () {
|
||||
match({a: {$mod: badMod}}, {a: 11});
|
||||
});
|
||||
@@ -866,9 +870,9 @@ Tinytest.add("minimongo - selector_compiler", function (test) {
|
||||
nomatch({a: {$bitsAllSet: 1}}, {a: ['a', 'b']})
|
||||
nomatch({a: {$bitsAllSet: 1}}, {a: {foo: 'bar'}})
|
||||
nomatch({a: {$bitsAllSet: 1}}, {a: 1.2})
|
||||
nomatch({a: {$bitsAllSet: 1}}, {a: "1"})
|
||||
nomatch({a: {$bitsAllSet: 1}}, {a: "1"});
|
||||
|
||||
_.each([
|
||||
[
|
||||
false,
|
||||
NaN,
|
||||
Infinity,
|
||||
@@ -879,7 +883,7 @@ Tinytest.add("minimongo - selector_compiler", function (test) {
|
||||
1.2,
|
||||
"1",
|
||||
[0, -1]
|
||||
], function (badValue) {
|
||||
].forEach(function (badValue) {
|
||||
test.throws(function () {
|
||||
match({a: {$bitsAllSet: badValue}}, {a: 42});
|
||||
});
|
||||
@@ -1441,10 +1445,10 @@ Tinytest.add("minimongo - projection_compiler", function (test) {
|
||||
var testProjection = function (projection, tests) {
|
||||
var projection_f = LocalCollection._compileProjection(projection);
|
||||
var equalNonStrict = function (a, b, desc) {
|
||||
test.isTrue(_.isEqual(a, b), desc);
|
||||
test.isTrue(EJSON.equals(a, b), desc);
|
||||
};
|
||||
|
||||
_.each(tests, function (testCase) {
|
||||
tests.forEach(function (testCase) {
|
||||
equalNonStrict(projection_f(testCase[0]), testCase[1], testCase[2]);
|
||||
});
|
||||
};
|
||||
@@ -1570,7 +1574,7 @@ Tinytest.add("minimongo - projection_compiler", function (test) {
|
||||
|
||||
Tinytest.add("minimongo - fetch with fields", function (test) {
|
||||
var c = new LocalCollection();
|
||||
_.times(30, function (i) {
|
||||
Array.from({length: 30}, function (_, i) {
|
||||
c.insert({
|
||||
something: Random.id(),
|
||||
anything: {
|
||||
@@ -1588,14 +1592,14 @@ Tinytest.add("minimongo - fetch with fields", function (test) {
|
||||
'anything.foo': 1
|
||||
} }).fetch();
|
||||
|
||||
test.isTrue(_.all(fetchResults, function (x) {
|
||||
test.isTrue(fetchResults.every(function (x) {
|
||||
return x &&
|
||||
x.something &&
|
||||
x.anything &&
|
||||
x.anything.foo &&
|
||||
x.anything.foo === "bar" &&
|
||||
!_.has(x, 'nothing') &&
|
||||
!_.has(x.anything, 'cool');
|
||||
!x.hasOwnProperty('nothing') &&
|
||||
!x.anything.hasOwnProperty('cool');
|
||||
}));
|
||||
|
||||
// Test with a selector, even field used in the selector is excluded in the
|
||||
@@ -1606,13 +1610,13 @@ Tinytest.add("minimongo - fetch with fields", function (test) {
|
||||
fields: { nothing: 0 }
|
||||
}).fetch();
|
||||
|
||||
test.isTrue(_.all(fetchResults, function (x) {
|
||||
test.isTrue(fetchResults.every(function (x) {
|
||||
return x &&
|
||||
x.something &&
|
||||
x.anything &&
|
||||
x.anything.foo === "bar" &&
|
||||
x.anything.cool === "hot" &&
|
||||
!_.has(x, 'nothing') &&
|
||||
!x.hasOwnProperty('nothing') &&
|
||||
x.i &&
|
||||
x.i >= 5;
|
||||
}));
|
||||
@@ -1634,13 +1638,13 @@ Tinytest.add("minimongo - fetch with fields", function (test) {
|
||||
}
|
||||
}).fetch();
|
||||
|
||||
test.isTrue(_.all(fetchResults, function (x) {
|
||||
test.isTrue(fetchResults.every(function (x) {
|
||||
return x &&
|
||||
x.something &&
|
||||
x.i >= 10 && x.i < 20;
|
||||
}));
|
||||
|
||||
_.each(fetchResults, function (x, i, arr) {
|
||||
fetchResults.forEach(function (x, i, arr) {
|
||||
if (!i) return;
|
||||
test.isTrue(x.i === arr[i-1].i + 1);
|
||||
});
|
||||
@@ -1685,7 +1689,7 @@ Tinytest.add("minimongo - fetch with projection, subarrays", function (test) {
|
||||
});
|
||||
|
||||
var equalNonStrict = function (a, b, desc) {
|
||||
test.isTrue(_.isEqual(a, b), desc);
|
||||
test.isTrue(EJSON.equals(a, b), desc);
|
||||
};
|
||||
|
||||
var testForProjection = function (projection, expected) {
|
||||
@@ -1796,7 +1800,7 @@ Tinytest.add("minimongo - observe ordered with projection", function (test) {
|
||||
handle.stop();
|
||||
|
||||
// test _suppress_initial
|
||||
handle = c.find({}, {sort: {a: -1}, fields: { a: 1 }}).observe(_.extend(cbs, {_suppress_initial: true}));
|
||||
handle = c.find({}, {sort: {a: -1}, fields: { a: 1 }}).observe(Object.assign(cbs, {_suppress_initial: true}));
|
||||
test.equal(operations.shift(), undefined);
|
||||
c.insert({a:100, b: { foo: "bar" }});
|
||||
test.equal(operations.shift(), ['added', {a:100}, 0, idA2]);
|
||||
@@ -1826,7 +1830,7 @@ Tinytest.add("minimongo - observe ordered with projection", function (test) {
|
||||
// test _no_indices
|
||||
|
||||
c.remove({});
|
||||
handle = c.find({}, {sort: {a: 1}, fields: { a: 1 }}).observe(_.extend(cbs, {_no_indices: true}));
|
||||
handle = c.find({}, {sort: {a: 1}, fields: { a: 1 }}).observe(Object.assign(cbs, {_no_indices: true}));
|
||||
c.insert({_id: 'foo', a:1, zoo: "crazy"});
|
||||
test.equal(operations.shift(), ['added', {a:1}, -1, null]);
|
||||
c.update({a:1}, {$set: {a: 2, foobar: "player"}});
|
||||
@@ -1875,7 +1879,7 @@ Tinytest.add("minimongo - ordering", function (test) {
|
||||
|
||||
// document ordering under a sort specification
|
||||
var verify = function (sorts, docs) {
|
||||
_.each(_.isArray(sorts) ? sorts : [sorts], function (sort) {
|
||||
(Array.isArray(sorts) ? sorts : [sorts]).forEach(function (sort) {
|
||||
var sorter = new Minimongo.Sorter(sort);
|
||||
assert_ordering(test, sorter.getComparator(), docs);
|
||||
});
|
||||
@@ -2050,25 +2054,25 @@ Tinytest.add("minimongo - subkey sort", function (test) {
|
||||
c.insert({a: {b: 1}});
|
||||
c.insert({a: {b: 3}});
|
||||
test.equal(
|
||||
_.pluck(c.find({}, {sort: {'a.b': -1}}).fetch(), 'a'),
|
||||
c.find({}, {sort: {'a.b': -1}}).fetch().map(function (doc) { return doc.a; }),
|
||||
[{b: 3}, {b: 2}, {b: 1}]);
|
||||
|
||||
// isn't an object
|
||||
c.insert({a: 1});
|
||||
test.equal(
|
||||
_.pluck(c.find({}, {sort: {'a.b': 1}}).fetch(), 'a'),
|
||||
c.find({}, {sort: {'a.b': 1}}).fetch().map(function (doc) { return doc.a; }),
|
||||
[1, {b: 1}, {b: 2}, {b: 3}]);
|
||||
|
||||
// complex object
|
||||
c.insert({a: {b: {c: 1}}});
|
||||
test.equal(
|
||||
_.pluck(c.find({}, {sort: {'a.b': -1}}).fetch(), 'a'),
|
||||
c.find({}, {sort: {'a.b': -1}}).fetch().map(function (doc) { return doc.a; }),
|
||||
[{b: {c: 1}}, {b: 3}, {b: 2}, {b: 1}, 1]);
|
||||
|
||||
// no such top level prop
|
||||
c.insert({c: 1});
|
||||
test.equal(
|
||||
_.pluck(c.find({}, {sort: {'a.b': -1}}).fetch(), 'a'),
|
||||
c.find({}, {sort: {'a.b': -1}}).fetch().map(function (doc) { return doc.a; }),
|
||||
[{b: {c: 1}}, {b: 3}, {b: 2}, {b: 1}, 1, undefined]);
|
||||
|
||||
// no such mid level prop. just test that it doesn't throw.
|
||||
@@ -2099,11 +2103,11 @@ Tinytest.add("minimongo - array sort", function (test) {
|
||||
var testCursorMatchesField = function (cursor, field) {
|
||||
var fieldValues = [];
|
||||
c.find().forEach(function (doc) {
|
||||
if (_.has(doc, field))
|
||||
if (doc.hasOwnProperty(field))
|
||||
fieldValues.push(doc[field]);
|
||||
});
|
||||
test.equal(_.pluck(cursor.fetch(), field),
|
||||
_.range(_.max(fieldValues) + 1));
|
||||
test.equal(cursor.fetch().map(function (doc) { return doc[field]; }),
|
||||
Array.from({length: Math.max.apply(null, fieldValues) + 1}, function (_, i) { return i; }));
|
||||
};
|
||||
|
||||
testCursorMatchesField(c.find({}, {sort: {'a.x': 1}}), 'up');
|
||||
@@ -2115,7 +2119,7 @@ Tinytest.add("minimongo - array sort", function (test) {
|
||||
Tinytest.add("minimongo - sort keys", function (test) {
|
||||
var keyListToObject = function (keyList) {
|
||||
var obj = {};
|
||||
_.each(keyList, function (key) {
|
||||
keyList.forEach(function (key) {
|
||||
obj[EJSON.stringify(key)] = true;
|
||||
});
|
||||
return obj;
|
||||
@@ -2961,7 +2965,7 @@ Tinytest.add("minimongo - observe ordered", function (test) {
|
||||
handle.stop();
|
||||
|
||||
// test _suppress_initial
|
||||
handle = c.find({}, {sort: {a: -1}}).observe(_.extend({
|
||||
handle = c.find({}, {sort: {a: -1}}).observe(Object.assign({
|
||||
_suppress_initial: true}, cbs));
|
||||
test.equal(operations.shift(), undefined);
|
||||
c.insert({a:100});
|
||||
@@ -3007,7 +3011,7 @@ Tinytest.add("minimongo - observe ordered", function (test) {
|
||||
// test _no_indices
|
||||
|
||||
c.remove({});
|
||||
handle = c.find({}, {sort: {a: 1}}).observe(_.extend(cbs, {_no_indices: true}));
|
||||
handle = c.find({}, {sort: {a: 1}}).observe(Object.assign(cbs, {_no_indices: true}));
|
||||
c.insert({_id: 'foo', a:1});
|
||||
test.equal(operations.shift(), ['added', {a:1}, -1, null]);
|
||||
c.update({a:1}, {$set: {a: 2}});
|
||||
@@ -3027,14 +3031,14 @@ Tinytest.add("minimongo - observe ordered", function (test) {
|
||||
handle.stop();
|
||||
});
|
||||
|
||||
_.each([true, false], function (ordered) {
|
||||
[true, false].forEach(function (ordered) {
|
||||
Tinytest.add("minimongo - observe ordered: " + ordered, function (test) {
|
||||
var c = new LocalCollection();
|
||||
|
||||
var ev = "";
|
||||
var makecb = function (tag) {
|
||||
var ret = {};
|
||||
_.each(["added", "changed", "removed"], function (fn) {
|
||||
["added", "changed", "removed"].forEach(function (fn) {
|
||||
var fnName = ordered ? fn + "At" : fn;
|
||||
ret[fnName] = function (doc) {
|
||||
ev = (ev + fn.substr(0, 1) + tag + doc._id + "_");
|
||||
@@ -3112,8 +3116,8 @@ Tinytest.add("minimongo - saveOriginals", function (test) {
|
||||
// Verify the originals.
|
||||
var originals = c.retrieveOriginals();
|
||||
var affected = ['bar', 'baz', 'quux', 'whoa', 'hooray'];
|
||||
test.equal(originals.size(), _.size(affected));
|
||||
_.each(affected, function (id) {
|
||||
test.equal(originals.size(), affected.length);
|
||||
affected.forEach(function (id) {
|
||||
test.isTrue(originals.has(id));
|
||||
});
|
||||
test.equal(originals.get('bar'), {_id: 'bar', x: 'updateme'});
|
||||
@@ -3378,7 +3382,7 @@ Tinytest.add("minimongo - $near operator tests", function (test) {
|
||||
test.equal(coll.find({ 'rest.loc': { $near: [0, 0], $maxDistance: 30 } }).count(), 3);
|
||||
test.equal(coll.find({ 'rest.loc': { $near: [0, 0], $maxDistance: 4 } }).count(), 1);
|
||||
var points = coll.find({ 'rest.loc': { $near: [0, 0], $maxDistance: 6 } }).fetch();
|
||||
_.each(points, function (point, i, points) {
|
||||
points.forEach(function (point, i, points) {
|
||||
test.isTrue(!i || distance([0, 0], point.rest.loc) >= distance([0, 0], points[i - 1].rest.loc));
|
||||
});
|
||||
|
||||
@@ -3397,7 +3401,7 @@ Tinytest.add("minimongo - $near operator tests", function (test) {
|
||||
{ "category" : "OTHER OFFENSES", "descript" : "POSSESSION OF BURGLARY TOOLS", "address" : "900 Block of MINNA ST", "location" : { "type" : "Point", "coordinates" : [ -122.415386041221, 37.7747879734156 ] } }
|
||||
];
|
||||
|
||||
_.each(data, function (x, i) { coll.insert(_.extend(x, { x: i })); });
|
||||
data.forEach(function (x, i) { coll.insert(Object.assign(x, { x: i })); });
|
||||
|
||||
var close15 = coll.find({ location: { $near: {
|
||||
$geometry: { type: "Point",
|
||||
@@ -3478,8 +3482,7 @@ Tinytest.add("minimongo - $near operator tests", function (test) {
|
||||
a: {b: [5, 5]}});
|
||||
var testNear = function (near, md, expected) {
|
||||
test.equal(
|
||||
_.pluck(
|
||||
coll.find({'a.b': {$near: near, $maxDistance: md}}).fetch(), '_id'),
|
||||
coll.find({'a.b': {$near: near, $maxDistance: md}}).fetch().map(function (doc) { return doc._id }),
|
||||
expected);
|
||||
};
|
||||
testNear([149, 149], 4, ['x']);
|
||||
@@ -3492,10 +3495,10 @@ Tinytest.add("minimongo - $near operator tests", function (test) {
|
||||
// issue #3599
|
||||
// Ensure that distance is not used as a tie-breaker for sort.
|
||||
test.equal(
|
||||
_.pluck(coll.find({'a.b': {$near: [1, 1]}}, {sort: {k: 1}}).fetch(), '_id'),
|
||||
coll.find({'a.b': {$near: [1, 1]}}, {sort: {k: 1}}).fetch().map(function (doc) { return doc._id; }),
|
||||
['x', 'y']);
|
||||
test.equal(
|
||||
_.pluck(coll.find({'a.b': {$near: [5, 5]}}, {sort: {k: 1}}).fetch(), '_id'),
|
||||
coll.find({'a.b': {$near: [5, 5]}}, {sort: {k: 1}}).fetch().map(function (doc) { return doc._id; }),
|
||||
['x', 'y']);
|
||||
|
||||
var operations = [];
|
||||
|
||||
@@ -35,14 +35,16 @@ LocalCollection._modify = function (doc, mod, options) {
|
||||
// apply modifiers to the doc.
|
||||
newDoc = EJSON.clone(doc);
|
||||
|
||||
_.each(mod, function (operand, op) {
|
||||
Object.keys(mod).forEach(function (op) {
|
||||
var operand = mod[op];
|
||||
var modFunc = MODIFIERS[op];
|
||||
// Treat $setOnInsert as $set if this is an insert.
|
||||
if (options.isInsert && op === '$setOnInsert')
|
||||
modFunc = MODIFIERS['$set'];
|
||||
if (!modFunc)
|
||||
throw MinimongoError("Invalid modifier specified " + op);
|
||||
_.each(operand, function (arg, keypath) {
|
||||
Object.keys(operand).forEach(function (keypath) {
|
||||
var arg = operand[keypath];
|
||||
if (keypath === '') {
|
||||
throw MinimongoError("An empty update path is not valid.");
|
||||
}
|
||||
@@ -53,13 +55,13 @@ LocalCollection._modify = function (doc, mod, options) {
|
||||
|
||||
var keyparts = keypath.split('.');
|
||||
|
||||
if (! _.all(keyparts, _.identity)) {
|
||||
if (!keyparts.every(Boolean)) {
|
||||
throw MinimongoError(
|
||||
"The update path '" + keypath +
|
||||
"' contains an empty field name, which is not allowed.");
|
||||
}
|
||||
|
||||
var noCreate = _.has(NO_CREATE_MODIFIERS, op);
|
||||
var noCreate = NO_CREATE_MODIFIERS.hasOwnProperty(op);
|
||||
var forbidArray = (op === "$rename");
|
||||
var target = findModTarget(newDoc, keyparts, {
|
||||
noCreate: NO_CREATE_MODIFIERS[op],
|
||||
@@ -73,15 +75,15 @@ LocalCollection._modify = function (doc, mod, options) {
|
||||
}
|
||||
|
||||
// move new document into place.
|
||||
_.each(_.keys(doc), function (k) {
|
||||
Object.keys(doc).forEach(function (k) {
|
||||
// Note: this used to be for (var k in doc) however, this does not
|
||||
// work right in Opera. Deleting from a doc while iterating over it
|
||||
// would sometimes cause opera to skip some keys.
|
||||
if (k !== '_id')
|
||||
delete doc[k];
|
||||
});
|
||||
_.each(newDoc, function (v, k) {
|
||||
doc[k] = v;
|
||||
Object.keys(newDoc).forEach(function (k) {
|
||||
doc[k] = newDoc[k];
|
||||
});
|
||||
};
|
||||
|
||||
@@ -237,7 +239,7 @@ var MODIFIERS = {
|
||||
}
|
||||
},
|
||||
$set: function (target, field, arg) {
|
||||
if (!_.isObject(target)) { // not an array or an object
|
||||
if (target !== Object(target)) { // not an array or an object
|
||||
var e = MinimongoError(
|
||||
"Cannot set property on non-object field", { field });
|
||||
e.setPropertyError = true;
|
||||
@@ -343,8 +345,8 @@ var MODIFIERS = {
|
||||
target[field] = []; // differs from Array.slice!
|
||||
else if (slice < 0)
|
||||
target[field] = target[field].slice(slice);
|
||||
else
|
||||
target[field] = target[field].slice(0, slice);
|
||||
else
|
||||
target[field] = target[field].slice(0, slice);
|
||||
}
|
||||
},
|
||||
$pushAll: function (target, field, arg) {
|
||||
@@ -380,7 +382,7 @@ var MODIFIERS = {
|
||||
throw MinimongoError(
|
||||
"Cannot apply $addToSet modifier to non-array", { field });
|
||||
else {
|
||||
_.each(values, function (value) {
|
||||
values.forEach(function (value) {
|
||||
for (var i = 0; i < x.length; i++)
|
||||
if (LocalCollection._f._equal(value, x[i]))
|
||||
return;
|
||||
|
||||
@@ -10,7 +10,7 @@ LocalCollection._selectorIsIdPerhapsAsObject = function (selector) {
|
||||
return LocalCollection._selectorIsId(selector) ||
|
||||
(selector && typeof selector === "object" &&
|
||||
selector._id && LocalCollection._selectorIsId(selector._id) &&
|
||||
_.size(selector) === 1);
|
||||
Object.keys(selector).length === 1);
|
||||
};
|
||||
|
||||
// If this is a selector which explicitly constrains the match by ID to a finite
|
||||
@@ -26,15 +26,15 @@ LocalCollection._idsMatchedBySelector = function (selector) {
|
||||
return null;
|
||||
|
||||
// Do we have an _id clause?
|
||||
if (_.has(selector, '_id')) {
|
||||
if (selector.hasOwnProperty('_id')) {
|
||||
// Is the _id clause just an ID?
|
||||
if (LocalCollection._selectorIsId(selector._id))
|
||||
return [selector._id];
|
||||
// Is the _id clause {_id: {$in: ["x", "y", "z"]}}?
|
||||
if (selector._id && selector._id.$in
|
||||
&& _.isArray(selector._id.$in)
|
||||
&& !_.isEmpty(selector._id.$in)
|
||||
&& _.all(selector._id.$in, LocalCollection._selectorIsId)) {
|
||||
&& Array.isArray(selector._id.$in)
|
||||
&& selector._id.$in.length
|
||||
&& selector._id.$in.every(LocalCollection._selectorIsId)) {
|
||||
return selector._id.$in;
|
||||
}
|
||||
return null;
|
||||
@@ -43,7 +43,7 @@ LocalCollection._idsMatchedBySelector = function (selector) {
|
||||
// If this is a top-level $and, and any of the clauses constrain their
|
||||
// documents, then the whole selector is constrained by any one clause's
|
||||
// constraint. (Well, by their intersection, but that seems unlikely.)
|
||||
if (selector.$and && _.isArray(selector.$and)) {
|
||||
if (selector.$and && Array.isArray(selector.$and)) {
|
||||
for (var i = 0; i < selector.$and.length; ++i) {
|
||||
var subIds = LocalCollection._idsMatchedBySelector(selector.$and[i]);
|
||||
if (subIds)
|
||||
|
||||
@@ -13,7 +13,7 @@ LocalCollection._CachingChangeObserver = function (options) {
|
||||
|
||||
var orderedFromCallbacks = options.callbacks &&
|
||||
LocalCollection._observeChangesCallbacksAreOrdered(options.callbacks);
|
||||
if (_.has(options, 'ordered')) {
|
||||
if (options.hasOwnProperty('ordered')) {
|
||||
self.ordered = options.ordered;
|
||||
if (options.callbacks && options.ordered !== orderedFromCallbacks)
|
||||
throw Error("ordered option doesn't match callbacks");
|
||||
@@ -89,7 +89,7 @@ LocalCollection._observeFromObserveChanges = function (cursor, observeCallbacks)
|
||||
var self = this;
|
||||
if (suppressed || !(observeCallbacks.addedAt || observeCallbacks.added))
|
||||
return;
|
||||
var doc = transform(_.extend(fields, {_id: id}));
|
||||
var doc = transform(Object.assign(fields, {_id: id}));
|
||||
if (observeCallbacks.addedAt) {
|
||||
var index = indices
|
||||
? (before ? self.docs.indexOf(before) : self.docs.size()) : -1;
|
||||
@@ -149,7 +149,7 @@ LocalCollection._observeFromObserveChanges = function (cursor, observeCallbacks)
|
||||
observeChangesCallbacks = {
|
||||
added: function (id, fields) {
|
||||
if (!suppressed && observeCallbacks.added) {
|
||||
var doc = _.extend(fields, {_id: id});
|
||||
var doc = Object.assign(fields, {_id: id});
|
||||
observeCallbacks.added(transform(doc));
|
||||
}
|
||||
},
|
||||
|
||||
@@ -9,7 +9,6 @@ Package.onUse(function (api) {
|
||||
api.export('MinimongoTest', { testOnly: true });
|
||||
api.export('MinimongoError', { testOnly: true });
|
||||
api.use([
|
||||
'underscore',
|
||||
'ejson',
|
||||
'id-map',
|
||||
'ordered-dict',
|
||||
@@ -51,7 +50,6 @@ Package.onTest(function (api) {
|
||||
api.use('test-helpers', 'client');
|
||||
api.use([
|
||||
'tinytest',
|
||||
'underscore',
|
||||
'ejson',
|
||||
'ordered-dict',
|
||||
'random',
|
||||
|
||||
@@ -8,22 +8,23 @@
|
||||
LocalCollection._compileProjection = function (fields) {
|
||||
LocalCollection._checkSupportedProjection(fields);
|
||||
|
||||
var _idProjection = _.isUndefined(fields._id) ? true : fields._id;
|
||||
var _idProjection = fields._id === undefined ? true : fields._id;
|
||||
var details = projectionDetails(fields);
|
||||
|
||||
// returns transformed doc according to ruleTree
|
||||
var transform = function (doc, ruleTree) {
|
||||
// Special case for "sets"
|
||||
if (_.isArray(doc))
|
||||
return _.map(doc, function (subdoc) { return transform(subdoc, ruleTree); });
|
||||
if (Array.isArray(doc))
|
||||
return doc.map(function (subdoc) { return transform(subdoc, ruleTree); });
|
||||
|
||||
var res = details.including ? {} : EJSON.clone(doc);
|
||||
_.each(ruleTree, function (rule, key) {
|
||||
if (!_.has(doc, key))
|
||||
Object.keys(ruleTree).forEach(function (key) {
|
||||
var rule = ruleTree[key];
|
||||
if (!doc.hasOwnProperty(key))
|
||||
return;
|
||||
if (_.isObject(rule)) {
|
||||
if (rule === Object(rule)) {
|
||||
// For sub-objects/subsets we branch
|
||||
if (_.isObject(doc[key]))
|
||||
if (doc[key] === Object(doc[key]))
|
||||
res[key] = transform(doc[key], rule);
|
||||
// Otherwise we don't even touch this subfield
|
||||
} else if (details.including)
|
||||
@@ -38,9 +39,9 @@ LocalCollection._compileProjection = function (fields) {
|
||||
return function (obj) {
|
||||
var res = transform(obj, details.tree);
|
||||
|
||||
if (_idProjection && _.has(obj, '_id'))
|
||||
if (_idProjection && obj.hasOwnProperty('_id'))
|
||||
res._id = obj._id;
|
||||
if (!_idProjection && _.has(res, '_id'))
|
||||
if (!_idProjection && res.hasOwnProperty('_id'))
|
||||
delete res._id;
|
||||
return res;
|
||||
};
|
||||
@@ -56,7 +57,7 @@ projectionDetails = function (fields) {
|
||||
// Find the non-_id keys (_id is handled specially because it is included unless
|
||||
// explicitly excluded). Sort the keys, so that our code to detect overlaps
|
||||
// like 'foo' and 'foo.bar' can assume that 'foo' comes first.
|
||||
var fieldsKeys = _.keys(fields).sort();
|
||||
var fieldsKeys = Object.keys(fields).sort();
|
||||
|
||||
// If _id is the only field in the projection, do not remove it, since it is
|
||||
// required to determine if this is an exclusion or exclusion. Also keep an
|
||||
@@ -66,12 +67,12 @@ projectionDetails = function (fields) {
|
||||
// special case, since exclusive _id is always allowed.
|
||||
if (fieldsKeys.length > 0 &&
|
||||
!(fieldsKeys.length === 1 && fieldsKeys[0] === '_id') &&
|
||||
!(_.contains(fieldsKeys, '_id') && fields['_id']))
|
||||
fieldsKeys = _.reject(fieldsKeys, function (key) { return key === '_id'; });
|
||||
!(fieldsKeys.includes('_id') && fields['_id']))
|
||||
fieldsKeys = fieldsKeys.filter(function (key) { return key !== '_id'; });
|
||||
|
||||
var including = null; // Unknown
|
||||
|
||||
_.each(fieldsKeys, function (keyPath) {
|
||||
fieldsKeys.forEach(function (keyPath) {
|
||||
var rule = !!fields[keyPath];
|
||||
if (including === null)
|
||||
including = rule;
|
||||
@@ -126,20 +127,20 @@ projectionDetails = function (fields) {
|
||||
// @returns - Object: tree represented as a set of nested objects
|
||||
pathsToTree = function (paths, newLeafFn, conflictFn, tree) {
|
||||
tree = tree || {};
|
||||
_.each(paths, function (keyPath) {
|
||||
paths.forEach(function (keyPath) {
|
||||
var treePos = tree;
|
||||
var pathArr = keyPath.split('.');
|
||||
|
||||
// use _.all just for iteration with break
|
||||
var success = _.all(pathArr.slice(0, -1), function (key, idx) {
|
||||
if (!_.has(treePos, key))
|
||||
// use .every just for iteration with break
|
||||
var success = pathArr.slice(0, -1).every(function (key, idx) {
|
||||
if (!treePos.hasOwnProperty(key))
|
||||
treePos[key] = {};
|
||||
else if (!_.isObject(treePos[key])) {
|
||||
else if (treePos[key] !== Object(treePos[key])) {
|
||||
treePos[key] = conflictFn(treePos[key],
|
||||
pathArr.slice(0, idx + 1).join('.'),
|
||||
keyPath);
|
||||
// break out of loop if we are failing for this path
|
||||
if (!_.isObject(treePos[key]))
|
||||
if (treePos[key] !== Object(treePos[key]))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -148,8 +149,8 @@ pathsToTree = function (paths, newLeafFn, conflictFn, tree) {
|
||||
});
|
||||
|
||||
if (success) {
|
||||
var lastKey = _.last(pathArr);
|
||||
if (!_.has(treePos, lastKey))
|
||||
var lastKey = pathArr[pathArr.length - 1];
|
||||
if (!treePos.hasOwnProperty(lastKey))
|
||||
treePos[lastKey] = newLeafFn(keyPath);
|
||||
else
|
||||
treePos[lastKey] = conflictFn(treePos[lastKey], keyPath, keyPath);
|
||||
@@ -160,15 +161,16 @@ pathsToTree = function (paths, newLeafFn, conflictFn, tree) {
|
||||
};
|
||||
|
||||
LocalCollection._checkSupportedProjection = function (fields) {
|
||||
if (!_.isObject(fields) || _.isArray(fields))
|
||||
if (fields !== Object(fields) || Array.isArray(fields))
|
||||
throw MinimongoError("fields option must be an object");
|
||||
|
||||
_.each(fields, function (val, keyPath) {
|
||||
if (_.contains(keyPath.split('.'), '$'))
|
||||
Object.keys(fields).forEach(function (keyPath) {
|
||||
var val = fields[keyPath];
|
||||
if (keyPath.split('.').includes('$'))
|
||||
throw MinimongoError("Minimongo doesn't support $ operator in projections yet.");
|
||||
if (typeof val === 'object' && _.intersection(['$elemMatch', '$meta', '$slice'], _.keys(val)).length > 0)
|
||||
if (typeof val === 'object' && ['$elemMatch', '$meta', '$slice'].some(key => Object.keys(val).includes(key)))
|
||||
throw MinimongoError("Minimongo doesn't support operators in projections yet.");
|
||||
if (_.indexOf([1, 0, true, false], val) === -1)
|
||||
if (![1, 0, true, false].includes(val))
|
||||
throw MinimongoError("Projection values should be one of 1, 0, true, or false");
|
||||
});
|
||||
};
|
||||
|
||||
@@ -47,7 +47,7 @@ Minimongo.Matcher = function (selector, isUpdate = false) {
|
||||
self._isUpdate = isUpdate;
|
||||
};
|
||||
|
||||
_.extend(Minimongo.Matcher.prototype, {
|
||||
Object.assign(Minimongo.Matcher.prototype, {
|
||||
documentMatches: function (doc) {
|
||||
if (!doc || typeof doc !== "object") {
|
||||
throw Error("documentMatches needs a document");
|
||||
@@ -109,7 +109,7 @@ _.extend(Minimongo.Matcher.prototype, {
|
||||
// Returns a list of key paths the given selector is looking for. It includes
|
||||
// the empty string if there is a $where.
|
||||
_getPaths: function () {
|
||||
return _.keys(this._paths);
|
||||
return Object.keys(this._paths);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -124,11 +124,12 @@ _.extend(Minimongo.Matcher.prototype, {
|
||||
var compileDocumentSelector = function (docSelector, matcher, options) {
|
||||
options = options || {};
|
||||
var docMatchers = [];
|
||||
_.each(docSelector, function (subSelector, key) {
|
||||
Object.keys(docSelector).forEach(function (key) {
|
||||
var subSelector = docSelector[key];
|
||||
if (key.substr(0, 1) === '$') {
|
||||
// Outer operators are either logical operators (they recurse back into
|
||||
// this function), or $where.
|
||||
if (!_.has(LOGICAL_OPERATORS, key))
|
||||
if (!LOGICAL_OPERATORS.hasOwnProperty(key))
|
||||
throw new Error("Unrecognized logical operator: " + key);
|
||||
matcher._isSimple = false;
|
||||
docMatchers.push(LOGICAL_OPERATORS[key](subSelector, matcher,
|
||||
@@ -182,7 +183,7 @@ var convertElementMatcherToBranchedMatcher = function (
|
||||
branches, options.dontIncludeLeafArrays);
|
||||
}
|
||||
var ret = {};
|
||||
ret.result = _.any(expanded, function (element) {
|
||||
ret.result = expanded.some(function (element) {
|
||||
var matched = elementMatcher(element.value);
|
||||
|
||||
// Special case for $elemMatch: it means "true, and use this as an array
|
||||
@@ -211,9 +212,7 @@ var convertElementMatcherToBranchedMatcher = function (
|
||||
regexpElementMatcher = function (regexp) {
|
||||
return function (value) {
|
||||
if (value instanceof RegExp) {
|
||||
// Comparing two regexps means seeing if the regexps are identical
|
||||
// (really!). Underscore knows how.
|
||||
return _.isEqual(value, regexp);
|
||||
return value.toString() === regexp.toString();
|
||||
}
|
||||
// Regexps only work against strings.
|
||||
if (typeof value !== 'string')
|
||||
@@ -258,21 +257,22 @@ var operatorBranchedMatcher = function (valueSelector, matcher, isRoot) {
|
||||
// is OK.
|
||||
|
||||
var operatorMatchers = [];
|
||||
_.each(valueSelector, function (operand, operator) {
|
||||
var simpleRange = _.contains(['$lt', '$lte', '$gt', '$gte'], operator) &&
|
||||
_.isNumber(operand);
|
||||
var simpleEquality = _.contains(['$ne', '$eq'], operator) && !_.isObject(operand);
|
||||
var simpleInclusion = _.contains(['$in', '$nin'], operator) &&
|
||||
_.isArray(operand) && !_.any(operand, _.isObject);
|
||||
Object.keys(valueSelector).forEach(function (operator) {
|
||||
var operand = valueSelector[operator];
|
||||
var simpleRange = ['$lt', '$lte', '$gt', '$gte'].includes(operator) &&
|
||||
typeof operand === 'number';
|
||||
var simpleEquality = ['$ne', '$eq'].includes(operator) && operand !== Object(operand);
|
||||
var simpleInclusion = ['$in', '$nin'].includes(operator) &&
|
||||
Array.isArray(operand) && !operand.some(function (x) { return x === Object(x); });
|
||||
|
||||
if (! (simpleRange || simpleInclusion || simpleEquality)) {
|
||||
matcher._isSimple = false;
|
||||
}
|
||||
|
||||
if (_.has(VALUE_OPERATORS, operator)) {
|
||||
if (VALUE_OPERATORS.hasOwnProperty(operator)) {
|
||||
operatorMatchers.push(
|
||||
VALUE_OPERATORS[operator](operand, valueSelector, matcher, isRoot));
|
||||
} else if (_.has(ELEMENT_OPERATORS, operator)) {
|
||||
} else if (ELEMENT_OPERATORS.hasOwnProperty(operator)) {
|
||||
var options = ELEMENT_OPERATORS[operator];
|
||||
operatorMatchers.push(
|
||||
convertElementMatcherToBranchedMatcher(
|
||||
@@ -289,9 +289,9 @@ var operatorBranchedMatcher = function (valueSelector, matcher, isRoot) {
|
||||
|
||||
var compileArrayOfDocumentSelectors = function (
|
||||
selectors, matcher, inElemMatch) {
|
||||
if (!isArray(selectors) || _.isEmpty(selectors))
|
||||
if (!isArray(selectors) || selectors.length === 0)
|
||||
throw Error("$and/$or/$nor must be nonempty array");
|
||||
return _.map(selectors, function (subSelector) {
|
||||
return selectors.map(function (subSelector) {
|
||||
if (!isPlainObject(subSelector))
|
||||
throw Error("$or/$and/$nor entries need to be full objects");
|
||||
return compileDocumentSelector(
|
||||
@@ -317,7 +317,7 @@ var LOGICAL_OPERATORS = {
|
||||
return matchers[0];
|
||||
|
||||
return function (doc) {
|
||||
var result = _.any(matchers, function (f) {
|
||||
var result = matchers.some(function (f) {
|
||||
return f(doc).result;
|
||||
});
|
||||
// $or does NOT set arrayIndices when it has multiple
|
||||
@@ -330,7 +330,7 @@ var LOGICAL_OPERATORS = {
|
||||
var matchers = compileArrayOfDocumentSelectors(
|
||||
subSelector, matcher, inElemMatch);
|
||||
return function (doc) {
|
||||
var result = _.all(matchers, function (f) {
|
||||
var result = matchers.every(function (f) {
|
||||
return !f(doc).result;
|
||||
});
|
||||
// Never set arrayIndices, because we only match if nothing in particular
|
||||
@@ -405,7 +405,7 @@ var VALUE_OPERATORS = {
|
||||
},
|
||||
// $options just provides options for $regex; its logic is inside $regex
|
||||
$options: function (operand, valueSelector) {
|
||||
if (!_.has(valueSelector, '$regex'))
|
||||
if (!valueSelector.hasOwnProperty('$regex'))
|
||||
throw Error("$options needs a $regex");
|
||||
return everythingMatcher;
|
||||
},
|
||||
@@ -419,11 +419,11 @@ var VALUE_OPERATORS = {
|
||||
if (!isArray(operand))
|
||||
throw Error("$all requires array");
|
||||
// Not sure why, but this seems to be what MongoDB does.
|
||||
if (_.isEmpty(operand))
|
||||
if (operand.length === 0)
|
||||
return nothingMatcher;
|
||||
|
||||
var branchedMatchers = [];
|
||||
_.each(operand, function (criterion) {
|
||||
operand.forEach(function (criterion) {
|
||||
// XXX handle $all/$elemMatch combination
|
||||
if (isOperatorObject(criterion))
|
||||
throw Error("no $ expressions in $all");
|
||||
@@ -445,7 +445,7 @@ var VALUE_OPERATORS = {
|
||||
// matched using $geometry.
|
||||
|
||||
var maxDistance, point, distance;
|
||||
if (isPlainObject(operand) && _.has(operand, '$geometry')) {
|
||||
if (isPlainObject(operand) && operand.hasOwnProperty('$geometry')) {
|
||||
// GeoJSON "2dsphere" mode.
|
||||
maxDistance = operand.$maxDistance;
|
||||
point = operand.$geometry;
|
||||
@@ -488,7 +488,7 @@ var VALUE_OPERATORS = {
|
||||
// each within-$maxDistance branching point.
|
||||
branchedValues = expandArraysInBranches(branchedValues);
|
||||
var result = {result: false};
|
||||
_.every(branchedValues, function (branch) {
|
||||
branchedValues.every(function (branch) {
|
||||
// if operation is an update, don't skip branches, just return the first one (#3599)
|
||||
if (!matcher._isUpdate){
|
||||
if (!(typeof branch.value === "object")){
|
||||
@@ -523,7 +523,7 @@ var distanceCoordinatePairs = function (a, b) {
|
||||
b = pointToArray(b);
|
||||
var x = a[0] - b[0];
|
||||
var y = a[1] - b[1];
|
||||
if (_.isNaN(x) || _.isNaN(y))
|
||||
if (Number.isNaN(x) || Number.isNaN(y))
|
||||
return null;
|
||||
return Math.sqrt(x * x + y * y);
|
||||
};
|
||||
@@ -531,7 +531,7 @@ var distanceCoordinatePairs = function (a, b) {
|
||||
// the second one to y no matter what user passes.
|
||||
// In case user passes { lon: x, lat: y } returns [x, y]
|
||||
var pointToArray = function (point) {
|
||||
return _.map(point, _.identity);
|
||||
return Array.isArray(point) ? point.slice() : [point.x, point.y];
|
||||
};
|
||||
|
||||
// Helper for $lt/$gt/$lte/$gte.
|
||||
@@ -671,7 +671,7 @@ ELEMENT_OPERATORS = {
|
||||
throw Error("$in needs an array");
|
||||
|
||||
var elementMatchers = [];
|
||||
_.each(operand, function (option) {
|
||||
operand.forEach(function (option) {
|
||||
if (option instanceof RegExp)
|
||||
elementMatchers.push(regexpElementMatcher(option));
|
||||
else if (isOperatorObject(option))
|
||||
@@ -684,7 +684,7 @@ ELEMENT_OPERATORS = {
|
||||
// Allow {a: {$in: [null]}} to match when 'a' does not exist.
|
||||
if (value === undefined)
|
||||
value = null;
|
||||
return _.any(elementMatchers, function (e) {
|
||||
return elementMatchers.some(function (e) {
|
||||
return e(value);
|
||||
});
|
||||
};
|
||||
@@ -801,7 +801,7 @@ ELEMENT_OPERATORS = {
|
||||
throw Error("$elemMatch need an object");
|
||||
|
||||
var subMatcher, isDocMatcher;
|
||||
if (isOperatorObject(_.omit(operand, _.keys(LOGICAL_OPERATORS)), true)) {
|
||||
if (isOperatorObject(Object.keys(operand).filter(key => !Object.keys(LOGICAL_OPERATORS).includes(key)).reduce(function (a, b) { return Object.assign(a, {[b]: operand[b]}); }, {}), true)) {
|
||||
subMatcher = compileValueSelector(operand, matcher);
|
||||
isDocMatcher = false;
|
||||
} else {
|
||||
@@ -993,7 +993,7 @@ makeLookupFunction = function (key, options) {
|
||||
// "look up this index" in that case, not "also look up this index in all
|
||||
// the elements of the array".
|
||||
if (isArray(firstLevel) && !(nextPartIsNumeric && options.forSort)) {
|
||||
_.each(firstLevel, function (branch, arrayIndex) {
|
||||
firstLevel.forEach(function (branch, arrayIndex) {
|
||||
if (isPlainObject(branch)) {
|
||||
appendToResult(lookupRest(
|
||||
branch,
|
||||
@@ -1009,7 +1009,7 @@ MinimongoTest.makeLookupFunction = makeLookupFunction;
|
||||
|
||||
expandArraysInBranches = function (branches, skipTheArrays) {
|
||||
var branchesOut = [];
|
||||
_.each(branches, function (branch) {
|
||||
branches.forEach(function (branch) {
|
||||
var thisIsArray = isArray(branch.value);
|
||||
// We include the branch itself, *UNLESS* we it's an array that we're going
|
||||
// to iterate and we're told to skip arrays. (That's right, we include some
|
||||
@@ -1022,7 +1022,7 @@ expandArraysInBranches = function (branches, skipTheArrays) {
|
||||
});
|
||||
}
|
||||
if (thisIsArray && !branch.dontIterate) {
|
||||
_.each(branch.value, function (leaf, i) {
|
||||
branch.value.forEach(function (leaf, i) {
|
||||
branchesOut.push({
|
||||
value: leaf,
|
||||
arrayIndices: (branch.arrayIndices || []).concat(i)
|
||||
@@ -1054,7 +1054,7 @@ var andSomeMatchers = function (subMatchers) {
|
||||
|
||||
return function (docOrBranches) {
|
||||
var ret = {};
|
||||
ret.result = _.all(subMatchers, function (f) {
|
||||
ret.result = subMatchers.every(function (f) {
|
||||
var subResult = f(docOrBranches);
|
||||
// Copy a 'distance' number out of the first sub-matcher that has
|
||||
// one. Yes, this means that if there are multiple $near fields in a
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
Minimongo.Matcher.prototype.affectedByModifier = function (modifier) {
|
||||
var self = this;
|
||||
// safe check for $set/$unset being objects
|
||||
modifier = _.extend({ $set: {}, $unset: {} }, modifier);
|
||||
var modifiedPaths = _.keys(modifier.$set).concat(_.keys(modifier.$unset));
|
||||
modifier = Object.assign({ $set: {}, $unset: {} }, modifier);
|
||||
var modifiedPaths = Object.keys(modifier.$set).concat(Object.keys(modifier.$unset));
|
||||
var meaningfulPaths = self._getPaths();
|
||||
|
||||
return _.any(modifiedPaths, function (path) {
|
||||
return modifiedPaths.some(function (path) {
|
||||
var mod = path.split('.');
|
||||
return _.any(meaningfulPaths, function (meaningfulPath) {
|
||||
return meaningfulPaths.some(function (meaningfulPath) {
|
||||
var sel = meaningfulPath.split('.');
|
||||
var i = 0, j = 0;
|
||||
|
||||
@@ -64,14 +64,14 @@ Minimongo.Matcher.prototype.canBecomeTrueByModifier = function (modifier) {
|
||||
if (!this.affectedByModifier(modifier))
|
||||
return false;
|
||||
|
||||
modifier = _.extend({$set:{}, $unset:{}}, modifier);
|
||||
var modifierPaths = _.keys(modifier.$set).concat(_.keys(modifier.$unset));
|
||||
modifier = Object.assign({$set:{}, $unset:{}}, modifier);
|
||||
var modifierPaths = Object.keys(modifier.$set).concat(Object.keys(modifier.$unset));
|
||||
|
||||
if (!self.isSimple())
|
||||
return true;
|
||||
|
||||
if (_.any(self._getPaths(), pathHasNumericKeys) ||
|
||||
_.any(modifierPaths, pathHasNumericKeys))
|
||||
if (self._getPaths().some(pathHasNumericKeys) ||
|
||||
modifierPaths.some(pathHasNumericKeys))
|
||||
return true;
|
||||
|
||||
// check if there is a $set or $unset that indicates something is an
|
||||
@@ -79,10 +79,11 @@ Minimongo.Matcher.prototype.canBecomeTrueByModifier = function (modifier) {
|
||||
// NOTE: it is correct since we allow only scalars in $-operators
|
||||
// Example: for selector {'a.b': {$gt: 5}} the modifier {'a.b.c':7} would
|
||||
// definitely set the result to false as 'a.b' appears to be an object.
|
||||
var expectedScalarIsObject = _.any(self._selector, function (sel, path) {
|
||||
var expectedScalarIsObject = Object.keys(self._selector).some(function (path) {
|
||||
var sel = self._selector[path];
|
||||
if (! isOperatorObject(sel))
|
||||
return false;
|
||||
return _.any(modifierPaths, function (modifierPath) {
|
||||
return modifierPaths.some(function (modifierPath) {
|
||||
return startsWith(modifierPath, path + '.');
|
||||
});
|
||||
});
|
||||
@@ -149,17 +150,17 @@ Minimongo.Matcher.prototype.matchingDocument = function () {
|
||||
// Return anything from $in that matches the whole selector for this
|
||||
// path. If nothing matches, returns `undefined` as nothing can make
|
||||
// this selector into `true`.
|
||||
return _.find(valueSelector.$in, function (x) {
|
||||
return valueSelector.$in.find(function (x) {
|
||||
return matcher.documentMatches({ placeholder: x }).result;
|
||||
});
|
||||
} else if (onlyContainsKeys(valueSelector, ['$gt', '$gte', '$lt', '$lte'])) {
|
||||
var lowerBound = -Infinity, upperBound = Infinity;
|
||||
_.each(['$lte', '$lt'], function (op) {
|
||||
if (_.has(valueSelector, op) && valueSelector[op] < upperBound)
|
||||
['$lte', '$lt'].forEach(function (op) {
|
||||
if (valueSelector.hasOwnProperty(op) && valueSelector[op] < upperBound)
|
||||
upperBound = valueSelector[op];
|
||||
});
|
||||
_.each(['$gte', '$gt'], function (op) {
|
||||
if (_.has(valueSelector, op) && valueSelector[op] > lowerBound)
|
||||
['$gte', '$gt'].forEach(function (op) {
|
||||
if (valueSelector.hasOwnProperty(op) && valueSelector[op] > lowerBound)
|
||||
lowerBound = valueSelector[op];
|
||||
});
|
||||
|
||||
@@ -181,7 +182,7 @@ Minimongo.Matcher.prototype.matchingDocument = function () {
|
||||
}
|
||||
return self._selector[path];
|
||||
},
|
||||
_.identity /*conflict resolution is no resolution*/);
|
||||
function (x) { return x; } /*conflict resolution is no resolution*/);
|
||||
|
||||
if (fallback)
|
||||
self._matchingDocument = null;
|
||||
@@ -190,28 +191,31 @@ Minimongo.Matcher.prototype.matchingDocument = function () {
|
||||
};
|
||||
|
||||
var getPaths = function (sel) {
|
||||
return _.keys(new Minimongo.Matcher(sel)._paths);
|
||||
return _.chain(sel).map(function (v, k) {
|
||||
return Object.keys(new Minimongo.Matcher(sel)._paths);
|
||||
return Object.keys(sel).map(function (k) {
|
||||
var v = sel[k];
|
||||
// we don't know how to handle $where because it can be anything
|
||||
if (k === "$where")
|
||||
return ''; // matches everything
|
||||
// we branch from $or/$and/$nor operator
|
||||
if (_.contains(['$or', '$and', '$nor'], k))
|
||||
return _.map(v, getPaths);
|
||||
if (['$or', '$and', '$nor'].includes(k))
|
||||
return v.map(getPaths);
|
||||
// the value is a literal or some comparison operator
|
||||
return k;
|
||||
}).flatten().uniq().value();
|
||||
})
|
||||
.reduce(function (a, b) { return a.concat(b); }, [])
|
||||
.filter(function (a, b, c) { return c.indexOf(a) === b; });
|
||||
};
|
||||
|
||||
// A helper to ensure object has only certain keys
|
||||
var onlyContainsKeys = function (obj, keys) {
|
||||
return _.all(obj, function (v, k) {
|
||||
return _.contains(keys, k);
|
||||
return Object.keys(obj).every(function (k) {
|
||||
return keys.includes(k);
|
||||
});
|
||||
};
|
||||
|
||||
var pathHasNumericKeys = function (path) {
|
||||
return _.any(path.split('.'), isNumericKey);
|
||||
return path.split('.').some(isNumericKey);
|
||||
}
|
||||
|
||||
// XXX from Underscore.String (http://epeli.github.com/underscore.string/)
|
||||
|
||||
@@ -9,7 +9,7 @@ Minimongo.Matcher.prototype.combineIntoProjection = function (projection) {
|
||||
// on all fields of the document. getSelectorPaths returns a list of paths
|
||||
// selector depends on. If one of the paths is '' (empty string) representing
|
||||
// the root or the whole document, complete projection should be returned.
|
||||
if (_.contains(selectorPaths, ''))
|
||||
if (selectorPaths.includes(''))
|
||||
return {};
|
||||
|
||||
return combineImportantPathsIntoProjection(selectorPaths, projection);
|
||||
@@ -17,8 +17,8 @@ Minimongo.Matcher.prototype.combineIntoProjection = function (projection) {
|
||||
|
||||
Minimongo._pathsElidingNumericKeys = function (paths) {
|
||||
var self = this;
|
||||
return _.map(paths, function (path) {
|
||||
return _.reject(path.split('.'), isNumericKey).join('.');
|
||||
return paths.map(function (path) {
|
||||
return path.split('.').filter(function (part) { return !isNumericKey(part); }).join('.');
|
||||
});
|
||||
};
|
||||
|
||||
@@ -42,7 +42,8 @@ combineImportantPathsIntoProjection = function (paths, projection) {
|
||||
// projection is pointing at fields to exclude
|
||||
// make sure we don't exclude important paths
|
||||
var mergedExclProjection = {};
|
||||
_.each(mergedProjection, function (incl, path) {
|
||||
Object.keys(mergedProjection).forEach(function (path) {
|
||||
var incl = mergedProjection[path];
|
||||
if (!incl)
|
||||
mergedExclProjection[path] = false;
|
||||
});
|
||||
@@ -57,9 +58,10 @@ var treeToPaths = function (tree, prefix) {
|
||||
prefix = prefix || '';
|
||||
var result = {};
|
||||
|
||||
_.each(tree, function (val, key) {
|
||||
if (_.isObject(val))
|
||||
_.extend(result, treeToPaths(val, prefix + key + '.'));
|
||||
Object.keys(tree).forEach(function (key) {
|
||||
var val = tree[key];
|
||||
if (val === Object(val))
|
||||
Object.assign(result, treeToPaths(val, prefix + key + '.'));
|
||||
else
|
||||
result[prefix + key] = val;
|
||||
});
|
||||
|
||||
@@ -39,7 +39,8 @@ Minimongo.Sorter = function (spec, options) {
|
||||
}
|
||||
}
|
||||
} else if (typeof spec === "object") {
|
||||
_.each(spec, function (value, key) {
|
||||
Object.keys(spec).forEach(function (key) {
|
||||
var value = spec[key];
|
||||
addSpecPart(key, value >= 0);
|
||||
});
|
||||
} else if (typeof spec === "function") {
|
||||
@@ -57,14 +58,14 @@ Minimongo.Sorter = function (spec, options) {
|
||||
// modifiers as this sort order. This is only implemented on the server.
|
||||
if (self.affectedByModifier) {
|
||||
var selector = {};
|
||||
_.each(self._sortSpecParts, function (spec) {
|
||||
self._sortSpecParts.forEach(function (spec) {
|
||||
selector[spec.path] = 1;
|
||||
});
|
||||
self._selectorForAffectedByModifier = new Minimongo.Matcher(selector);
|
||||
}
|
||||
|
||||
self._keyComparator = composeComparators(
|
||||
_.map(self._sortSpecParts, function (spec, i) {
|
||||
self._sortSpecParts.map(function (spec, i) {
|
||||
return self._keyFieldComparator(i);
|
||||
}));
|
||||
|
||||
@@ -77,11 +78,11 @@ Minimongo.Sorter = function (spec, options) {
|
||||
|
||||
// In addition to these methods, sorter_project.js defines combineIntoProjection
|
||||
// on the server only.
|
||||
_.extend(Minimongo.Sorter.prototype, {
|
||||
Object.assign(Minimongo.Sorter.prototype, {
|
||||
getComparator: function (options) {
|
||||
var self = this;
|
||||
|
||||
// If sort is specified or have no distances, just use the comparator from
|
||||
// If sort is specified or have no distances, just use the comparator from
|
||||
// the source specification (which defaults to "everything is equal".
|
||||
// issue #3599
|
||||
// https://docs.mongodb.com/manual/reference/operator/query/near/#sort-operation
|
||||
@@ -104,7 +105,7 @@ _.extend(Minimongo.Sorter.prototype, {
|
||||
|
||||
_getPaths: function () {
|
||||
var self = this;
|
||||
return _.pluck(self._sortSpecParts, 'path');
|
||||
return self._sortSpecParts.map(function (part) { return part.path; });
|
||||
},
|
||||
|
||||
// Finds the minimum key from the doc, according to the sort specs. (We say
|
||||
@@ -163,7 +164,7 @@ _.extend(Minimongo.Sorter.prototype, {
|
||||
|
||||
var knownPaths = null;
|
||||
|
||||
_.each(self._sortSpecParts, function (spec, whichField) {
|
||||
self._sortSpecParts.forEach(function (spec, whichField) {
|
||||
// Expand any leaf arrays that we find, and ignore those arrays
|
||||
// themselves. (We never sort based on an array itself.)
|
||||
var branches = expandArraysInBranches(spec.lookup(doc), true);
|
||||
@@ -175,7 +176,7 @@ _.extend(Minimongo.Sorter.prototype, {
|
||||
|
||||
var usedPaths = false;
|
||||
valuesByIndexAndPath[whichField] = {};
|
||||
_.each(branches, function (branch) {
|
||||
branches.forEach(function (branch) {
|
||||
if (!branch.arrayIndices) {
|
||||
// If there are no array indices for a branch, then it must be the
|
||||
// only branch, because the only thing that produces multiple branches
|
||||
@@ -188,7 +189,7 @@ _.extend(Minimongo.Sorter.prototype, {
|
||||
|
||||
usedPaths = true;
|
||||
var path = pathFromIndices(branch.arrayIndices);
|
||||
if (_.has(valuesByIndexAndPath[whichField], path))
|
||||
if (valuesByIndexAndPath[whichField].hasOwnProperty(path))
|
||||
throw Error("duplicate path: " + path);
|
||||
valuesByIndexAndPath[whichField][path] = branch.value;
|
||||
|
||||
@@ -202,7 +203,7 @@ _.extend(Minimongo.Sorter.prototype, {
|
||||
// and 'a.x.y' are both arrays, but we don't allow this for now.
|
||||
// #NestedArraySort
|
||||
// XXX achieve full compatibility here
|
||||
if (knownPaths && !_.has(knownPaths, path)) {
|
||||
if (knownPaths && !knownPaths.hasOwnProperty(path)) {
|
||||
throw Error("cannot index parallel arrays");
|
||||
}
|
||||
});
|
||||
@@ -210,13 +211,13 @@ _.extend(Minimongo.Sorter.prototype, {
|
||||
if (knownPaths) {
|
||||
// Similarly to above, paths must match everywhere, unless this is a
|
||||
// non-array field.
|
||||
if (!_.has(valuesByIndexAndPath[whichField], '') &&
|
||||
_.size(knownPaths) !== _.size(valuesByIndexAndPath[whichField])) {
|
||||
if (!valuesByIndexAndPath[whichField].hasOwnProperty('') &&
|
||||
Object.keys(knownPaths).length !== Object.keys(valuesByIndexAndPath[whichField]).length) {
|
||||
throw Error("cannot index parallel arrays!");
|
||||
}
|
||||
} else if (usedPaths) {
|
||||
knownPaths = {};
|
||||
_.each(valuesByIndexAndPath[whichField], function (x, path) {
|
||||
Object.keys(valuesByIndexAndPath[whichField]).forEach(function (path) {
|
||||
knownPaths[path] = true;
|
||||
});
|
||||
}
|
||||
@@ -224,8 +225,8 @@ _.extend(Minimongo.Sorter.prototype, {
|
||||
|
||||
if (!knownPaths) {
|
||||
// Easy case: no use of arrays.
|
||||
var soleKey = _.map(valuesByIndexAndPath, function (values) {
|
||||
if (!_.has(values, ''))
|
||||
var soleKey = valuesByIndexAndPath.map(function (values) {
|
||||
if (!values.hasOwnProperty(''))
|
||||
throw Error("no value in sole key case?");
|
||||
return values[''];
|
||||
});
|
||||
@@ -233,11 +234,11 @@ _.extend(Minimongo.Sorter.prototype, {
|
||||
return;
|
||||
}
|
||||
|
||||
_.each(knownPaths, function (x, path) {
|
||||
var key = _.map(valuesByIndexAndPath, function (values) {
|
||||
if (_.has(values, ''))
|
||||
Object.keys(knownPaths).forEach(function (path) {
|
||||
var key = valuesByIndexAndPath.map(function (values) {
|
||||
if (values.hasOwnProperty(''))
|
||||
return values[''];
|
||||
if (!_.has(values, path))
|
||||
if (!values.hasOwnProperty(path))
|
||||
throw Error("missing path?");
|
||||
return values[path];
|
||||
});
|
||||
@@ -322,7 +323,7 @@ _.extend(Minimongo.Sorter.prototype, {
|
||||
// If we are only sorting by distance, then we're not going to bother to
|
||||
// build a key filter.
|
||||
// XXX figure out how geoqueries interact with this stuff
|
||||
if (_.isEmpty(self._sortSpecParts))
|
||||
if (!self._sortSpecParts.length)
|
||||
return;
|
||||
|
||||
var selector = matcher._selector;
|
||||
@@ -333,11 +334,12 @@ _.extend(Minimongo.Sorter.prototype, {
|
||||
return;
|
||||
|
||||
var constraintsByPath = {};
|
||||
_.each(self._sortSpecParts, function (spec, i) {
|
||||
self._sortSpecParts.forEach(function (spec, i) {
|
||||
constraintsByPath[spec.path] = [];
|
||||
});
|
||||
|
||||
_.each(selector, function (subSelector, key) {
|
||||
Object.keys(selector).forEach(function (key) {
|
||||
var subSelector = selector[key];
|
||||
// XXX support $and and $or
|
||||
|
||||
var constraints = constraintsByPath[key];
|
||||
@@ -362,8 +364,9 @@ _.extend(Minimongo.Sorter.prototype, {
|
||||
}
|
||||
|
||||
if (isOperatorObject(subSelector)) {
|
||||
_.each(subSelector, function (operand, operator) {
|
||||
if (_.contains(['$lt', '$lte', '$gt', '$gte'], operator)) {
|
||||
Object.keys(subSelector).forEach(function (operator) {
|
||||
var operand = subSelector[operator];
|
||||
if (['$lt', '$lte', '$gt', '$gte'].includes(operator)) {
|
||||
// XXX this depends on us knowing that these operators don't use any
|
||||
// of the arguments to compileElementSelector other than operand.
|
||||
constraints.push(
|
||||
@@ -390,12 +393,12 @@ _.extend(Minimongo.Sorter.prototype, {
|
||||
// others; we shouldn't create a key filter unless the first sort field is
|
||||
// restricted, though after that point we can restrict the other sort fields
|
||||
// or not as we wish.
|
||||
if (_.isEmpty(constraintsByPath[self._sortSpecParts[0].path]))
|
||||
if (!constraintsByPath[self._sortSpecParts[0].path].length)
|
||||
return;
|
||||
|
||||
self._keyFilter = function (key) {
|
||||
return _.all(self._sortSpecParts, function (specPart, index) {
|
||||
return _.all(constraintsByPath[specPart.path], function (f) {
|
||||
return self._sortSpecParts.every(function (specPart, index) {
|
||||
return constraintsByPath[specPart.path].every(function (f) {
|
||||
return f(key[index]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@ const invalidCharMsg = {
|
||||
};
|
||||
export function assertIsValidFieldName(key) {
|
||||
let match;
|
||||
if (_.isString(key) && (match = key.match(/^\$|\.|\0/))) {
|
||||
if (typeof key === 'string' && (match = key.match(/^\$|\.|\0/))) {
|
||||
throw MinimongoError(`Key ${key} must not ${invalidCharMsg[match[0]]}`);
|
||||
}
|
||||
};
|
||||
@@ -21,4 +21,4 @@ export function assertHasValidFieldNames(doc){
|
||||
return value;
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ LocalCollection.wrapTransform = function (transform) {
|
||||
return transform;
|
||||
|
||||
var wrapped = function (doc) {
|
||||
if (!_.has(doc, '_id')) {
|
||||
if (!doc.hasOwnProperty('_id')) {
|
||||
// XXX do we ever have a transform on the oplog's collection? because that
|
||||
// collection has no _id.
|
||||
throw new Error("can only transform documents with _id");
|
||||
@@ -32,7 +32,7 @@ LocalCollection.wrapTransform = function (transform) {
|
||||
throw new Error("transform must return object");
|
||||
}
|
||||
|
||||
if (_.has(transformed, '_id')) {
|
||||
if (transformed.hasOwnProperty('_id')) {
|
||||
if (!EJSON.equals(transformed._id, id)) {
|
||||
throw new Error("transformed document can't have different _id");
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ Tinytest.add("minimongo - wrapTransform", function (test) {
|
||||
return doc;
|
||||
};
|
||||
var transformed = wrap(validTransform)({_id: "asdf", x: 54});
|
||||
test.equal(_.keys(transformed), ['_id', 'y', 'z']);
|
||||
test.equal(Object.keys(transformed), ['_id', 'y', 'z']);
|
||||
test.equal(transformed.y, 42);
|
||||
test.equal(transformed.z(), 43);
|
||||
|
||||
@@ -28,7 +28,7 @@ Tinytest.add("minimongo - wrapTransform", function (test) {
|
||||
"asdf", new MongoID.ObjectID(), false, null, true,
|
||||
27, [123], /adsf/, new Date, function () {}, undefined
|
||||
];
|
||||
_.each(invalidObjects, function (invalidObject) {
|
||||
invalidObjects.forEach(function (invalidObject) {
|
||||
var wrapped = wrap(function () { return invalidObject; });
|
||||
test.throws(function () {
|
||||
wrapped({_id: "asdf"});
|
||||
|
||||
Reference in New Issue
Block a user