mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
Fix client-side c.update({foo: /bar/}) and remove.
Minimongo supported JS RegExp object in selectors, but previously we serialized
them poorly over DDP. Fix by converting to the equivalent {foo: {$regex: 'bar'}}
form.
Fixes #346.
This commit is contained in:
@@ -163,6 +163,29 @@ _.extend(Meteor.Collection.prototype, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// protect against dangerous selectors. falsey and {_id: falsey} are both
|
||||||
|
// likely programmer error, and not what you want, particularly for destructive
|
||||||
|
// operations. JS regexps don't serialize over DDP but can be trivially
|
||||||
|
// replaced by $regex.
|
||||||
|
Meteor.Collection._rewriteSelector = function (selector) {
|
||||||
|
// shorthand -- scalars match _id
|
||||||
|
if (LocalCollection._selectorIsId(selector))
|
||||||
|
selector = {_id: selector};
|
||||||
|
|
||||||
|
if (!selector || (('_id' in selector) && !selector._id))
|
||||||
|
// can't match anything
|
||||||
|
return {_id: Meteor.uuid()};
|
||||||
|
|
||||||
|
var ret = {};
|
||||||
|
_.each(selector, function (value, key) {
|
||||||
|
if (value instanceof RegExp)
|
||||||
|
ret[key] = {$regex: value.source};
|
||||||
|
else
|
||||||
|
ret[key] = value;
|
||||||
|
});
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
// 'insert' immediately returns the inserted document's new _id. The
|
// 'insert' immediately returns the inserted document's new _id. The
|
||||||
// others return nothing.
|
// others return nothing.
|
||||||
//
|
//
|
||||||
@@ -217,6 +240,8 @@ _.each(["insert", "update", "remove"], function (name) {
|
|||||||
if ('_id' in args[0])
|
if ('_id' in args[0])
|
||||||
throw new Error("Do not pass an _id to insert. Meteor will generate the _id for you.");
|
throw new Error("Do not pass an _id to insert. Meteor will generate the _id for you.");
|
||||||
ret = args[0]._id = Meteor.uuid();
|
ret = args[0]._id = Meteor.uuid();
|
||||||
|
} else {
|
||||||
|
args[0] = Meteor.Collection._rewriteSelector(args[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self._manager && self._manager !== Meteor.default_server) {
|
if (self._manager && self._manager !== Meteor.default_server) {
|
||||||
|
|||||||
@@ -42,21 +42,6 @@ _Mongo = function (url) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// protect against dangerous selectors. falsey and {_id: falsey}
|
|
||||||
// are both likely programmer error, and not what you want,
|
|
||||||
// particularly for destructive operations.
|
|
||||||
_Mongo._rewriteSelector = function (selector) {
|
|
||||||
// shorthand -- scalars match _id
|
|
||||||
if ((typeof selector === 'string') || (typeof selector === 'number'))
|
|
||||||
selector = {_id: selector};
|
|
||||||
|
|
||||||
if (!selector || (('_id' in selector) && !selector._id))
|
|
||||||
// can't match anything
|
|
||||||
return {_id: Meteor.uuid()};
|
|
||||||
else
|
|
||||||
return selector;
|
|
||||||
};
|
|
||||||
|
|
||||||
// callback: lambda (err, collection) called when
|
// callback: lambda (err, collection) called when
|
||||||
// collection is ready to go, or on error.
|
// collection is ready to go, or on error.
|
||||||
_Mongo.prototype._withCollection = function(collection_name, callback) {
|
_Mongo.prototype._withCollection = function(collection_name, callback) {
|
||||||
@@ -145,9 +130,6 @@ _Mongo.prototype.remove = function (collection_name, selector) {
|
|||||||
|
|
||||||
var write = self._maybeBeginWrite();
|
var write = self._maybeBeginWrite();
|
||||||
|
|
||||||
// XXX does not allow options. matches the client.
|
|
||||||
selector = _Mongo._rewriteSelector(selector);
|
|
||||||
|
|
||||||
var future = new Future;
|
var future = new Future;
|
||||||
self._withCollection(collection_name, function (err, collection) {
|
self._withCollection(collection_name, function (err, collection) {
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -179,7 +161,6 @@ _Mongo.prototype.update = function (collection_name, selector, mod, options) {
|
|||||||
|
|
||||||
var write = self._maybeBeginWrite();
|
var write = self._maybeBeginWrite();
|
||||||
|
|
||||||
selector = _Mongo._rewriteSelector(selector);
|
|
||||||
if (!options) options = {};
|
if (!options) options = {};
|
||||||
|
|
||||||
var future = new Future;
|
var future = new Future;
|
||||||
@@ -279,7 +260,7 @@ _Mongo.prototype._ensureIndex = function (collectionName, index, options) {
|
|||||||
var CursorDescription = function (collectionName, selector, options) {
|
var CursorDescription = function (collectionName, selector, options) {
|
||||||
var self = this;
|
var self = this;
|
||||||
self.collectionName = collectionName;
|
self.collectionName = collectionName;
|
||||||
self.selector = _Mongo._rewriteSelector(selector);
|
self.selector = Meteor.Collection._rewriteSelector(selector);
|
||||||
self.options = options || {};
|
self.options = options || {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -514,3 +514,51 @@ if (Meteor.isServer) {
|
|||||||
onComplete();
|
onComplete();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Meteor.isServer) {
|
||||||
|
Meteor.methods({
|
||||||
|
createInsecureCollection: function (name) {
|
||||||
|
var c = new Meteor.Collection(name);
|
||||||
|
c._insecure = true;
|
||||||
|
Meteor.publish('c-' + name, function () {
|
||||||
|
return c.find();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
testAsyncMulti('mongo-livedata - rewrite selector', [
|
||||||
|
function (test, expect) {
|
||||||
|
var collectionName = Meteor.uuid();
|
||||||
|
if (Meteor.isClient) {
|
||||||
|
Meteor.call('createInsecureCollection', collectionName);
|
||||||
|
Meteor.subscribe('c-' + collectionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
var coll = new Meteor.Collection(collectionName);
|
||||||
|
|
||||||
|
var docId;
|
||||||
|
|
||||||
|
var updateCallback = expect(function (err2) {
|
||||||
|
test.isFalse(err2);
|
||||||
|
|
||||||
|
var doc = coll.findOne(docId);
|
||||||
|
test.isTrue(doc);
|
||||||
|
test.equal(doc.name, "foobar");
|
||||||
|
test.equal(doc.value, 43);
|
||||||
|
});
|
||||||
|
|
||||||
|
coll.insert({name: 'foobar', value: 42}, expect(function (err1, id) {
|
||||||
|
test.isFalse(err1);
|
||||||
|
test.isTrue(id);
|
||||||
|
docId = id;
|
||||||
|
|
||||||
|
var doc = coll.findOne(docId);
|
||||||
|
test.isTrue(doc);
|
||||||
|
test.equal(doc.name, "foobar");
|
||||||
|
test.equal(doc.value, 42);
|
||||||
|
|
||||||
|
coll.update({name: /o+b/}, {$inc: {value: 1}}, updateCallback);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|||||||
Reference in New Issue
Block a user