diff --git a/spec/MongoTransform.spec.js b/spec/MongoTransform.spec.js index ce48fb528e..5489d95223 100644 --- a/spec/MongoTransform.spec.js +++ b/spec/MongoTransform.spec.js @@ -63,12 +63,29 @@ describe('parseObjectToMongoObjectForCreate', () => { done(); }); - it('plain', (done) => { - const geoPoint = {__type: 'GeoPoint', longitude: 180, latitude: -180}; + it('parse geopoint to mongo', (done) => { + const lat = -45; + const lng = 45; + const geoPoint = {__type: 'GeoPoint', latitude: lat, longitude: lng}; const out = transform.parseObjectToMongoObjectForCreate(null, {location: geoPoint},{ fields: {location: {type: 'GeoPoint'}} }); - expect(out.location).toEqual([180, -180]); + expect(out.location).toEqual([lng, lat]); + done(); + }); + + it('parse polygon to mongo', (done) => { + const lat1 = -45; + const lng1 = 45; + const lat2 = -55; + const lng2 = 55; + const lat3 = -65; + const lng3 = 65; + const polygon = {__type: 'Polygon', coordinates: [[lat1, lng1],[lat2, lng2],[lat3, lng3]]} + const out = transform.parseObjectToMongoObjectForCreate(null, {location: polygon},{ + fields: {location: {type: 'Polygon'}} + }); + expect(out.location.coordinates).toEqual([[[lng1, lat1],[lng2, lat2],[lng3, lat3],[lng1, lat1]]]); done(); }); @@ -144,26 +161,31 @@ describe('parseObjectToMongoObjectForCreate', () => { done(); }); - it('geopoint', (done) => { - const input = {location: [45, -45]}; + it('mongo geopoint to parse', (done) => { + const lat = -45; + const lng = 45; + const input = {location: [lng, lat]}; const output = transform.mongoObjectToParseObject(null, input, { fields: { location: { type: 'GeoPoint' }}, }); expect(typeof output.location).toEqual('object'); expect(output.location).toEqual( - {__type: 'GeoPoint', longitude: 45, latitude: -45} + {__type: 'GeoPoint', latitude: lat, longitude: lng} ); done(); }); - it('polygon', (done) => { - const input = {location: { type: 'Polygon', coordinates: [[[45, -45],[45, -45]]]}}; + it('mongo polygon to parse', (done) => { + const lat = -45; + const lng = 45; + // Mongo stores polygon in WGS84 lng/lat + const input = {location: { type: 'Polygon', coordinates: [[[lat, lng],[lat, lng]]]}}; const output = transform.mongoObjectToParseObject(null, input, { fields: { location: { type: 'Polygon' }}, }); expect(typeof output.location).toEqual('object'); expect(output.location).toEqual( - {__type: 'Polygon', coordinates: [[45, -45],[45, -45]]} + {__type: 'Polygon', coordinates: [[lng, lat],[lng, lat]]} ); done(); }); diff --git a/spec/ParsePolygon.spec.js b/spec/ParsePolygon.spec.js index 19091ce7cd..25d4edffa3 100644 --- a/spec/ParsePolygon.spec.js +++ b/spec/ParsePolygon.spec.js @@ -160,6 +160,64 @@ describe('Parse.Polygon testing', () => { }, done.fail); }); + it('polygonContain query no reverse input (Regression test for #4608)', (done) => { + const points1 = [[.25,0],[.25,1.25],[.75,1.25],[.75,0]]; + const points2 = [[0,0],[0,2],[2,2],[2,0]]; + const points3 = [[10,10],[10,15],[15,15],[15,10],[10,10]]; + const polygon1 = new Parse.Polygon(points1); + const polygon2 = new Parse.Polygon(points2); + const polygon3 = new Parse.Polygon(points3); + const obj1 = new TestObject({location: polygon1}); + const obj2 = new TestObject({location: polygon2}); + const obj3 = new TestObject({location: polygon3}); + Parse.Object.saveAll([obj1, obj2, obj3]).then(() => { + const where = { + location: { + $geoIntersects: { + $point: { __type: 'GeoPoint', latitude: 0.5, longitude:1.0 } + } + } + }; + return rp.post({ + url: Parse.serverURL + '/classes/TestObject', + json: { where, '_method': 'GET' }, + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-Javascript-Key': Parse.javaScriptKey + } + }); + }).then((resp) => { + expect(resp.results.length).toBe(2); + done(); + }, done.fail); + }); + + it('polygonContain query real data (Regression test for #4608)', (done) => { + const detroit = [[42.631655189280224,-83.78406753121705],[42.633047793854814,-83.75333640366955],[42.61625254348911,-83.75149921669944],[42.61526926650296,-83.78161794858735],[42.631655189280224,-83.78406753121705]]; + const polygon = new Parse.Polygon(detroit); + const obj = new TestObject({location: polygon}); + obj.save().then(() => { + const where = { + location: { + $geoIntersects: { + $point: { __type: 'GeoPoint', latitude: 42.624599, longitude:-83.770162 } + } + } + }; + return rp.post({ + url: Parse.serverURL + '/classes/TestObject', + json: { where, '_method': 'GET' }, + headers: { + 'X-Parse-Application-Id': Parse.applicationId, + 'X-Parse-Javascript-Key': Parse.javaScriptKey + } + }); + }).then((resp) => { + expect(resp.results.length).toBe(1); + done(); + }, done.fail); + }); + it('polygonContain invalid input', (done) => { const points = [[0,0],[0,1],[1,1],[1,0]]; const polygon = new Parse.Polygon(points); @@ -255,6 +313,24 @@ describe_only_db('mongo')('Parse.Polygon testing', () => { }, done.fail); }); + it('polygon coordinates reverse input', (done) => { + const Config = require('../src/Config'); + const config = Config.get('test'); + + // When stored the first point should be the last point + const input = [[12,11],[14,13],[16,15],[18,17]]; + const output = [[[11,12],[13,14],[15,16],[17,18],[11,12]]]; + const obj = new TestObject(); + obj.set('polygon', new Parse.Polygon(input)); + obj.save().then(() => { + return config.database.adapter._rawFind('TestObject', {_id: obj.id}); + }).then((results) => { + expect(results.length).toBe(1); + expect(results[0].polygon.coordinates).toEqual(output); + done(); + }); + }); + it('polygon loop is not valid', (done) => { const coords = [[0,0],[0,1],[1,0],[1,1]]; const obj = new TestObject(); diff --git a/src/Adapters/Storage/Mongo/MongoTransform.js b/src/Adapters/Storage/Mongo/MongoTransform.js index 1e98eb1057..a5cbe1f195 100644 --- a/src/Adapters/Storage/Mongo/MongoTransform.js +++ b/src/Adapters/Storage/Mongo/MongoTransform.js @@ -1261,9 +1261,13 @@ var GeoPointCoder = { var PolygonCoder = { databaseToJSON(object) { + // Convert lng/lat -> lat/lng + const coords = object.coordinates[0].map((coord) => { + return [coord[1], coord[0]]; + }); return { __type: 'Polygon', - coordinates: object['coordinates'][0] + coordinates: coords } }, @@ -1283,7 +1287,8 @@ var PolygonCoder = { }, JSONToDatabase(json) { - const coords = json.coordinates; + let coords = json.coordinates; + // Add first point to the end to close polygon if (coords[0][0] !== coords[coords.length - 1][0] || coords[0][1] !== coords[coords.length - 1][1]) { coords.push(coords[0]); @@ -1306,6 +1311,10 @@ var PolygonCoder = { 'GeoJSON: Loop must have at least 3 different vertices' ); } + // Convert lat/long -> long/lat + coords = coords.map((coord) => { + return [coord[1], coord[0]]; + }); return { type: 'Polygon', coordinates: [coords] }; },