Skip to content

Commit

Permalink
Merge branch 'release-0.5.6'
Browse files Browse the repository at this point in the history
  • Loading branch information
Naomi Seyfer committed Feb 15, 2013
2 parents 3753c98 + aaa86c3 commit 405cd9e
Show file tree
Hide file tree
Showing 12 changed files with 213 additions and 30 deletions.
9 changes: 9 additions & 0 deletions History.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@

## vNEXT

## v0.5.6

* Fix 0.5.5 regression: Minimongo selectors matching subdocuments under arrays
did not work correctly.

* Some Bootstrap icons should have appeared white.

Patches contributed by GitHub user benjaminchelli.

## v0.5.5

* Deprecate `Meteor.autosubscribe`. `Meteor.subscribe` now works within
Expand Down
2 changes: 1 addition & 1 deletion admin/debian/changelog
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
meteor (0.5.5-1) unstable; urgency=low
meteor (0.5.6-1) unstable; urgency=low

* Automated debian build.

Expand Down
2 changes: 1 addition & 1 deletion admin/install-s3.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## example.

URLBASE="https://d3sqy0vbqsdhku.cloudfront.net"
VERSION="0.5.5"
VERSION="0.5.6"
PKGVERSION="${VERSION}-1"

UNAME=`uname`
Expand Down
6 changes: 3 additions & 3 deletions admin/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": "0.5.5",
"deb_version": "0.5.5-1",
"rpm_version": "0.5.5-1",
"version": "0.5.6",
"deb_version": "0.5.6-1",
"rpm_version": "0.5.6-1",
"urlbase": "https://d3sqy0vbqsdhku.cloudfront.net"
}
2 changes: 1 addition & 1 deletion admin/meteor.spec
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Summary: Meteor platform and JavaScript application server
Vendor: Meteor
Name: meteor
Version: 0.5.5
Version: 0.5.6
Release: 1
License: MIT
Group: Networking/WWW
Expand Down
2 changes: 1 addition & 1 deletion app/lib/updater.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// true. This will make it act as if it is at version 0.1.0 and use test URLs
// for update checks.
var testingUpdater = false;
exports.CURRENT_VERSION = testingUpdater ? "0.1.0" : "0.5.5";
exports.CURRENT_VERSION = testingUpdater ? "0.1.0" : "0.5.6";

