This commit is contained in:
Miroslav Bajtoš 2019-06-25 13:29:11 +02:00
parent 58b3c4f148
commit 9338ac0bcb
No known key found for this signature in database
GPG Key ID: 669F60D63FEC1CA8
2 changed files with 107 additions and 2 deletions

View File

@ -1540,6 +1540,12 @@ DataAccessObject.find = function find(query, options, cb) {
let geoQueryObject;
if (near) {
if (options.splitLongInq) {
const msg = g.f('The option "splitLongInq" is not supported for near/geo queries.');
const error = new Error(msg);
cb(error);
return cb.promise;
}
if (supportsGeo) {
// convert it
connector.buildNearFilter(query, near);
@ -1568,7 +1574,6 @@ DataAccessObject.find = function find(query, options, cb) {
// already handled
return cb.promise;
}
}
function geoCallback(err, data) {
const memory = new Memory();
@ -1599,6 +1604,25 @@ DataAccessObject.find = function find(query, options, cb) {
geoQueryObject = query;
near = query && geo.nearFilter(query.where);
invokeConnectorMethod(connector, 'all', self, [{}], options, geoCallback);
}
function queryWithInqSplit() {
const inqLimit = self.dataSource && self.dataSource.settings &&
self.dataSource.settings.inqLimit || 256;
// clone the original query
const query = Object.assign({}, query);
query.where = Object.assign({}, query.where);
if (query.where.and || query.where.or) {
const msg = g.f('The option "splitLongInq" does not support "and" and "or" operators yet.');
const error = new Error(msg);
cb(error);
return cb.promise;
}
function allCb(err, data) {
@ -1699,6 +1723,11 @@ DataAccessObject.find = function find(query, options, cb) {
}
if (options.notify === false) {
if (options.splitLongInq && isInqQuery(query.where)) {
queryWithInqSplit();
return cb.promise;
}
invokeConnectorMethod(connector, 'all', self, [query], options, allCb);
} else {
const context = {
@ -1709,6 +1738,12 @@ DataAccessObject.find = function find(query, options, cb) {
};
this.notifyObserversOf('access', context, function(err, ctx) {
if (err) return cb(err);
if (options.splitLongInq && isInqQuery(query.where)) {
queryWithInqSplit();
return;
}
invokeConnectorMethod(connector, 'all', self, [ctx.query], options, allCb);
});
}

View File

@ -12,7 +12,7 @@ const bdd = require('./helpers/bdd-if');
const should = require('./init.js');
const uid = require('./helpers/uid-generator');
let db, User;
let db, User, Product;
describe('basic-querying', function() {
before(function(done) {
@ -52,6 +52,11 @@ describe('basic-querying', function() {
(db.adapter.name != 'informix') && (db.adapter.name != 'cassandra');
if (connectorCapabilities.geoPoint) userModelDef.addressLoc = {type: 'GeoPoint'};
User = db.define('User', userModelDef);
Product = db.define('Product', {
name: {type: String, required: true},
});
db.automigrate(done);
});
@ -1127,6 +1132,71 @@ describe('basic-querying', function() {
}, done);
});
});
bdd.describeIf(connectorCapabilities.supportInq !== false, 'inq query', () => {
let originalInqLimit;
let originalAll;
let observedCalls;
before(async function setupTestModels() {
Product = db.define('Product', {
name: {type: String, required: true},
});
await db.automigrate(Product.modelName);
originalInqLimit = db.settings.inqLimit;
originalAll = db.connector.all;
if ((db.settings.inqLimit || Infinity) > 5) {
// artificially reduce the inqLimit to a small number to trigger
// inq splitting even for connectors that support arbitrarily-long
// inq lists and also to keep the test fast
db.settings.inqLimit = 3;
}
});
afterEach(function restoreOriginalState() {
db.settings.inqLimit = originalInqLimit;
db.connector.all = originalAll;
});
it('rejects geo queries with inq splitting', function() {
const where = {
id: {inq: [1, 2, 3]},
location: {near: {lat: 29.9, lng: -90.07}},
};
return Product.find({where}, {splitLongInq: true})
.should.be.rejectedWith(/splitLongInq.*not supported/);
});
it('splits large inq list', async function() {
const observedCalls = [];
db.connector.all = function(modelName, query, options, cb) {
observedCalls.push({modelName, query, options});
originalAll.apply(this, arguments);
};
const created = [];
// Notice that 10 is not divisible by inqLimit
for (let i = 0; i < 10; i++) {
// Create a product that we will look for
created.push(await Product.create({name: `a-product-${i}`}));
// Create also a product that won't be matched by the query
await Product.create({name: `another-product-${i}`});
}
const found = await Product.find(
{where: {id: {inq: created.map(u => u.id)}}},
{splitLongInq: true}
);
// Records were found correctly
found.map(u => u.name).should.eql(created.map(u => u.name));
// Multiple database queries were sent
observedCalls.length.should.be.greaterThan(1);
});
});
});
// FIXME: This should either be re-enabled or removed.