Skip to content

Commit

Permalink
Fix Mongo queries with {$regex: /foo/}
Browse files Browse the repository at this point in the history
The bug manifested as incorrect cursor de-duping, making
queries on different regular expressions "de-dup" into one,
which, combined with hot code reload caused crazy seeming
things such as needing to save twice to see a code change
executed.
  • Loading branch information
avital committed Jul 29, 2013
1 parent 1297034 commit f7d991c
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 19 deletions.
36 changes: 25 additions & 11 deletions packages/mongo-livedata/collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,30 +261,44 @@ Meteor.Collection._rewriteSelector = function (selector) {

var ret = {};
_.each(selector, function (value, key) {
// Mongo supports both {field: /foo/} and {field: {$regex: /foo/}}
if (value instanceof RegExp) {
ret[key] = {$regex: value.source};
var regexOptions = '';
// JS RegExp objects support 'i', 'm', and 'g'. Mongo regex $options
// support 'i', 'm', 'x', and 's'. So we support 'i' and 'm' here.
if (value.ignoreCase)
regexOptions += 'i';
if (value.multiline)
regexOptions += 'm';
if (regexOptions)
ret[key].$options = regexOptions;
ret[key] = convertRegexpToMongoSelector(value);
} else if (value && value.$regex instanceof RegExp) {
ret[key] = convertRegexpToMongoSelector(value.$regex);
}
else if (_.contains(['$or','$and','$nor'], key)) {
// Translate lower levels of $and/$or/$nor
ret[key] = _.map(value, function (v) {
return Meteor.Collection._rewriteSelector(v);
});
}
else
else {
ret[key] = value;
}
});
return ret;
};

// convert a JS RegExp object to a Mongo {$regex: ..., $options: ...}
// selector
var convertRegexpToMongoSelector = function (regexp) {
check(regexp, RegExp); // safety belt

var selector = {$regex: regexp.source};
var regexOptions = '';
// JS RegExp objects support 'i', 'm', and 'g'. Mongo regex $options
// support 'i', 'm', 'x', and 's'. So we support 'i' and 'm' here.
if (regexp.ignoreCase)
regexOptions += 'i';
if (regexp.multiline)
regexOptions += 'm';
if (regexOptions)
selector.$options = regexOptions;

return selector;
};

var throwIfSelectorIsNotId = function (selector, methodName) {
if (!LocalCollection._selectorIsIdPerhapsAsObject(selector)) {
throw new Meteor.Error(
Expand Down
28 changes: 20 additions & 8 deletions packages/mongo-livedata/mongo_livedata_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -876,8 +876,12 @@ if (Meteor.isServer) {
Tinytest.add('mongo-livedata - rewrite selector', function (test) {
test.equal(Meteor.Collection._rewriteSelector({x: /^o+B/im}),
{x: {$regex: '^o+B', $options: 'im'}});
test.equal(Meteor.Collection._rewriteSelector({x: {$regex: /^o+B/im}}),
{x: {$regex: '^o+B', $options: 'im'}});
test.equal(Meteor.Collection._rewriteSelector({x: /^o+B/}),
{x: {$regex: '^o+B'}});
test.equal(Meteor.Collection._rewriteSelector({x: {$regex: /^o+B/}}),
{x: {$regex: '^o+B'}});
test.equal(Meteor.Collection._rewriteSelector('foo'),
{_id: 'foo'});

Expand All @@ -886,13 +890,15 @@ Tinytest.add('mongo-livedata - rewrite selector', function (test) {
{'$or': [
{x: /^o/},
{y: /^p/},
{z: 'q'}
{z: 'q'},
{w: {$regex: /^r/}}
]}
),
{'$or': [
{x: {$regex: '^o'}},
{y: {$regex: '^p'}},
{z: 'q'}
{z: 'q'},
{w: {$regex: '^r'}}
]}
);

Expand All @@ -901,22 +907,28 @@ Tinytest.add('mongo-livedata - rewrite selector', function (test) {
{'$or': [
{'$and': [
{x: /^a/i},
{y: /^b/}
{y: /^b/},
{z: {$regex: /^c/i}},
{w: {$regex: '^[abc]', $options: 'i'}} // make sure we don't break vanilla selectors
]},
{'$nor': [
{s: /^c/},
{t: /^d/i}
{s: /^d/},
{t: /^e/i},
{u: {$regex: /^f/i}}
]}
]}
),
{'$or': [
{'$and': [
{x: {$regex: '^a', $options: 'i'}},
{y: {$regex: '^b'}}
{y: {$regex: '^b'}},
{z: {$regex: '^c', $options: 'i'}},
{w: {$regex: '^[abc]', $options: 'i'}}
]},
{'$nor': [
{s: {$regex: '^c'}},
{t: {$regex: '^d', $options: 'i'}}
{s: {$regex: '^d'}},
{t: {$regex: '^e', $options: 'i'}},
{u: {$regex: '^f', $options: 'i'}}
]}
]}
);
Expand Down

0 comments on commit f7d991c

Please sign in to comment.