var fs = require("fs");
var http = require("http");
Expand Down
2 changes: 1 addition & 1 deletion app/meteor/post-upgrade.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ try {
// XXX can't get this from updater.js because in 0.3.7 and before the
// updater didn't have the right NODE_PATH set. At some point we can
// remove this and just use updater.CURRENT_VERSION.
var VERSION = "0.5.5";
var VERSION = "0.5.6";

var fs = require('fs');
var path = require('path');
Expand Down
2 changes: 1 addition & 1 deletion docs/client/docs.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</div>
<div id="main">
<div id="top"></div>
<h1 class="main-headline">Meteor 0.5.5</h1>
<h1 class="main-headline">Meteor 0.5.6</h1>
{{> introduction }}
{{> concepts }}
{{> api }}
Expand Down
2 changes: 1 addition & 1 deletion docs/client/docs.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
METEOR_VERSION = "0.5.5";
METEOR_VERSION = "0.5.6";

Meteor.startup(function () {
// XXX this is broken by the new multi-page layout. Also, it was
Expand Down
27 changes: 24 additions & 3 deletions packages/bootstrap/css/bootstrap-override.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*
/*
* XXX Hack to make bootstrap work when bundled. This needs to be included
* _after_ the standard bootstrap css files.
*
Expand All @@ -10,7 +10,28 @@
[class*=" icon-"] {
background-image: url("/packages/bootstrap/img/glyphicons-halflings.png");
}

.icon-white {
/*
* Selectors borrowed from bootstrap.css. For all releases of bootstrap, when
* we upgrade, update this file to borrow the selectors from where bootstrap.css
* references any .png. When we update to using .less instead, use the less
* directives in a less file instead.
*/
.icon-white,
.nav-pills > .active > a > [class^="icon-"],
.nav-pills > .active > a > [class*=" icon-"],
.nav-list > .active > a > [class^="icon-"],
.nav-list > .active > a > [class*=" icon-"],
.navbar-inverse .nav > .active > a > [class^="icon-"],
.navbar-inverse .nav > .active > a > [class*=" icon-"],
.dropdown-menu > li > a:hover > [class^="icon-"],
.dropdown-menu > li > a:focus > [class^="icon-"],
.dropdown-menu > li > a:hover > [class*=" icon-"],
.dropdown-menu > li > a:focus > [class*=" icon-"],
.dropdown-menu > .active > a > [class^="icon-"],
.dropdown-menu > .active > a > [class*=" icon-"],
.dropdown-submenu:hover > a > [class^="icon-"],
.dropdown-submenu:focus > a > [class^="icon-"],
.dropdown-submenu:hover > a > [class*=" icon-"],
.dropdown-submenu:focus > a > [class*=" icon-"] {
background-image: url("/packages/bootstrap/img/glyphicons-halflings-white.png");
}
72 changes: 70 additions & 2 deletions packages/minimongo/minimongo_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,26 @@ Tinytest.add("minimongo - misc", function (test) {
test.equal(b.x.a, 14); // just to document current behavior
});

Tinytest.add("minimongo - lookup", function (test) {
var lookupA = LocalCollection._makeLookupFunction('a');
test.equal(lookupA({}), [undefined]);
test.equal(lookupA({a: 1}), [1]);
test.equal(lookupA({a: [1]}), [[1]]);

var lookupAX = LocalCollection._makeLookupFunction('a.x');
test.equal(lookupAX({a: {x: 1}}), [1]);
test.equal(lookupAX({a: {x: [1]}}), [[1]]);
test.equal(lookupAX({a: 5}), [undefined]);
test.equal(lookupAX({a: [{x: 1}, {x: [2]}, {y: 3}]}),
[1, [2], undefined]);

var lookupA0X = LocalCollection._makeLookupFunction('a.0.x');
test.equal(lookupA0X({a: [{x: 1}]}), [1]);
test.equal(lookupA0X({a: [{x: [1]}]}), [[1]]);
test.equal(lookupA0X({a: 5}), [undefined]);
test.equal(lookupA0X({a: [{x: 1}, {x: [2]}, {y: 3}]}), [1]);
});

Tinytest.add("minimongo - selector_compiler", function (test) {
var matches = function (should_match, selector, doc) {
var does_match = LocalCollection._matches(selector, doc);
Expand Down Expand Up @@ -808,6 +828,21 @@ Tinytest.add("minimongo - selector_compiler", function (test) {
nomatch({"dogs.1.name": "Fido"}, {dogs: [{name: "Fido"}, {name: "Rex"}]});
match({"room.1b": "bla"}, {room: {"1b": "bla"}});

match({"dogs.name": "Fido"}, {dogs: [{name: "Fido"}, {name: "Rex"}]});
match({"dogs.name": "Rex"}, {dogs: [{name: "Fido"}, {name: "Rex"}]});
match({"animals.dogs.name": "Fido"},
{animals: [{dogs: [{name: "Rover"}]},
{},
{dogs: [{name: "Fido"}, {name: "Rex"}]}]});
match({"animals.dogs.name": "Fido"},
{animals: [{dogs: {name: "Rex"}},
{dogs: {name: "Fido"}}]});
match({"animals.dogs.name": "Fido"},
{animals: [{dogs: [{name: "Rover"}]},
{},
{dogs: [{name: ["Fido"]}, {name: "Rex"}]}]});
nomatch({"dogs.name": "Fido"}, {dogs: []});

// $elemMatch
match({dogs: {$elemMatch: {name: /e/}}},
{dogs: [{name: "Fido"}, {name: "Rex"}]});
Expand Down Expand Up @@ -847,10 +882,19 @@ Tinytest.add("minimongo - ordering", function (test) {
});
};

// note: [] doesn't sort with "arrays", it sorts as "undefined". the position
// of arrays in _typeorder only matters for things like $lt. (This behavior
// verified with MongoDB 2.2.1.) We don't define the relative order of {a: []}
// and {c: 1} is undefined (MongoDB does seem to care but it's not clear how
// or why).
verify([{"a" : 1}, ["a"], [["a", "asc"]]],
[{a: []}, {a: 1}, {a: {}}, {a: true}]);
verify([{"a" : 1}, ["a"], [["a", "asc"]]],
[{c: 1}, {a: 1}, {a: {}}, {a: []}, {a: true}]);
[{c: 1}, {a: 1}, {a: {}}, {a: true}]);
verify([{"a" : -1}, [["a", "desc"]]],
[{a: true}, {a: []}, {a: {}}, {a: 1}, {c: 1}]);
[{a: true}, {a: {}}, {a: 1}, {c: 1}]);
verify([{"a" : -1}, [["a", "desc"]]],
[{a: true}, {a: {}}, {a: 1}, {a: []}]);

verify([{"a" : 1, "b": -1}, ["a", ["b", "desc"]],
[["a", "asc"], ["b", "desc"]]],
Expand Down Expand Up @@ -935,6 +979,30 @@ Tinytest.add("minimongo - subkey sort", function (test) {
test.equal(c.find({}, {sort: {'a.nope.c': -1}}).count(), 6);
});

Tinytest.add("minimongo - array sort", function (test) {
var c = new LocalCollection();

// "up" and "down" are the indices that the docs should have when sorted
// ascending and descending by "a.x" respectively. They are not reverses of
// each other: when sorting ascending, you use the minimum value you can find
// in the document, and when sorting descending, you use the maximum value you
// can find. So [1, 4] shows up in the 1 slot when sorting ascending and the 4
// slot when sorting descending.
c.insert({up: 1, down: 1, a: {x: [1, 4]}});
c.insert({up: 2, down: 2, a: [{x: [2]}, {x: 3}]});
c.insert({up: 0, down: 4, a: {x: 0}});
c.insert({up: 3, down: 3, a: {x: 2.5}});
c.insert({up: 4, down: 0, a: {x: 5}});

test.equal(
_.pluck(c.find({}, {sort: {'a.x': 1}}).fetch(), 'up'),
_.range(c.find().count()));

test.equal(
_.pluck(c.find({}, {sort: {'a.x': -1}}).fetch(), 'down'),
_.range(c.find().count()));
});


Tinytest.add("minimongo - modify", function (test) {
var modify = function (doc, mod, result) {
Expand Down
115 changes: 100 additions & 15 deletions packages/minimongo/selector.js
Original file line number Diff line number Diff line change
Expand Up @@ -478,18 +478,61 @@ LocalCollection._matches = function (selector, doc) {
return (LocalCollection._compileSelector(selector))(doc);
};

var makeLookupFunction = function (key) {
// _makeLookupFunction(key) returns a lookup function.
//
// A lookup function takes in a document and returns an array of matching
// values. This array has more than one element if any segment of the key other
// than the last one is an array. ie, any arrays found when doing non-final
// lookups result in this function "branching"; each element in the returned
// array represents the value found at this branch. If any branch doesn't have a
// final value for the full key, its element in the returned list will be
// undefined. It always returns a non-empty array.
//
// _makeLookupFunction('a.x')({a: {x: 1}}) returns [1]
// _makeLookupFunction('a.x')({a: {x: [1]}}) returns [[1]]
// _makeLookupFunction('a.x')({a: 5}) returns [undefined]
// _makeLookupFunction('a.x')({a: [{x: 1},
// {x: [2]},
// {y: 3}]})
// returns [1, [2], undefined]
LocalCollection._makeLookupFunction = function (key) {
var dotLocation = key.indexOf('.');
var first = dotLocation === -1 ? key : key.substr(0, dotLocation);
var lookupRest = dotLocation !== -1 &&
makeLookupFunction(key.substr(dotLocation + 1));
var first, lookupRest, nextIsNumeric;
if (dotLocation === -1) {
first = key;
} else {
first = key.substr(0, dotLocation);
var rest = key.substr(dotLocation + 1);
lookupRest = LocalCollection._makeLookupFunction(rest);
// Is the next (perhaps final) piece numeric (ie, an array lookup?)
nextIsNumeric = /^\d+(\.|$)/.test(rest);
}

return function (doc) {
if (doc == null) // null or undefined
return undefined;
return [undefined];
var firstLevel = doc[first];
if (lookupRest)
return lookupRest(firstLevel);
return firstLevel;

// We don't "branch" at the final level.
if (!lookupRest)
return [firstLevel];

// It's an empty array, and we're not done: we won't find anything.
if (_.isArray(firstLevel) && firstLevel.length === 0)
return [undefined];

// For each result at this level, finish the lookup on the rest of the key,
// and return everything we find. Also, if the next result is a number,
// don't branch here.
//
// Technically, in MongoDB, we should be able to handle the case where
// objects have numeric keys, but Mongo doesn't actually handle this
// consistently yet itself, see eg
// https://jira.mongodb.org/browse/SERVER-2898
// https://github.com/mongodb/mongo/blob/master/jstests/array_match2.js
if (!_.isArray(firstLevel) || nextIsNumeric)
firstLevel = [firstLevel];
return Array.prototype.concat.apply([], _.map(firstLevel, lookupRest));
};
};

Expand All @@ -504,10 +547,14 @@ var compileDocumentSelector = function (docSelector) {
throw new Error("Unrecognized logical operator: " + key);
perKeySelectors.push(LOGICAL_OPERATORS[key](subSelector));
} else {
var lookUpByIndex = makeLookupFunction(key);
var lookUpByIndex = LocalCollection._makeLookupFunction(key);
var valueSelectorFunc = compileValueSelector(subSelector);
perKeySelectors.push(function (doc) {
return valueSelectorFunc(lookUpByIndex(doc));
var branchValues = lookUpByIndex(doc);
// We apply the selector to each "branched" value and return true if any
// match. This isn't 100% consistent with MongoDB; eg, see:
// https://jira.mongodb.org/browse/SERVER-8585
return _.any(branchValues, valueSelectorFunc);
});
}
});
Expand Down Expand Up @@ -570,20 +617,20 @@ LocalCollection._compileSort = function (spec) {
for (var i = 0; i < spec.length; i++) {
if (typeof spec[i] === "string") {
sortSpecParts.push({
lookup: makeLookupFunction(spec[i]),
lookup: LocalCollection._makeLookupFunction(spec[i]),
ascending: true
});
} else {
sortSpecParts.push({
lookup: makeLookupFunction(spec[i][0]),
lookup: LocalCollection._makeLookupFunction(spec[i][0]),
ascending: spec[i][1] !== "desc"
});
}
}
} else if (typeof spec === "object") {
for (var key in spec) {
sortSpecParts.push({
lookup: makeLookupFunction(key),
lookup: LocalCollection._makeLookupFunction(key),
ascending: spec[key] >= 0
});
}
Expand All @@ -594,11 +641,49 @@ LocalCollection._compileSort = function (spec) {
if (sortSpecParts.length === 0)
return function () {return 0;};

// reduceValue takes in all the possible values for the sort key along various
// branches, and returns the min or max value (according to the bool
// findMin). Each value can itself be an array, and we look at its values
// too. (ie, we do a single level of flattening on branchValues, then find the
// min/max.)
var reduceValue = function (branchValues, findMin) {
var reduced;
var first = true;
// Iterate over all the values found in all the branches, and if a value is
// an array itself, iterate over the values in the array separately.
_.each(branchValues, function (branchValue) {
// Value not an array? Pretend it is.
if (!_.isArray(branchValue))
branchValue = [branchValue];
// Value is an empty array? Pretend it was missing, since that's where it
// should be sorted.
if (_.isArray(branchValue) && branchValue.length === 0)
branchValue = [undefined];
_.each(branchValue, function (value) {
// We should get here at least once: lookup functions return non-empty
// arrays, so the outer loop runs at least once, and we prevented
// branchValue from being an empty array.
if (first) {
reduced = value;
first = false;
} else {
// Compare the value we found to the value we found so far, saving it
// if it's less (for an ascending sort) or more (for a descending
// sort).
var cmp = LocalCollection._f._cmp(reduced, value);
if ((findMin && cmp > 0) || (!findMin && cmp < 0))
reduced = value;
}
});
});
return reduced;
};

return function (a, b) {
for (var i = 0; i < sortSpecParts.length; ++i) {
var specPart = sortSpecParts[i];
var aValue = specPart.lookup(a);
var bValue = specPart.lookup(b);
var aValue = reduceValue(specPart.lookup(a), specPart.ascending);
var bValue = reduceValue(specPart.lookup(b), specPart.ascending);
var compare = LocalCollection._f._cmp(aValue, bValue);
if (compare !== 0)
return specPart.ascending ? compare : -compare;
Expand Down

0 comments on commit 405cd9e

Please sign in to comment.