diff --git a/spec/ParseGeoPoint.spec.js b/spec/ParseGeoPoint.spec.js index f2f8201e98..36e559eab5 100644 --- a/spec/ParseGeoPoint.spec.js +++ b/spec/ParseGeoPoint.spec.js @@ -628,4 +628,139 @@ describe('Parse.GeoPoint testing', () => { done(); }); }); + + it('works with $centerSphere queries where centerPoint is Array', (done) => { + const CenterSphereTestObject = Parse.Object.extend('CenterSphereTestObject'); + var odense = new CenterSphereTestObject(); + odense.set('location', new Parse.GeoPoint(55.398167, 10.386916)); + odense.set('name', 'Odense'); + + var slagelse = new CenterSphereTestObject(); + slagelse.set('location', new Parse.GeoPoint(55.401286, 11.364699)); + slagelse.set('name', 'Slagelse'); + + var copenhagen = new CenterSphereTestObject(); + copenhagen.set('location', new Parse.GeoPoint(55.674820, 12.589675)); + copenhagen.set('name', 'Copenhagen'); + + Parse.Object.saveAll([odense, slagelse, copenhagen]).then(() => { + // const center = new Parse.GeoPoint(55.461373, 11.891823); + const center = [55.461373, 11.891823]; + const radius = 60 / 6371.0 // 60 km in radians + const where = { + location: { + $geoWithin: { + $centerSphere: [ + center, + radius + ] + } + } + }; + + return rp.get({ + uri: Parse.serverURL + '/classes/CenterSphereTestObject', + json: { + where + }, + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-Javascript-Key': Parse.javaScriptKey + } + }); + }).then(resp => { + const names = ['Slagelse', 'Copenhagen']; + equal(resp.results.length, 2); + expect(names).toContain(resp.results[0].name); + expect(names).toContain(resp.results[1].name); + done(); + }); + }); + + it('works with $centerSphere queries where centerPoint is Parse.GeoPoint', (done) => { + const CenterSphereTestObject = Parse.Object.extend('CenterSphereTestObject'); + var odense = new CenterSphereTestObject(); + odense.set('location', new Parse.GeoPoint(55.398167, 10.386916)); + odense.set('name', 'Odense'); + + var slagelse = new CenterSphereTestObject(); + slagelse.set('location', new Parse.GeoPoint(55.401286, 11.364699)); + slagelse.set('name', 'Slagelse'); + + var copenhagen = new CenterSphereTestObject(); + copenhagen.set('location', new Parse.GeoPoint(55.674820, 12.589675)); + copenhagen.set('name', 'Copenhagen'); + + Parse.Object.saveAll([odense, slagelse, copenhagen]).then(() => { + const center = new Parse.GeoPoint(55.461373, 11.891823); + const radius = 60 / 6371.0 // 60 km in radians + const where = { + location: { + $geoWithin: { + $centerSphere: [ + center, + radius + ] + } + } + }; + + return rp.get({ + uri: Parse.serverURL + '/classes/CenterSphereTestObject', + json: { + where + }, + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-Javascript-Key': Parse.javaScriptKey + } + }); + }).then(resp => { + const names = ['Slagelse', 'Copenhagen']; + equal(resp.results.length, 2); + expect(names).toContain(resp.results[0].name); + expect(names).toContain(resp.results[1].name); + done(); + }); + }); + + it('should respond with error with invalid centerPoint in $centerSphere query', (done) => { + // const center = 'john'; + const CenterSphereTestObject = Parse.Object.extend('CenterSphereTestObject'); + var odense = new CenterSphereTestObject(); + odense.set('location', new Parse.GeoPoint(55.398167, 10.386916)); + odense.set('name', 'Odense'); + + odense.save().then(() => { + const centerPoint = 'foo'; + const radius = 60 / 6371.0 // 60 km in radians + const where = { + location: { + $geoWithin: { + $centerSphere: [ + centerPoint, + radius + ] + } + } + }; + + return rp.get({ + uri: Parse.serverURL + '/classes/CenterSphereTestObject', + json: { + where + }, + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-Javascript-Key': Parse.javaScriptKey + } + }) + }).then((resp) => { + fail(`no request should succeed: ${JSON.stringify(resp)}`); + done(); + }).catch((err) => { + expect(err.error.code).toEqual(107); + done(); + }); + }); }); diff --git a/src/Adapters/Storage/Mongo/MongoTransform.js b/src/Adapters/Storage/Mongo/MongoTransform.js index f46c310e23..26b47b253c 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -669,30 +669,62 @@ function transformConstraint(constraint, inArray) { break; case '$geoWithin': { - const polygon = constraint[key]['$polygon']; - if (!(polygon instanceof Array)) { - throw new Parse.Error( - Parse.Error.INVALID_JSON, - 'bad $geoWithin value; $polygon should contain at least 3 GeoPoints' - ); - } - if (polygon.length < 3) { - throw new Parse.Error( - Parse.Error.INVALID_JSON, - 'bad $geoWithin value; $polygon should contain at least 3 GeoPoints' - ); + const query = Object.keys(constraint[key])[0]; + const shape = constraint[key][query]; + switch(query) { + case '$polygon': { + if (!(shape instanceof Array)) { + throw new Parse.Error( + Parse.Error.INVALID_JSON, + 'bad $geoWithin value; $polygon should contain at least 3 GeoPoints' + ); + } + if (shape.length < 3) { + throw new Parse.Error( + Parse.Error.INVALID_JSON, + 'bad $geoWithin value; $polygon should contain at least 3 GeoPoints' + ); + } + const points = shape.map((point) => { + if (!GeoPointCoder.isValidJSON(point)) { + throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad $geoWithin value'); + } else { + Parse.GeoPoint._validate(point.latitude, point.longitude); + } + return [point.longitude, point.latitude]; + }); + answer[key] = { + '$polygon': points + }; + break; } - const points = polygon.map((point) => { - if (!GeoPointCoder.isValidJSON(point)) { - throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad $geoWithin value'); + + case '$centerSphere': { + if (!(shape instanceof Array) || shape.length != 2) { + throw new Parse.Error( + Parse.Error.INVALID_JSON, + 'bad $geoWithin value; $centerSphere malformatted' + ); + } + let centerPoint = shape[0] + const radius = shape[1] + if (centerPoint instanceof Array && centerPoint.length == 2) { + centerPoint = new Parse.GeoPoint(centerPoint[0], centerPoint[1]).toJSON(); + } + if (!GeoPointCoder.isValidJSON(centerPoint)) { + throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad $geoWithin value; centerPoint malformatted'); } else { - Parse.GeoPoint._validate(point.latitude, point.longitude); + Parse.GeoPoint._validate(centerPoint.latitude, centerPoint.longitude) } - return [point.longitude, point.latitude]; - }); - answer[key] = { - '$polygon': points - }; + answer[key] = { + '$centerSphere': [ + [centerPoint.longitude, centerPoint.latitude], + radius + ] + }; + break; + } + } break; } case '$geoIntersects': { diff --git a/src/vendor/mongodbUrl.js b/src/vendor/mongodbUrl.js index 1616c3dfc0..4e3689f0c3 100644 --- a/src/vendor/mongodbUrl.js +++ b/src/vendor/mongodbUrl.js @@ -255,8 +255,8 @@ Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) { hostEnd = i; break; case 64: // '@' - // At this point, either we have an explicit point where the - // auth portion cannot go past, or the last @ char is the decider. + // At this point, either we have an explicit point where the + // auth portion cannot go past, or the last @ char is the decider. atSign = i; nonHost = -1; break;