Merge pull request #1108 from strongloop/fix_geo_2.x
Fix the bug when near filter is used
This commit is contained in:
commit
8caf4c8327
314
lib/dao.js
314
lib/dao.js
|
@ -1798,174 +1798,174 @@ DataAccessObject.find = function find(query, options, cb) {
|
||||||
var near = query && geo.nearFilter(query.where);
|
var near = query && geo.nearFilter(query.where);
|
||||||
var supportsGeo = !!connector.buildNearFilter;
|
var supportsGeo = !!connector.buildNearFilter;
|
||||||
|
|
||||||
if (near) {
|
if (query.where && near && !supportsGeo) {
|
||||||
if (supportsGeo) {
|
// do in memory query
|
||||||
// convert it
|
// using all documents
|
||||||
connector.buildNearFilter(query, near);
|
// TODO [fabien] use default scope here?
|
||||||
} else if (query.where) {
|
|
||||||
// do in memory query
|
|
||||||
// using all documents
|
|
||||||
// TODO [fabien] use default scope here?
|
|
||||||
|
|
||||||
if (options.notify === false) {
|
if (options.notify === false) {
|
||||||
queryGeo(query);
|
queryGeo(query);
|
||||||
} else {
|
} else {
|
||||||
withNotifyGeo();
|
withNotifyGeo();
|
||||||
}
|
|
||||||
|
|
||||||
function withNotifyGeo() {
|
|
||||||
var context = {
|
|
||||||
Model: self,
|
|
||||||
query: query,
|
|
||||||
hookState: hookState,
|
|
||||||
options: options,
|
|
||||||
};
|
|
||||||
self.notifyObserversOf('access', context, function(err, ctx) {
|
|
||||||
if (err) return cb(err);
|
|
||||||
queryGeo(ctx.query);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function queryGeo(query) {
|
|
||||||
function geoCallback(err, data) {
|
|
||||||
var memory = new Memory();
|
|
||||||
var modelName = self.modelName;
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
cb(err);
|
|
||||||
} else if (Array.isArray(data)) {
|
|
||||||
memory.define({
|
|
||||||
properties: self.dataSource.definitions[self.modelName].properties,
|
|
||||||
settings: self.dataSource.definitions[self.modelName].settings,
|
|
||||||
model: self,
|
|
||||||
});
|
|
||||||
|
|
||||||
data.forEach(function(obj) {
|
|
||||||
memory.create(modelName, obj, options, function() {
|
|
||||||
// noop
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// FIXME: apply "includes" and other transforms - see allCb below
|
|
||||||
memory.all(modelName, query, options, cb);
|
|
||||||
} else {
|
|
||||||
cb(null, []);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connector.all.length === 4) {
|
|
||||||
connector.all(self.modelName, {}, options, geoCallback);
|
|
||||||
} else {
|
|
||||||
connector.all(self.modelName, {}, geoCallback);
|
|
||||||
}
|
|
||||||
// already handled
|
|
||||||
return cb.promise;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var allCb = function(err, data) {
|
function withNotifyGeo() {
|
||||||
if (!err && Array.isArray(data)) {
|
var context = {
|
||||||
async.map(data, function(item, next) {
|
Model: self,
|
||||||
var Model = self.lookupModel(item);
|
query: query,
|
||||||
var obj = new Model(item, { fields: query.fields, applySetters: false, persisted: true });
|
hookState: hookState,
|
||||||
|
options: options,
|
||||||
if (query && query.include) {
|
};
|
||||||
if (query.collect) {
|
self.notifyObserversOf('access', context, function(err, ctx) {
|
||||||
// The collect property indicates that the query is to return the
|
|
||||||
// standalone items for a related model, not as child of the parent object
|
|
||||||
// For example, article.tags
|
|
||||||
obj = obj.__cachedRelations[query.collect];
|
|
||||||
if (obj === null) {
|
|
||||||
obj = undefined;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// This handles the case to return parent items including the related
|
|
||||||
// models. For example, Article.find({include: 'tags'}, ...);
|
|
||||||
// Try to normalize the include
|
|
||||||
var includes = Inclusion.normalizeInclude(query.include || []);
|
|
||||||
includes.forEach(function(inc) {
|
|
||||||
var relationName = inc;
|
|
||||||
if (utils.isPlainObject(inc)) {
|
|
||||||
relationName = Object.keys(inc)[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Promote the included model as a direct property
|
|
||||||
var included = obj.__cachedRelations[relationName];
|
|
||||||
if (Array.isArray(included)) {
|
|
||||||
included = new List(included, null, obj);
|
|
||||||
}
|
|
||||||
if (included) obj.__data[relationName] = included;
|
|
||||||
});
|
|
||||||
delete obj.__data.__cachedRelations;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (obj !== undefined) {
|
|
||||||
if (options.notify === false) {
|
|
||||||
next(null, obj);
|
|
||||||
} else {
|
|
||||||
context = {
|
|
||||||
Model: Model,
|
|
||||||
instance: obj,
|
|
||||||
isNewInstance: false,
|
|
||||||
hookState: hookState,
|
|
||||||
options: options,
|
|
||||||
};
|
|
||||||
|
|
||||||
Model.notifyObserversOf('loaded', context, function(err) {
|
|
||||||
if (err) return next(err);
|
|
||||||
|
|
||||||
next(null, obj);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function(err, results) {
|
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
queryGeo(ctx.query);
|
||||||
// When applying query.collect, some root items may not have
|
|
||||||
// any related/linked item. We store `undefined` in the results
|
|
||||||
// array in such case, which is not desirable from API consumer's
|
|
||||||
// point of view.
|
|
||||||
results = results.filter(isDefined);
|
|
||||||
|
|
||||||
if (data && data.countBeforeLimit) {
|
|
||||||
results.countBeforeLimit = data.countBeforeLimit;
|
|
||||||
}
|
|
||||||
if (!supportsGeo && near) {
|
|
||||||
results = geo.filter(results, near);
|
|
||||||
}
|
|
||||||
|
|
||||||
cb(err, results);
|
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
cb(err, data || []);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if (options.notify === false) {
|
function queryGeo(query) {
|
||||||
if (connector.all.length === 4) {
|
function geoCallback(err, data) {
|
||||||
connector.all(self.modelName, query, options, allCb);
|
var memory = new Memory();
|
||||||
} else {
|
var modelName = self.modelName;
|
||||||
connector.all(self.modelName, query, allCb);
|
|
||||||
|
if (err) {
|
||||||
|
cb(err);
|
||||||
|
} else if (Array.isArray(data)) {
|
||||||
|
memory.define({
|
||||||
|
properties: self.dataSource.definitions[self.modelName].properties,
|
||||||
|
settings: self.dataSource.definitions[self.modelName].settings,
|
||||||
|
model: self,
|
||||||
|
});
|
||||||
|
|
||||||
|
data.forEach(function(obj) {
|
||||||
|
memory.create(modelName, obj, options, function() {
|
||||||
|
// noop
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// FIXME: apply "includes" and other transforms - see allCb below
|
||||||
|
memory.all(modelName, query, options, cb);
|
||||||
|
} else {
|
||||||
|
cb(null, []);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connector.all.length === 4) {
|
||||||
|
connector.all(self.modelName, {}, options, geoCallback);
|
||||||
|
} else {
|
||||||
|
connector.all(self.modelName, {}, geoCallback);
|
||||||
|
}
|
||||||
|
// already handled
|
||||||
|
return cb.promise;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var context = {
|
if (near && supportsGeo) {
|
||||||
Model: this,
|
connector.buildNearFilter(query, near);
|
||||||
query: query,
|
}
|
||||||
hookState: hookState,
|
|
||||||
options: options,
|
|
||||||
};
|
|
||||||
this.notifyObserversOf('access', context, function(err, ctx) {
|
|
||||||
if (err) return cb(err);
|
|
||||||
|
|
||||||
connector.all.length === 4 ?
|
var allCb = function(err, data) {
|
||||||
connector.all(self.modelName, ctx.query, options, allCb) :
|
if (!err && Array.isArray(data)) {
|
||||||
connector.all(self.modelName, ctx.query, allCb);
|
async.map(data, function(item, next) {
|
||||||
});
|
var Model = self.lookupModel(item);
|
||||||
|
var obj = new Model(item, { fields: query.fields, applySetters: false, persisted: true });
|
||||||
|
|
||||||
|
if (query && query.include) {
|
||||||
|
if (query.collect) {
|
||||||
|
// The collect property indicates that the query is to return the
|
||||||
|
// standalone items for a related model, not as child of the parent object
|
||||||
|
// For example, article.tags
|
||||||
|
obj = obj.__cachedRelations[query.collect];
|
||||||
|
if (obj === null) {
|
||||||
|
obj = undefined;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This handles the case to return parent items including the related
|
||||||
|
// models. For example, Article.find({include: 'tags'}, ...);
|
||||||
|
// Try to normalize the include
|
||||||
|
var includes = Inclusion.normalizeInclude(query.include || []);
|
||||||
|
includes.forEach(function(inc) {
|
||||||
|
var relationName = inc;
|
||||||
|
if (utils.isPlainObject(inc)) {
|
||||||
|
relationName = Object.keys(inc)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Promote the included model as a direct property
|
||||||
|
var included = obj.__cachedRelations[relationName];
|
||||||
|
if (Array.isArray(included)) {
|
||||||
|
included = new List(included, null, obj);
|
||||||
|
}
|
||||||
|
if (included) obj.__data[relationName] = included;
|
||||||
|
});
|
||||||
|
delete obj.__data.__cachedRelations;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (obj !== undefined) {
|
||||||
|
if (options.notify === false) {
|
||||||
|
next(null, obj);
|
||||||
|
} else {
|
||||||
|
context = {
|
||||||
|
Model: Model,
|
||||||
|
instance: obj,
|
||||||
|
isNewInstance: false,
|
||||||
|
hookState: hookState,
|
||||||
|
options: options,
|
||||||
|
};
|
||||||
|
|
||||||
|
Model.notifyObserversOf('loaded', context, function(err) {
|
||||||
|
if (err) return next(err);
|
||||||
|
|
||||||
|
next(null, obj);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function(err, results) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
|
||||||
|
// When applying query.collect, some root items may not have
|
||||||
|
// any related/linked item. We store `undefined` in the results
|
||||||
|
// array in such case, which is not desirable from API consumer's
|
||||||
|
// point of view.
|
||||||
|
results = results.filter(isDefined);
|
||||||
|
|
||||||
|
if (data && data.countBeforeLimit) {
|
||||||
|
results.countBeforeLimit = data.countBeforeLimit;
|
||||||
|
}
|
||||||
|
if (!supportsGeo && near) {
|
||||||
|
results = geo.filter(results, near);
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(err, results);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cb(err, data || []);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.notify === false) {
|
||||||
|
if (connector.all.length === 4) {
|
||||||
|
connector.all(self.modelName, query, options, allCb);
|
||||||
|
} else {
|
||||||
|
connector.all(self.modelName, query, allCb);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var context = {
|
||||||
|
Model: this,
|
||||||
|
query: query,
|
||||||
|
hookState: hookState,
|
||||||
|
options: options,
|
||||||
|
};
|
||||||
|
this.notifyObserversOf('access', context, function(err, ctx) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
|
||||||
|
connector.all.length === 4 ?
|
||||||
|
connector.all(self.modelName, ctx.query, options, allCb) :
|
||||||
|
connector.all(self.modelName, ctx.query, allCb);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return cb.promise;
|
||||||
}
|
}
|
||||||
return cb.promise;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function isDefined(value) {
|
function isDefined(value) {
|
||||||
|
|
|
@ -86,6 +86,19 @@ module.exports = function(dataSource, should, connectorCapabilities) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('triggers correct hooks when near filter is used', function(done) {
|
||||||
|
monitorHookExecution();
|
||||||
|
var query = { where:
|
||||||
|
{ location: { near: '10,20', maxDistance: '10', unit: 'meters' }},
|
||||||
|
};
|
||||||
|
|
||||||
|
TestModel.find(query, function(err, list) {
|
||||||
|
if (err) return done(err);
|
||||||
|
hookMonitor.names.should.eql(['access']);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should not trigger hooks, if notify is false', function(done) {
|
it('should not trigger hooks, if notify is false', function(done) {
|
||||||
monitorHookExecution();
|
monitorHookExecution();
|
||||||
TestModel.find(
|
TestModel.find(
|
||||||
|
|
Loading…
Reference in New Issue