mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Fix Mongo queries with {$regex: /foo/}
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.
This commit is contained in:
@@ -261,17 +261,11 @@ 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
|
||||
@@ -279,12 +273,32 @@ Meteor.Collection._rewriteSelector = function (selector) {
|
||||
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(
|
||||
|
||||
@@ -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'});
|
||||
|
||||
@@ -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'}}
|
||||
]}
|
||||
);
|
||||
|
||||
@@ -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'}}
|
||||
]}
|
||||
]}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user