* Add a tests that fails due to issue #5285 * Make test code much simpler * Fix #5285 by rewriting query (replacing $nearSphere by $geoWithin) All credit goes to @dplewis ! * move logic to transform
This commit is contained in:
committed by
Diamond Lewis
parent
7e130c5421
commit
7122ca05c4
@@ -11,9 +11,8 @@ describe('Parse.GeoPoint testing', () => {
|
|||||||
obj.set('location', point);
|
obj.set('location', point);
|
||||||
obj.set('name', 'Ferndale');
|
obj.set('name', 'Ferndale');
|
||||||
await obj.save();
|
await obj.save();
|
||||||
const results = await new Parse.Query(TestObject).find();
|
const result = await new Parse.Query(TestObject).get(obj.id);
|
||||||
equal(results.length, 1);
|
const pointAgain = result.get('location');
|
||||||
const pointAgain = results[0].get('location');
|
|
||||||
ok(pointAgain);
|
ok(pointAgain);
|
||||||
equal(pointAgain.latitude, 44.0);
|
equal(pointAgain.latitude, 44.0);
|
||||||
equal(pointAgain.longitude, -11.0);
|
equal(pointAgain.longitude, -11.0);
|
||||||
@@ -727,4 +726,49 @@ describe('Parse.GeoPoint testing', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('withinKilometers supports count', async () => {
|
||||||
|
const inside = new Parse.GeoPoint(10, 10);
|
||||||
|
const outside = new Parse.GeoPoint(20, 20);
|
||||||
|
|
||||||
|
const obj1 = new Parse.Object('TestObject', { location: inside });
|
||||||
|
const obj2 = new Parse.Object('TestObject', { location: outside });
|
||||||
|
|
||||||
|
await Parse.Object.saveAll([obj1, obj2]);
|
||||||
|
|
||||||
|
const q = new Parse.Query(TestObject).withinKilometers(
|
||||||
|
'location',
|
||||||
|
inside,
|
||||||
|
5
|
||||||
|
);
|
||||||
|
const count = await q.count();
|
||||||
|
|
||||||
|
equal(count, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('withinKilometers complex supports count', async () => {
|
||||||
|
const inside = new Parse.GeoPoint(10, 10);
|
||||||
|
const middle = new Parse.GeoPoint(20, 20);
|
||||||
|
const outside = new Parse.GeoPoint(30, 30);
|
||||||
|
const obj1 = new Parse.Object('TestObject', { location: inside });
|
||||||
|
const obj2 = new Parse.Object('TestObject', { location: middle });
|
||||||
|
const obj3 = new Parse.Object('TestObject', { location: outside });
|
||||||
|
|
||||||
|
await Parse.Object.saveAll([obj1, obj2, obj3]);
|
||||||
|
|
||||||
|
const q1 = new Parse.Query(TestObject).withinKilometers(
|
||||||
|
'location',
|
||||||
|
inside,
|
||||||
|
5
|
||||||
|
);
|
||||||
|
const q2 = new Parse.Query(TestObject).withinKilometers(
|
||||||
|
'location',
|
||||||
|
middle,
|
||||||
|
5
|
||||||
|
);
|
||||||
|
const query = Parse.Query.or(q1, q2);
|
||||||
|
const count = await query.count();
|
||||||
|
|
||||||
|
equal(count, 2);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -690,7 +690,7 @@ export class MongoStorageAdapter implements StorageAdapter {
|
|||||||
readPreference = this._parseReadPreference(readPreference);
|
readPreference = this._parseReadPreference(readPreference);
|
||||||
return this._adaptiveCollection(className)
|
return this._adaptiveCollection(className)
|
||||||
.then(collection =>
|
.then(collection =>
|
||||||
collection.count(transformWhere(className, query, schema), {
|
collection.count(transformWhere(className, query, schema, true), {
|
||||||
maxTimeMS: this._maxTimeMS,
|
maxTimeMS: this._maxTimeMS,
|
||||||
readPreference,
|
readPreference,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ const valueAsDate = value => {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
function transformQueryKeyValue(className, key, value, schema) {
|
function transformQueryKeyValue(className, key, value, schema, count = false) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case 'createdAt':
|
case 'createdAt':
|
||||||
if (valueAsDate(value)) {
|
if (valueAsDate(value)) {
|
||||||
@@ -293,7 +293,7 @@ function transformQueryKeyValue(className, key, value, schema) {
|
|||||||
return {
|
return {
|
||||||
key: key,
|
key: key,
|
||||||
value: value.map(subQuery =>
|
value: value.map(subQuery =>
|
||||||
transformWhere(className, subQuery, schema)
|
transformWhere(className, subQuery, schema, count)
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
case 'lastUsed':
|
case 'lastUsed':
|
||||||
@@ -330,7 +330,7 @@ function transformQueryKeyValue(className, key, value, schema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle query constraints
|
// Handle query constraints
|
||||||
const transformedConstraint = transformConstraint(value, field);
|
const transformedConstraint = transformConstraint(value, field, count);
|
||||||
if (transformedConstraint !== CannotTransform) {
|
if (transformedConstraint !== CannotTransform) {
|
||||||
if (transformedConstraint.$text) {
|
if (transformedConstraint.$text) {
|
||||||
return { key: '$text', value: transformedConstraint.$text };
|
return { key: '$text', value: transformedConstraint.$text };
|
||||||
@@ -359,14 +359,15 @@ function transformQueryKeyValue(className, key, value, schema) {
|
|||||||
// Main exposed method to help run queries.
|
// Main exposed method to help run queries.
|
||||||
// restWhere is the "where" clause in REST API form.
|
// restWhere is the "where" clause in REST API form.
|
||||||
// Returns the mongo form of the query.
|
// Returns the mongo form of the query.
|
||||||
function transformWhere(className, restWhere, schema) {
|
function transformWhere(className, restWhere, schema, count = false) {
|
||||||
const mongoWhere = {};
|
const mongoWhere = {};
|
||||||
for (const restKey in restWhere) {
|
for (const restKey in restWhere) {
|
||||||
const out = transformQueryKeyValue(
|
const out = transformQueryKeyValue(
|
||||||
className,
|
className,
|
||||||
restKey,
|
restKey,
|
||||||
restWhere[restKey],
|
restWhere[restKey],
|
||||||
schema
|
schema,
|
||||||
|
count
|
||||||
);
|
);
|
||||||
mongoWhere[out.key] = out.value;
|
mongoWhere[out.key] = out.value;
|
||||||
}
|
}
|
||||||
@@ -816,7 +817,7 @@ function relativeTimeToDate(text, now = new Date()) {
|
|||||||
// If it is not a valid constraint but it could be a valid something
|
// If it is not a valid constraint but it could be a valid something
|
||||||
// else, return CannotTransform.
|
// else, return CannotTransform.
|
||||||
// inArray is whether this is an array field.
|
// inArray is whether this is an array field.
|
||||||
function transformConstraint(constraint, field) {
|
function transformConstraint(constraint, field, count = false) {
|
||||||
const inArray = field && field.type && field.type === 'Array';
|
const inArray = field && field.type && field.type === 'Array';
|
||||||
if (typeof constraint !== 'object' || !constraint) {
|
if (typeof constraint !== 'object' || !constraint) {
|
||||||
return CannotTransform;
|
return CannotTransform;
|
||||||
@@ -1002,15 +1003,27 @@ function transformConstraint(constraint, field) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case '$nearSphere':
|
case '$nearSphere': {
|
||||||
var point = constraint[key];
|
const point = constraint[key];
|
||||||
answer[key] = [point.longitude, point.latitude];
|
if (count) {
|
||||||
|
answer.$geoWithin = {
|
||||||
|
$centerSphere: [
|
||||||
|
[point.longitude, point.latitude],
|
||||||
|
constraint.$maxDistance,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
answer[key] = [point.longitude, point.latitude];
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case '$maxDistance':
|
case '$maxDistance': {
|
||||||
|
if (count) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
answer[key] = constraint[key];
|
answer[key] = constraint[key];
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
// The SDKs don't seem to use these but they are documented in the
|
// The SDKs don't seem to use these but they are documented in the
|
||||||
// REST API docs.
|
// REST API docs.
|
||||||
case '$maxDistanceInRadians':
|
case '$maxDistanceInRadians':
|
||||||
|
|||||||
Reference in New Issue
Block a user