Skip to content

Commit 06cac9e

Browse files
authored
Merge pull request #996 from strongloop/fix/order-in-find
Ensure stable order of items in DAO.find()
2 parents f7e2021 + 699e058 commit 06cac9e

File tree

2 files changed

+47
-21
lines changed

2 files changed

+47
-21
lines changed

lib/dao.js

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1678,26 +1678,22 @@ DataAccessObject.find = function find(query, options, cb) {
16781678
}
16791679

16801680
var allCb = function(err, data) {
1681-
var results = [];
16821681
if (!err && Array.isArray(data)) {
1683-
async.each(data, function(item, callback) {
1684-
var d = item;//data[i];
1685-
var Model = self.lookupModel(d);
1682+
async.map(data, function(item, next) {
1683+
var Model = self.lookupModel(item);
16861684
if (options.notify === false) {
1687-
buildResult(d);
1685+
buildResult(item, next);
16881686
} else {
1689-
withNotify();
1687+
withNotify(item, next);
16901688
}
16911689

1692-
function buildResult(data) {
1693-
d = data;
1694-
1690+
function buildResult(data, callback) {
16951691
var ctorOpts = {
16961692
fields: query.fields,
16971693
applySetters: false,
16981694
persisted: true,
16991695
};
1700-
var obj = new Model(d, ctorOpts);
1696+
var obj = new Model(data, ctorOpts);
17011697

17021698
if (query && query.include) {
17031699
if (query.collect) {
@@ -1730,32 +1726,33 @@ DataAccessObject.find = function find(query, options, cb) {
17301726
}
17311727
}
17321728

1733-
if (obj !== undefined) {
1734-
results.push(obj);
1735-
callback();
1736-
} else {
1737-
callback();
1738-
}
1729+
callback(null, obj);
17391730
}
17401731

1741-
function withNotify() {
1742-
context = {
1732+
function withNotify(data, callback) {
1733+
var context = {
17431734
Model: Model,
1744-
data: d,
1735+
data: data,
17451736
isNewInstance: false,
17461737
hookState: hookState,
17471738
options: options,
17481739
};
17491740

17501741
Model.notifyObserversOf('loaded', context, function(err) {
17511742
if (err) return callback(err);
1752-
buildResult(context.data);
1743+
buildResult(context.data, callback);
17531744
});
17541745
}
17551746
},
1756-
function(err) {
1747+
function(err, results) {
17571748
if (err) return cb(err);
17581749

1750+
// When applying query.collect, some root items may not have
1751+
// any related/linked item. We store `undefined` in the results
1752+
// array in such case, which is not desirable from API consumer's
1753+
// point of view.
1754+
results = results.filter(isDefined);
1755+
17591756
if (data && data.countBeforeLimit) {
17601757
results.countBeforeLimit = data.countBeforeLimit;
17611758
}
@@ -1794,6 +1791,10 @@ DataAccessObject.find = function find(query, options, cb) {
17941791
return cb.promise;
17951792
};
17961793

1794+
function isDefined(value) {
1795+
return value !== undefined;
1796+
}
1797+
17971798
/**
17981799
* Find one record, same as `find`, but limited to one result. This function returns an object, not a collection.
17991800
*

test/basic-querying.test.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,14 @@ describe('basic-querying', function() {
129129

130130
before(seed);
131131

132+
before(function setupDelayingLoadedHook() {
133+
User.observe('loaded', nextAfterDelay);
134+
});
135+
136+
after(function removeDelayingLoadHook() {
137+
User.removeObserver('loaded', nextAfterDelay);
138+
});
139+
132140
it('should query collection', function(done) {
133141
User.find(function(err, users) {
134142
should.exists(users);
@@ -220,6 +228,18 @@ describe('basic-querying', function() {
220228
});
221229
});
222230

231+
it('should query sorted desc by order integer field even though there' +
232+
'is an async model loaded hook', function(done) {
233+
User.find({ order: 'order DESC' }, function(err, users) {
234+
if (err) return done(err);
235+
236+
should.exists(users);
237+
var order = users.map(function(u) { return u.order; });
238+
order.should.eql([6, 5, 4, 3, 2, 1]);
239+
done();
240+
});
241+
});
242+
223243
it('should support "and" operator that is satisfied', function(done) {
224244
User.find({ where: { and: [
225245
{ name: 'John Lennon' },
@@ -826,3 +846,8 @@ function seed(done) {
826846
},
827847
], done);
828848
}
849+
850+
function nextAfterDelay(ctx, next) {
851+
var randomTimeoutTrigger = Math.floor(Math.random() * 100);
852+
setTimeout(function() { process.nextTick(next); }, randomTimeoutTrigger);
853+
}

0 commit comments

Comments
 (0)