From 1e7e5c80d2aaf908c105ab6fd3260170b6bf82fa Mon Sep 17 00:00:00 2001 From: ryneeverett Date: Sat, 18 Apr 2015 19:27:57 -0400 Subject: [PATCH 01/17] Minimongo support $eq operator (#4142). --- packages/minimongo/minimongo_server_tests.js | 7 +++++++ packages/minimongo/minimongo_tests.js | 17 +++++++++++++++++ packages/minimongo/selector.js | 5 ++++- packages/minimongo/selector_modifier.js | 7 +++++-- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/packages/minimongo/minimongo_server_tests.js b/packages/minimongo/minimongo_server_tests.js index 5443659567..913633a4eb 100644 --- a/packages/minimongo/minimongo_server_tests.js +++ b/packages/minimongo/minimongo_server_tests.js @@ -527,6 +527,9 @@ Tinytest.add("minimongo - sorter and projection combination", function (test) { // XXX this test should be F, but since it is so hard to be precise in // floating point math, the current implementation falls back to T T({ a: { $gt: 9.999999999999999, $lt: 10 }, x: 1 }, { $set: { x: 1 } }, "very close $gt and $lt"); + T({ a: { $eq: 5 } }, { $set: { a: 5 } }, "set of $eq"); + F({ a: { $eq: 5 } }, { $set: { a: 4 } }, "set below of $eq"); + F({ a: { $eq: 5 } }, { $set: { a: 6 } }, "set above of $eq"); T({ a: { $ne: 5 } }, { $unset: { a: 1 } }, "unset of $ne"); T({ a: { $ne: 5 } }, { $set: { a: 1 } }, "set of $ne"); T({ a: { $ne: "some string" }, x: 1 }, { $set: { x: 1 } }, "$ne dummy"); @@ -549,6 +552,10 @@ Tinytest.add("minimongo - sorter and projection combination", function (test) { Tinytest.add("minimongo - can selector become true by modifier - $-nonscalar selectors and simple tests", function (t) { test = t; + // XXX this test should be T, but it is not implemented yet + F({ a: { $eq: { x: 5 } } }, { $set: { 'a.x': 5 } }, "set of $eq"); + F({ a: { $eq: { x: 5 } } }, { $set: { 'a.x': 4 } }, "set of $eq"); + F({ a: { $eq: { x: 5 } } }, { $set: { 'a.y': 4 } }, "set of $eq"); T({ a: { $ne: { x: 5 } } }, { $set: { 'a.x': 3 } }, "set of $ne"); // XXX this test should be F, but it is not implemented yet T({ a: { $ne: { x: 5 } } }, { $set: { 'a.x': 5 } }, "set of $ne"); diff --git a/packages/minimongo/minimongo_tests.js b/packages/minimongo/minimongo_tests.js index 43dce8dae5..e3faefc744 100644 --- a/packages/minimongo/minimongo_tests.js +++ b/packages/minimongo/minimongo_tests.js @@ -510,6 +510,23 @@ Tinytest.add("minimongo - selector_compiler", function (test) { }); }); + // $eq + nomatch({a: {$eq: 1}}, {a: 2}); + match({a: {$eq: 2}}, {a: 2}); + nomatch({a: {$eq: [1]}}, {a: [2]}); + + match({a: {$eq: [1, 2]}}, {a: [1, 2]}); + match({a: {$eq: 1}}, {a: [1, 2]}); + match({a: {$eq: 2}}, {a: [1, 2]}); + nomatch({a: {$eq: 3}}, {a: [1, 2]}); + match({'a.b': {$eq: 1}}, {a: [{b: 1}, {b: 2}]}); + match({'a.b': {$eq: 2}}, {a: [{b: 1}, {b: 2}]}); + nomatch({'a.b': {$eq: 3}}, {a: [{b: 1}, {b: 2}]}); + + match({a: {$eq: {x: 1}}}, {a: {x: 1}}); + nomatch({a: {$eq: {x: 1}}}, {a: {x: 2}}); + nomatch({a: {$eq: {x: 1}}}, {a: {x: 1, y: 2}}); + // $ne match({a: {$ne: 1}}, {a: 2}); nomatch({a: {$ne: 2}}, {a: 2}); diff --git a/packages/minimongo/selector.js b/packages/minimongo/selector.js index 75ac4b02a9..fe092329a7 100644 --- a/packages/minimongo/selector.js +++ b/packages/minimongo/selector.js @@ -255,7 +255,6 @@ var operatorBranchedMatcher = function (valueSelector, matcher, isRoot) { var operatorMatchers = []; _.each(valueSelector, function (operand, operator) { - // XXX we should actually implement $eq, which is new in 2.6 var simpleRange = _.contains(['$lt', '$lte', '$gt', '$gte'], operator) && _.isNumber(operand); var simpleInequality = operator === '$ne' && !_.isObject(operand); @@ -380,6 +379,10 @@ var invertBranchedMatcher = function (branchedMatcher) { // "match each branched value independently and combine with // convertElementMatcherToBranchedMatcher". var VALUE_OPERATORS = { + $eq: function (operand) { + return convertElementMatcherToBranchedMatcher( + equalityElementMatcher(operand)); + }, $not: function (operand, valueSelector, matcher) { return invertBranchedMatcher(compileValueSelector(operand, matcher)); }, diff --git a/packages/minimongo/selector_modifier.js b/packages/minimongo/selector_modifier.js index 7ea8ed36c5..6b097c6632 100644 --- a/packages/minimongo/selector_modifier.js +++ b/packages/minimongo/selector_modifier.js @@ -141,7 +141,10 @@ Minimongo.Matcher.prototype.matchingDocument = function () { // if there is a strict equality, there is a good // chance we can use one of those as "matching" // dummy value - if (valueSelector.$in) { + if (valueSelector.$eq) { + var matcher = new Minimongo.Matcher({ placeholder: valueSelector }); + return matcher.documentMatches({ placeholder: valueSelector.$eq }); + } else if (valueSelector.$in) { var matcher = new Minimongo.Matcher({ placeholder: valueSelector }); // Return anything from $in that matches the whole selector for this @@ -168,7 +171,7 @@ Minimongo.Matcher.prototype.matchingDocument = function () { fallback = true; return middle; - } else if (onlyContainsKeys(valueSelector, ['$nin',' $ne'])) { + } else if (onlyContainsKeys(valueSelector, ['$nin', '$ne'])) { // Since self._isSimple makes sure $nin and $ne are not combined with // objects or arrays, we can confidently return an empty object as it // never matches any scalar. From 5f154f1623b0f9698cc7086725fc9ce29d8ad778 Mon Sep 17 00:00:00 2001 From: ryneeverett Date: Wed, 22 Apr 2015 17:58:41 -0400 Subject: [PATCH 02/17] canBecomeTrueByModifier - $eq always return true --- packages/minimongo/minimongo_server_tests.js | 9 +++++---- packages/minimongo/selector.js | 5 ++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/minimongo/minimongo_server_tests.js b/packages/minimongo/minimongo_server_tests.js index 913633a4eb..89bd9bfbf3 100644 --- a/packages/minimongo/minimongo_server_tests.js +++ b/packages/minimongo/minimongo_server_tests.js @@ -552,10 +552,11 @@ Tinytest.add("minimongo - sorter and projection combination", function (test) { Tinytest.add("minimongo - can selector become true by modifier - $-nonscalar selectors and simple tests", function (t) { test = t; - // XXX this test should be T, but it is not implemented yet - F({ a: { $eq: { x: 5 } } }, { $set: { 'a.x': 5 } }, "set of $eq"); - F({ a: { $eq: { x: 5 } } }, { $set: { 'a.x': 4 } }, "set of $eq"); - F({ a: { $eq: { x: 5 } } }, { $set: { 'a.y': 4 } }, "set of $eq"); + T({ a: { $eq: { x: 5 } } }, { $set: { 'a.x': 5 } }, "set of $eq"); + // XXX this test should be F, but it is not implemented yet + T({ a: { $eq: { x: 5 } } }, { $set: { 'a.x': 4 } }, "set of $eq"); + // XXX this test should be F, but it is not implemented yet + T({ a: { $eq: { x: 5 } } }, { $set: { 'a.y': 4 } }, "set of $eq"); T({ a: { $ne: { x: 5 } } }, { $set: { 'a.x': 3 } }, "set of $ne"); // XXX this test should be F, but it is not implemented yet T({ a: { $ne: { x: 5 } } }, { $set: { 'a.x': 5 } }, "set of $ne"); diff --git a/packages/minimongo/selector.js b/packages/minimongo/selector.js index fe092329a7..15f8071cf3 100644 --- a/packages/minimongo/selector.js +++ b/packages/minimongo/selector.js @@ -257,12 +257,11 @@ var operatorBranchedMatcher = function (valueSelector, matcher, isRoot) { _.each(valueSelector, function (operand, operator) { var simpleRange = _.contains(['$lt', '$lte', '$gt', '$gte'], operator) && _.isNumber(operand); - var simpleInequality = operator === '$ne' && !_.isObject(operand); + var simpleEquality = _.contains(['$ne', '$eq'], operator) && !_.isObject(operand); var simpleInclusion = _.contains(['$in', '$nin'], operator) && _.isArray(operand) && !_.any(operand, _.isObject); - if (! (operator === '$eq' || simpleRange || - simpleInclusion || simpleInequality)) { + if (! (simpleRange || simpleInclusion || simpleEquality)) { matcher._isSimple = false; } From 70b6898af9ea88165dc3b2d38c7ea3f52a5a1ec7 Mon Sep 17 00:00:00 2001 From: Alexander Sulfrian Date: Tue, 26 Apr 2016 19:11:45 +0200 Subject: [PATCH 03/17] Insert default date header into emails This will insert a default date header into all emails, if you do not specify such a header by your self. This way it will work for the emails send by accounts-password and all emails from user code. So this will fix #3940. --- packages/email/email.js | 4 ++++ packages/email/email_tests.js | 20 +++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/email/email.js b/packages/email/email.js index d4eda67e75..82bd8d62a0 100644 --- a/packages/email/email.js +++ b/packages/email/email.js @@ -178,6 +178,10 @@ Email.send = function (options) { mc.addHeader(name, value); }); + if (!options.headers.hasOwnProperty('Date')) { + mc.addHeader('Date', new Date().toUTCString().replace(/GMT/, '+0000')); + } + _.each(options.attachments, function(attachment){ mc.addAttachment(attachment); }); diff --git a/packages/email/email_tests.js b/packages/email/email_tests.js index 286440232c..c5faade643 100644 --- a/packages/email/email_tests.js +++ b/packages/email/email_tests.js @@ -13,7 +13,10 @@ Tinytest.add("email - dev mode smoke test", function (test) { cc: ["friends@example.com", "enemies@example.com"], subject: "This is the subject", text: "This is the body\nof the message\nFrom us.", - headers: {'X-Meteor-Test': 'a custom header'} + headers: { + 'X-Meteor-Test': 'a custom header', + 'Date': 'dummy', + }, }); // XXX brittle if mailcomposer changes header order, etc test.equal(stream.getContentsAsString("utf8"), @@ -22,6 +25,7 @@ Tinytest.add("email - dev mode smoke test", function (test) { "environment variable.)\n" + "MIME-Version: 1.0\r\n" + "X-Meteor-Test: a custom header\r\n" + + "Date: dummy\r\n" + "From: foo@example.com\r\n" + "To: bar@example.com\r\n" + "Cc: friends@example.com, enemies@example.com\r\n" + @@ -52,6 +56,20 @@ Tinytest.add("email - dev mode smoke test", function (test) { "\r\n" + "body\r\n" + "====== END MAIL #1 ======\n"); + + // Test if date header is automaticall generated, if not specified + Email.send({ + from: "foo@example.com", + to: "bar@example.com", + subject: "This is the subject", + text: "This is the body\nof the message\nFrom us.", + headers: { + 'X-Meteor-Test': 'a custom header', + }, + }); + + test.matches(stream.getContentsAsString("utf8"), + /^Date: .+$/m); } finally { EmailTest.restoreOutputStream(); } From 6ae4434e2f8203c9619b03d8387f61fef4ea7dbf Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Wed, 11 May 2016 16:20:50 -0700 Subject: [PATCH 04/17] Symlink rather than copy the warehouse into the sandbox Mainly because the dev bundle is so big, it took upwards on 5 mins (on my MBP w/ SSD) to copy the warehouse packages into the sandbox. AFAICT there is no reason not to symlink it if we can. --- tools/tool-testing/selftest.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/tool-testing/selftest.js b/tools/tool-testing/selftest.js index ab4a3bfc13..29d48c76df 100644 --- a/tools/tool-testing/selftest.js +++ b/tools/tool-testing/selftest.js @@ -13,6 +13,7 @@ var Console = require('../console/console.js').Console; var archinfo = require('../utils/archinfo.js'); var config = require('../meteor-services/config.js'); var buildmessage = require('../utils/buildmessage.js'); +var Builder = require('../isobuild/builder.js').default; var catalog = require('../packaging/catalog/catalog.js'); var catalogRemote = require('../packaging/catalog/catalog-remote.js'); @@ -832,9 +833,13 @@ _.extend(Sandbox.prototype, { var serverUrl = self.env.METEOR_PACKAGE_SERVER_URL; var packagesDirectoryName = config.getPackagesDirectoryName(serverUrl); - files.cp_r(files.pathJoin(builtPackageTropohouseDir, 'packages'), - files.pathJoin(self.warehouse, packagesDirectoryName), - { preserveSymlinks: true }); + + var builder = new Builder({outputPath: files.pathJoin(self.warehouse)}); + builder.copyDirectory({ + from: files.pathJoin(builtPackageTropohouseDir, 'packages'), + to: packagesDirectoryName, + symlink: true + }); var stubCatalog = { syncToken: {}, From e4355b3d0999d25afaf8f593fc10c88f0b6917e0 Mon Sep 17 00:00:00 2001 From: Wexpo Lyu Date: Sat, 14 May 2016 08:19:51 +0800 Subject: [PATCH 05/17] Ability to override the default warehouse url base Use `METEOR_WAREHOUSE_URLBASE` to do so. --- tools/packaging/warehouse.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/packaging/warehouse.js b/tools/packaging/warehouse.js index 585090d0d1..e17f33d4d7 100644 --- a/tools/packaging/warehouse.js +++ b/tools/packaging/warehouse.js @@ -43,7 +43,9 @@ var files = require('../fs/files.js'); var httpHelpers = require('../utils/http-helpers.js'); var fiberHelpers = require('../utils/fiber-helpers.js'); -var WAREHOUSE_URLBASE = 'https://warehouse.meteor.com'; +// Use `METEOR_WAREHOUSE_URLBASE` to override the default warehouse +// url base. +var WAREHOUSE_URLBASE = process.env.METEOR_WAREHOUSE_URLBASE || 'https://warehouse.meteor.com'; var warehouse = exports; _.extend(warehouse, { From 9b09d3bad4498efd40f18d374f10064970951f81 Mon Sep 17 00:00:00 2001 From: gsuess Date: Mon, 16 May 2016 18:47:24 +0200 Subject: [PATCH 06/17] Minimongo: Allow `_id` in `$setOnInsert`. --- packages/minimongo/minimongo_tests.js | 24 ++++++++++++++++++++++++ packages/minimongo/modify.js | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/packages/minimongo/minimongo_tests.js b/packages/minimongo/minimongo_tests.js index 4be1670fbb..5ef796bfc5 100644 --- a/packages/minimongo/minimongo_tests.js +++ b/packages/minimongo/minimongo_tests.js @@ -2085,6 +2085,23 @@ Tinytest.add("minimongo - modify", function (test) { exceptionWithQuery(doc, {}, mod); }; + var upsert = function (query, mod, expected) { + var coll = new LocalCollection; + + var result = coll.upsert(query, mod); + + var actual = coll.findOne(); + + if (expected._id) { + test.equal(result.insertedId, expected._id); + } + else { + delete actual._id; + } + + test.equal(actual, expected); + }; + // document replacement modify({}, {}, {}); modify({a: 12}, {}, {}); // tested against mongodb @@ -2406,6 +2423,13 @@ Tinytest.add("minimongo - modify", function (test) { exception({}, {$rename: {'a.b': 'a.b'}}); modify({a: 12, b: 13}, {$rename: {a: 'b'}}, {b: 12}); + // $setOnInsert + modify({a: 0}, {$setOnInsert: {a: 12}}, {a: 0}); + upsert({a: 12}, {$setOnInsert: {b: 12}}, {a: 12, b: 12}); + upsert({a: 12}, {$setOnInsert: {_id: 'test'}}, {_id: 'test', a: 12}); + + exception({}, {$set: {_id: 'bad'}}); + // $bit // unimplemented diff --git a/packages/minimongo/modify.js b/packages/minimongo/modify.js index 3b49ff0443..348e31a51e 100644 --- a/packages/minimongo/modify.js +++ b/packages/minimongo/modify.js @@ -49,7 +49,7 @@ LocalCollection._modify = function (doc, mod, options) { throw MinimongoError("An empty update path is not valid."); } - if (keypath === '_id') { + if (keypath === '_id' && op !== '$setOnInsert') { throw MinimongoError("Mod on _id not allowed"); } From 376df0d285ef85ce25367b574994d1ea61de0f5e Mon Sep 17 00:00:00 2001 From: Wexpo Lyu Date: Tue, 17 May 2016 17:01:58 +0800 Subject: [PATCH 07/17] Update History.md --- History.md | 1 + 1 file changed, 1 insertion(+) diff --git a/History.md b/History.md index 876c3e4404..5991d4b993 100644 --- a/History.md +++ b/History.md @@ -6,6 +6,7 @@ [PR #6760](https://github.com/meteor/meteor/pull/6760) [Issue #6532](https://github.com/meteor/meteor/issues/6532) * Allow using authType in Facebook login [PR #5694](https://github.com/meteor/meteor/pull/5694) * Adds flush() method to Tracker to force recomputation [PR #4710](https://github.com/meteor/meteor/pull/4710) +* Allow overridding the default warehouse url by specifying `METEOR_WAREHOUSE_URLBASE` [PR #7054](https://github.com/meteor/meteor/pull/7054) ## v1.3.2.3 From 2ddf14575a8b45a2899e6e6c5760fc0b8f6b6828 Mon Sep 17 00:00:00 2001 From: Eric Dobbertin Date: Thu, 10 Dec 2015 19:35:40 -0600 Subject: [PATCH 08/17] Allow new Mongo.Collection to be called multiple times for the same collection name - No error is thrown when constructing a Mongo.Collection twice for the same name if _suppressSameNameError option is true - If mutation methods were already created for a named collection, we skip them and do not throw an error - Mongo.Collection constructor takes a new option, defineMutationMethods, which can be set to false to skip creating the default mutation methods - _defineMutationMethods function performance is slightly improved by returning earlier if there is no need to loop through method types --- packages/allow-deny/allow-deny.js | 31 ++++++++++++++++-------- packages/mongo/collection.js | 29 +++++++++++++++++++--- packages/mongo/collection_tests.js | 39 ++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 14 deletions(-) diff --git a/packages/allow-deny/allow-deny.js b/packages/allow-deny/allow-deny.js index b8cf8159dc..819a4dfc59 100644 --- a/packages/allow-deny/allow-deny.js +++ b/packages/allow-deny/allow-deny.js @@ -70,8 +70,9 @@ CollectionPrototype.deny = function(options) { addValidator(this, 'deny', options); }; -CollectionPrototype._defineMutationMethods = function() { +CollectionPrototype._defineMutationMethods = function(options) { const self = this; + options = options || {}; // set to true once we call any allow or deny methods. If true, use // allow/deny semantics. If false, use insecure mode semantics. @@ -99,12 +100,26 @@ CollectionPrototype._defineMutationMethods = function() { // "Meteor:Mongo:insert/NAME"? self._prefix = '/' + self._name + '/'; - // mutation methods - if (self._connection) { + // Mutation Methods + // Minimongo on the server gets no stubs; instead, by default + // it wait()s until its result is ready, yielding. + // This matches the behavior of macromongo on the server better. + // XXX see #MeteorServerNull + if (self._connection && (self._connection === Meteor.server || Meteor.isClient)) { const m = {}; _.each(['insert', 'update', 'remove'], function (method) { - m[self._prefix + method] = function (/* ... */) { + const methodName = self._prefix + method; + + if (options.useExisting) { + const handlerPropName = Meteor.isClient ? '_methodHandlers' : 'method_handlers'; + // Do not try to create additional methods if this has already been called. + // (Otherwise the .methods() call below will throw an error.) + if (self._connection[handlerPropName] && + typeof self._connection[handlerPropName][methodName] === 'function') return; + } + + m[methodName] = function (/* ... */) { // All the methods do their own validation, instead of using check(). check(arguments, [Match.Any]); const args = _.toArray(arguments); @@ -183,12 +198,8 @@ CollectionPrototype._defineMutationMethods = function() { } }; }); - // Minimongo on the server gets no stubs; instead, by default - // it wait()s until its result is ready, yielding. - // This matches the behavior of macromongo on the server better. - // XXX see #MeteorServerNull - if (Meteor.isClient || self._connection === Meteor.server) - self._connection.methods(m); + + self._connection.methods(m); } }; diff --git a/packages/mongo/collection.js b/packages/mongo/collection.js index 98d621a7e5..6a588ac64e 100644 --- a/packages/mongo/collection.js +++ b/packages/mongo/collection.js @@ -22,6 +22,7 @@ Mongo = {}; The default id generation technique is `'STRING'`. * @param {Function} options.transform An optional transformation function. Documents will be passed through this function before being returned from `fetch` or `findOne`, and before being passed to callbacks of `observe`, `map`, `forEach`, `allow`, and `deny`. Transforms are *not* applied for the callbacks of `observeChanges` or to cursors returned from publish functions. + * @param {Boolean} options.defineMutationMethods Set to `false` to skip setting up the mutation methods that enable insert/update/remove from client code. Default `true`. */ Mongo.Collection = function (name, options) { var self = this; @@ -209,21 +210,41 @@ Mongo.Collection = function (name, options) { getDoc: function(id) { return self.findOne(id); }, - + // To be able to get back to the collection from the store. _getCollection: function () { return self; } }); - if (!ok) - throw new Error("There is already a collection named '" + name + "'"); + if (!ok) { + const message = `There is already a collection named "${name}"`; + if (options._suppressSameNameError === true) { + // XXX In theory we do not have to throw when `ok` is falsy. The store is already defined + // for this collection name, but this will simply be another reference to it and everything + // should work. However, we have historically thrown an error here, so for now we will + // skip the error only when `_suppressSameNameError` is `true`, allowing people to opt in + // and give this some real world testing. + console.warn ? console.warn(message) : console.log(message); + } else { + throw new Error(message); + } + } } // XXX don't define these until allow or deny is actually used for this // collection. Could be hard if the security rules are only defined on the // server. - self._defineMutationMethods(); + if (options.defineMutationMethods !== false) { + try { + self._defineMutationMethods({ useExisting: (options._suppressSameNameError === true) }); + } catch (error) { + // Throw a more understandable error on the server for same collection name + if (error.message === `A method named '/${name}/insert' is already defined`) + throw new Error(`There is already a collection named "${name}"`); + throw error; + } + } // autopublish if (Package.autopublish && !options._preventAutopublish && self._connection diff --git a/packages/mongo/collection_tests.js b/packages/mongo/collection_tests.js index 2e10e449d8..76ea4a73e7 100644 --- a/packages/mongo/collection_tests.js +++ b/packages/mongo/collection_tests.js @@ -9,3 +9,42 @@ Tinytest.add( ); } ); + +Tinytest.add('collection - call new Mongo.Collection multiple times', + function (test) { + new Mongo.Collection('multiple_times_1'); + + test.throws( + function () { + new Mongo.Collection('multiple_times_1'); + }, + /There is already a collection named "multiple_times_1"/ + ); + } +); + +Tinytest.add('collection - call new Mongo.Collection multiple times with _suppressSameNameError=true', + function (test) { + new Mongo.Collection('multiple_times_2'); + + try { + new Mongo.Collection('multiple_times_2', {_suppressSameNameError: true}); + test.ok(); + } catch (error) { + console.log(error); + test.fail('Expected new Mongo.Collection not to throw an error when called twice with the same name'); + } + } +); + +Tinytest.add('collection - call new Mongo.Collection with defineMutationMethods=false', + function (test) { + var handlerPropName = Meteor.isClient ? '_methodHandlers' : 'method_handlers'; + + var hasmethods = new Mongo.Collection('hasmethods'); + test.equal(typeof hasmethods._connection[handlerPropName]['/hasmethods/insert'], 'function'); + + var nomethods = new Mongo.Collection('nomethods', {defineMutationMethods: false}); + test.equal(nomethods._connection[handlerPropName]['/nomethods/insert'], undefined); + } +); From 971db8870a0d496ec60f3c7beafd0f280c20b0f9 Mon Sep 17 00:00:00 2001 From: Zoltan Olah Date: Tue, 17 May 2016 15:09:31 -0700 Subject: [PATCH 09/17] Updates History.md for PR #5778 --- History.md | 1 + 1 file changed, 1 insertion(+) diff --git a/History.md b/History.md index 876c3e4404..636e36a911 100644 --- a/History.md +++ b/History.md @@ -6,6 +6,7 @@ [PR #6760](https://github.com/meteor/meteor/pull/6760) [Issue #6532](https://github.com/meteor/meteor/issues/6532) * Allow using authType in Facebook login [PR #5694](https://github.com/meteor/meteor/pull/5694) * Adds flush() method to Tracker to force recomputation [PR #4710](https://github.com/meteor/meteor/pull/4710) +* Adds `defineMutationMethods` option (default: true) to `new Mongo.Collection` to override default behavior that sets up mutation methods (/collection/[insert|update...]) [PR #5778](https://github.com/meteor/meteor/pull/5778) ## v1.3.2.3 From 04ff1aa11598573faf3fbcd518ba69413c6721ed Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Tue, 17 May 2016 15:46:45 -0700 Subject: [PATCH 10/17] Update History.md --- History.md | 1 + 1 file changed, 1 insertion(+) diff --git a/History.md b/History.md index 6bbdfdb9dc..e5734ebcc7 100644 --- a/History.md +++ b/History.md @@ -8,6 +8,7 @@ * Adds flush() method to Tracker to force recomputation [PR #4710](https://github.com/meteor/meteor/pull/4710) * Adds `defineMutationMethods` option (default: true) to `new Mongo.Collection` to override default behavior that sets up mutation methods (/collection/[insert|update...]) [PR #5778](https://github.com/meteor/meteor/pull/5778) * Allow overridding the default warehouse url by specifying `METEOR_WAREHOUSE_URLBASE` [PR #7054](https://github.com/meteor/meteor/pull/7054) +* Allow `_id` in `$setOnInsert` in Minimongo: https://github.com/meteor/meteor/pull/7066 ## v1.3.2.3 From 65957b171313a115e71c722d4f903a860904d5d7 Mon Sep 17 00:00:00 2001 From: Sashko Stubailo Date: Tue, 17 May 2016 16:00:42 -0700 Subject: [PATCH 11/17] Make setDefault compatible with object type argument (#7021) --- packages/reactive-dict/reactive-dict-tests.js | 12 +++++++++++ packages/reactive-dict/reactive-dict.js | 20 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/packages/reactive-dict/reactive-dict-tests.js b/packages/reactive-dict/reactive-dict-tests.js index 7c845cd0f4..f67530d011 100644 --- a/packages/reactive-dict/reactive-dict-tests.js +++ b/packages/reactive-dict/reactive-dict-tests.js @@ -16,6 +16,18 @@ Tinytest.add('ReactiveDict - setDefault', function (test) { dict.setDefault('D', undefined); test.equal(dict.all(), {A: 'blah', B: undefined, C: 'default', D: undefined}); + + dict = new ReactiveDict; + dict.set('A', 'blah'); + dict.set('B', undefined); + dict.setDefault({ + A: 'default', + B: 'defualt', + C: 'default', + D: undefined + }); + test.equal(dict.all(), {A: 'blah', B: undefined, + C: 'default', D: undefined}); }); Tinytest.add('ReactiveDict - all() works', function (test) { diff --git a/packages/reactive-dict/reactive-dict.js b/packages/reactive-dict/reactive-dict.js index a807898c1b..a4d4592a54 100644 --- a/packages/reactive-dict/reactive-dict.js +++ b/packages/reactive-dict/reactive-dict.js @@ -79,8 +79,18 @@ _.extend(ReactiveDict.prototype, { } }, - setDefault: function (key, value) { + setDefault: function (keyOrObject, value) { var self = this; + + if ((typeof keyOrObject === 'object') && (value === undefined)) { + // Called as `dict.setDefault({...})` + self._setDefaultObject(keyOrObject); + return; + } + // the input isn't an object, so it must be a key + // and we resume with the rest of the function + var key = keyOrObject; + if (! _.has(self.keys, key)) { self.set(key, value); } @@ -198,6 +208,14 @@ _.extend(ReactiveDict.prototype, { }); }, + _setDefaultObject: function (object) { + var self = this; + + _.each(object, function (value, key){ + self.setDefault(key, value); + }); + }, + _ensureKey: function (key) { var self = this; if (!(key in self.keyDeps)) { From 59d61cd44ef1251718feda565607fd73c3a78d0a Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Wed, 18 May 2016 16:39:17 -0700 Subject: [PATCH 12/17] Fix collection creation tests to pass when they re-run cc @aldeed -- using test.id when you need a unique thing is the way to go. --- packages/mongo/collection_tests.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/mongo/collection_tests.js b/packages/mongo/collection_tests.js index 76ea4a73e7..e7b709e861 100644 --- a/packages/mongo/collection_tests.js +++ b/packages/mongo/collection_tests.js @@ -12,23 +12,25 @@ Tinytest.add( Tinytest.add('collection - call new Mongo.Collection multiple times', function (test) { - new Mongo.Collection('multiple_times_1'); + var collectionName = 'multiple_times_1_' + test.id; + new Mongo.Collection(collectionName); test.throws( function () { - new Mongo.Collection('multiple_times_1'); + new Mongo.Collection(collectionName); }, - /There is already a collection named "multiple_times_1"/ + /There is already a collection named/ ); } ); Tinytest.add('collection - call new Mongo.Collection multiple times with _suppressSameNameError=true', function (test) { - new Mongo.Collection('multiple_times_2'); + var collectionName = 'multiple_times_2_' + test.id; + new Mongo.Collection(collectionName); try { - new Mongo.Collection('multiple_times_2', {_suppressSameNameError: true}); + new Mongo.Collection(collectionName, {_suppressSameNameError: true}); test.ok(); } catch (error) { console.log(error); @@ -41,10 +43,12 @@ Tinytest.add('collection - call new Mongo.Collection with defineMutationMethods= function (test) { var handlerPropName = Meteor.isClient ? '_methodHandlers' : 'method_handlers'; - var hasmethods = new Mongo.Collection('hasmethods'); - test.equal(typeof hasmethods._connection[handlerPropName]['/hasmethods/insert'], 'function'); + var methodCollectionName = 'hasmethods' + test.id; + var hasmethods = new Mongo.Collection(methodCollectionName); + test.equal(typeof hasmethods._connection[handlerPropName]['/' + methodCollectionName + '/insert'], 'function'); - var nomethods = new Mongo.Collection('nomethods', {defineMutationMethods: false}); - test.equal(nomethods._connection[handlerPropName]['/nomethods/insert'], undefined); + var noMethodCollectionName = 'nomethods' + test.id; + var nomethods = new Mongo.Collection(noMethodCollectionName, {defineMutationMethods: false}); + test.equal(nomethods._connection[handlerPropName]['/' + noMethodCollectionName + '/insert'], undefined); } ); From bb551b31924af4fae5e7dd22cb6ed3b4e4233e46 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Wed, 18 May 2016 16:47:39 -0700 Subject: [PATCH 13/17] Return a correct matching object from matchingDocument in the $eq case For #4235. The previous version worked for most simple cases but was not actually correct. The idea is this function returns a "prototypical" document that can be tested by the oplog query -- this was returning `true` which tended to match but wasn't actually right. --- packages/minimongo/minimongo_server_tests.js | 2 +- packages/minimongo/selector_modifier.js | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/minimongo/minimongo_server_tests.js b/packages/minimongo/minimongo_server_tests.js index 89bd9bfbf3..38cc1476da 100644 --- a/packages/minimongo/minimongo_server_tests.js +++ b/packages/minimongo/minimongo_server_tests.js @@ -528,6 +528,7 @@ Tinytest.add("minimongo - sorter and projection combination", function (test) { // floating point math, the current implementation falls back to T T({ a: { $gt: 9.999999999999999, $lt: 10 }, x: 1 }, { $set: { x: 1 } }, "very close $gt and $lt"); T({ a: { $eq: 5 } }, { $set: { a: 5 } }, "set of $eq"); + T({ a: { $eq: 5 }, b: { $eq: 7 } }, { $set: { a: 5 } }, "set of $eq with other $eq"); F({ a: { $eq: 5 } }, { $set: { a: 4 } }, "set below of $eq"); F({ a: { $eq: 5 } }, { $set: { a: 6 } }, "set above of $eq"); T({ a: { $ne: 5 } }, { $unset: { a: 1 } }, "unset of $ne"); @@ -568,4 +569,3 @@ Tinytest.add("minimongo - sorter and projection combination", function (test) { T({ a: { $ne: { a: 2 } } }, { $set: { a: { a: 2 } } }, "$ne object"); }); })(); - diff --git a/packages/minimongo/selector_modifier.js b/packages/minimongo/selector_modifier.js index 6b097c6632..54b37df68b 100644 --- a/packages/minimongo/selector_modifier.js +++ b/packages/minimongo/selector_modifier.js @@ -142,8 +142,7 @@ Minimongo.Matcher.prototype.matchingDocument = function () { // chance we can use one of those as "matching" // dummy value if (valueSelector.$eq) { - var matcher = new Minimongo.Matcher({ placeholder: valueSelector }); - return matcher.documentMatches({ placeholder: valueSelector.$eq }); + return valueSelector.$eq; } else if (valueSelector.$in) { var matcher = new Minimongo.Matcher({ placeholder: valueSelector }); @@ -220,4 +219,3 @@ var startsWith = function(str, starts) { return str.length >= starts.length && str.substring(0, starts.length) === starts; }; - From 1000af63d3f023ebf75f03b88c89ae49fd4d52fe Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Thu, 19 May 2016 08:06:47 -0700 Subject: [PATCH 14/17] Update History.md --- History.md | 1 + 1 file changed, 1 insertion(+) diff --git a/History.md b/History.md index e5734ebcc7..cd717334c8 100644 --- a/History.md +++ b/History.md @@ -9,6 +9,7 @@ * Adds `defineMutationMethods` option (default: true) to `new Mongo.Collection` to override default behavior that sets up mutation methods (/collection/[insert|update...]) [PR #5778](https://github.com/meteor/meteor/pull/5778) * Allow overridding the default warehouse url by specifying `METEOR_WAREHOUSE_URLBASE` [PR #7054](https://github.com/meteor/meteor/pull/7054) * Allow `_id` in `$setOnInsert` in Minimongo: https://github.com/meteor/meteor/pull/7066 +* Added support for `$eq` to Minimongo: https://github.com/meteor/meteor/pull/4235 ## v1.3.2.3 From 4065990130cad86029bfb5851b3ff5641733ebf2 Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Thu, 19 May 2016 09:25:54 -0700 Subject: [PATCH 15/17] Fixed issue with not using builder properly --- tools/tool-testing/selftest.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/tool-testing/selftest.js b/tools/tool-testing/selftest.js index 29d48c76df..b8d4cbca47 100644 --- a/tools/tool-testing/selftest.js +++ b/tools/tool-testing/selftest.js @@ -834,12 +834,13 @@ _.extend(Sandbox.prototype, { var serverUrl = self.env.METEOR_PACKAGE_SERVER_URL; var packagesDirectoryName = config.getPackagesDirectoryName(serverUrl); - var builder = new Builder({outputPath: files.pathJoin(self.warehouse)}); + var builder = new Builder({outputPath: self.warehouse}); builder.copyDirectory({ from: files.pathJoin(builtPackageTropohouseDir, 'packages'), to: packagesDirectoryName, symlink: true }); + builder.complete(); var stubCatalog = { syncToken: {}, From de262b70ce28bd6193bbbf9670dd1b9eaad0d22d Mon Sep 17 00:00:00 2001 From: Tom Coleman Date: Thu, 19 May 2016 11:02:39 -0700 Subject: [PATCH 16/17] Update History.md --- History.md | 1 + 1 file changed, 1 insertion(+) diff --git a/History.md b/History.md index cd717334c8..1b7b93d17e 100644 --- a/History.md +++ b/History.md @@ -10,6 +10,7 @@ * Allow overridding the default warehouse url by specifying `METEOR_WAREHOUSE_URLBASE` [PR #7054](https://github.com/meteor/meteor/pull/7054) * Allow `_id` in `$setOnInsert` in Minimongo: https://github.com/meteor/meteor/pull/7066 * Added support for `$eq` to Minimongo: https://github.com/meteor/meteor/pull/4235 +* Insert a `Date` header into emails by default: https://github.com/meteor/meteor/pull/6916/files ## v1.3.2.3 From 026e063dcb32f40c04f325c536e2e2d0c54cf292 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Thu, 19 May 2016 21:28:48 +0300 Subject: [PATCH 17/17] Fix incorrect History entry about Match.Maybe and Match.Optional The log entry about `Match.*` bugs in 1.3.2 is actually opposite of what was changed. This clarifies it and adds an entry for the original addition of `Match.Maybe` to the 1.3 log. Fixes #7083 --- History.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/History.md b/History.md index 1b7b93d17e..acd8bdf4c9 100644 --- a/History.md +++ b/History.md @@ -58,16 +58,14 @@ * The `npm-bcrypt` package has been upgraded to use the latest version (0.8.5) of the `bcrypt` npm package. -* `Match.Optional` only passes if the value is `null` or the specified - type, whereas previously it accepted `undefined`. Use `Match.Maybe` to - allow `undefined`. #6735 - * Compiler plugins can call `addJavaScript({ path })` multiple times with different paths for the same source file, and `module.id` will reflect this `path` instead of the source path, if they are different. #6806 * Fixed bugs: https://github.com/meteor/meteor/milestones/Release%201.3.2 +* Fixed unintended change to `Match.Optional` which caused it to behave the same as the new `Match.Maybe` and incorrectly matching `null` where it previously would not have allowed it. #6735 + ## v1.3.1 * Long isopacket node_modules paths have been shortened, fixing upgrade @@ -290,6 +288,10 @@ * Improve automatic blocking of URLs in attribute values to also include `vbscript:` URLs. +### Check + +* Introduced new matcher `Match.Maybe(type)` which will also match (permit) `null` in addition to `undefined`. This is a suggested replacement (where appropriate) for `Match.Optional` which did not permit `null`. This prevents the need to use `Match.OneOf(null, undefined, type)`. #6220 + ### Testing * Packages can now be marked as `testOnly` to only run as part of app