Skip to content

Fix GeoPoint issues on PostgreSQL (#3285 & #3659) #3660

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed

Fix GeoPoint issues on PostgreSQL (#3285 & #3659) #3660

wants to merge 5 commits into from

Conversation

vferdiansyah
Copy link

This is a small fix to the GeoPoint issues that I experienced on #3285 and #3659

@natanrolnik
Copy link
Contributor

@vitaly-t @kulshekhar and @cherukumilli - would you guys mind reviewing this PR?

Copy link
Contributor

@kulshekhar kulshekhar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apart from the comment, I think this needs a closer look by someone who uses GeoPoint (I don't) as the tests are failing. My suspicion is that the second set of change might not be necessary - this is just a guess though.

patterns.push(`ST_distance_sphere($${index}:name::geometry, POINT($${index + 1}, $${index + 2})::geometry) <= $${index + 3}`);
sorts.push(`ST_distance_sphere($${index}:name::geometry, POINT($${index + 1}, $${index + 2})::geometry) ASC`)
patterns.push(`ST_distance_sphere($${index}:name::geometry, POINT($${index + 2}, $${index + 1})::geometry) <= $${index + 3}`);
sorts.push(`ST_distance_sphere($${index}:name::geometry, POINT($${index + 2}, $${index + 1})::geometry) ASC`)
values.push(fieldName, point.longitude, point.latitude, distanceInKM);
index += 4;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks fine.
Although I think it might be more readable to change the order of latitude/longitude when pushing them in values.

So, leaving lines 328/329 as they originally were and replacing values.push(fieldName, point.longitude, point.latitude, distanceInKM); with values.push(fieldName, point.latitude, point.longitude, distanceInKM); on line 330

Copy link
Contributor

@vitaly-t vitaly-t Mar 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whenever in doubt about what pg-promise outputs, you can always run it through pgp.as.format(query, values) locally, throw the result into the console and see what's there ;)

Copy link
Contributor

@vitaly-t vitaly-t Mar 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may have incomplete understanding in what that ST_distance_sphere does, but just to make sure, the :name formatting results in the value being wrapped into double quotes, as in ST_distance_sphere("value", , as per the SQL Names formatting.

Are you guys sure this is what the function actually expects? 'Cos I'm not sure...

It looks very suspecious. Looks to me from the API documentation that it should be a string. Or am I wrong there?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Original tests were passing, so I'd trust it. But I may be wrong

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solution suggested by @kulshekhar also works actually. Just tried it on my local machine.

screen shot 2017-03-24 at 16 37 51
Not sure if this is what you meant @vitaly-t but as far as I can see, the results aren't wrapped in double quotes at all.

Yes, original tests were passing @flovilmart and it works fine so far on my app.

Copy link
Contributor

@vitaly-t vitaly-t Mar 25, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The best way to see what is really going on in terms of the queries being executed, is with pg-monitor. You can diagnose issues much quicker than.

For that just update PosgresClient.js like this:

  1. Add var monitor = require('pg-monitor');
  2. Call monitor.attach(dbOptions); to attach to the pg options object
  3. Optional, for best look: monitor.setTheme('matrix');

And of course install it first npm install pg-monitor --save

Then you will be able to see every query the module executes 😉

@flovilmart
Copy link
Contributor

flovilmart commented Mar 25, 2017

@vferdiansyah what is very odd in your case, is that the test suite that covers what you describe fails with your changes. The same test suite is used against mongodb.

Can you design a single test that would fail on PG currently and that shows what part is failing?

Particularly have a look at that test suite

Which specifically test the different use cases you describe here and here.

To run the tests on your machine, I encourage you to use:

PARSE_SERVER_TEST_DB=postgres npm test spec/ParseGeoPoint.spec.js 

With a local PG database running.

@facebook-github-bot
Copy link

@vferdiansyah updated the pull request - view changes

@vferdiansyah
Copy link
Author

Committed new fix that passed all tests on my local machine.

@flovilmart
Copy link
Contributor

Tests seems to be passing ;)

@vferdiansyah
Copy link
Author

Yep. Hopefully this is gonna be released soon.

@kulshekhar
Copy link
Contributor

kulshekhar commented Mar 28, 2017

The tests were passing even before this PR but the query wasn't behaving in the expected manner.

@vferdiansyah would it be possible to add a test (similar to the existing ones) that would fail with the existing code but pass with this PR? I suspect it might be as simple as copying the existing test and plugging in the values that didn't work for you.

This would ensure that any future changes to this part of the code won't inadvertently break what your PR fixes!

@vferdiansyah
Copy link
Author

vferdiansyah commented Mar 28, 2017

So I've tried making a new test case which I think is gonna fail, that is returning nearest location since that is the one that breaks on my app. The test looks like this:

it('returns nearest location', (done) => {
    makeSomeGeoPoints(function() {
      var sfo = new Parse.GeoPoint(37.6189722, -122.3748889);
      var query = new Parse.Query(TestObject);
      query.near('location', sfo);
      query.find({
        success: function(results) {
          equal(results[0].get('name'), 'San Francisco');
          equal(results[1].get('name'), 'Sacramento');
          done();
        }
      });
    });
  });

BUT, the test still PASSED on both the current version and the one with my PR.

HOWEVER, when I tried it in my app, both returns a very different results. I'm querying a place nearby a location with coordinates (35.0056643, 135.7745649).

  • Current version:
    current
  • With PR:
    pr

As you can see in the picture above, the latitude returned by the current version is wrong. Latitude should be ranged from -90 to +90. And I have checked my database and can confirm that the latitude value is actually a longitude and vice versa.

And with the current PR, it returns the desired value.

The thing that I don't understand is, according to the test, it returns the desired results. So how can it breaks? Or maybe I miss something with my test case above?

@vferdiansyah
Copy link
Author

Any inputs on this @flovilmart @vitaly-t?

@flovilmart
Copy link
Contributor

Yeah, that's a bummer, I dont recall why I reversed latitudes and longitude in the point, but because this is against the 'natural' order, there's probably a good reason. Otherwise, it's good, as it reversing the points twice, but may break when updating the server.

@codecov
Copy link

codecov bot commented Apr 7, 2017

Codecov Report

Merging #3660 into master will increase coverage by 0.29%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #3660      +/-   ##
==========================================
+ Coverage   90.16%   90.45%   +0.29%     
==========================================
  Files         114      114              
  Lines        7532     7406     -126     
==========================================
- Hits         6791     6699      -92     
+ Misses        741      707      -34
Impacted Files Coverage Δ
...dapters/Storage/Postgres/PostgresStorageAdapter.js 95.58% <100%> (+0.26%) ⬆️
src/password.js 87.5% <0%> (-12.5%) ⬇️
src/Adapters/Cache/InMemoryCache.js 92.3% <0%> (-7.7%) ⬇️
src/AccountLockout.js 91.8% <0%> (-5.82%) ⬇️
src/Routers/UsersRouter.js 87.02% <0%> (-1.87%) ⬇️
src/Controllers/LoggerController.js 88.05% <0%> (-0.83%) ⬇️
src/Push/PushQueue.js 96% <0%> (-0.56%) ⬇️
src/triggers.js 87.63% <0%> (-0.14%) ⬇️
src/StatusHandler.js 98.97% <0%> (-0.08%) ⬇️
src/Controllers/DatabaseController.js 94.3% <0%> (-0.06%) ⬇️
... and 22 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 17a2d26...f18cc3c. Read the comment docs.

@flovilmart
Copy link
Contributor

@vferdiansyah Can you add a test that shows the fix is effective? From what I can see, we flipped the order of the coordinates inside the storage but all tests are still good.

@flovilmart
Copy link
Contributor

@vferdiansyah I just ran the test locally alone, on the top of the master branch and it doesn'T seem to validate the error (it should fail)

@vferdiansyah
Copy link
Author

I just ran the test locally alone, on the top of the master branch and it doesn'T seem to validate the error (it should fail)

That's why I wrote this in my previous comment:

BUT, the test still PASSED on both the current version and the one with my PR.

It fails on my app but it passed all tests. So something must be wrong down the road but I still can't find where.

If you see the screenshots of the response on my previous comment, you'll know that it's a bug.

@flovilmart
Copy link
Contributor

That's what bugs me, it seems that we don't really understand where it fails and why.

@vferdiansyah
Copy link
Author

@flovilmart I've tried several things today (like exchanging latitude to longitude, etc), but this is the only one that works :/

@flovilmart
Copy link
Contributor

I can understand your frustration, however, this bug seems to be critical, and without a proper test that makes an example out of it, I'm not really sure what to think.

@vferdiansyah
Copy link
Author

Yeah I know. Do you still can't recall why did you reverse the order when you first created this adapter?

@flovilmart
Copy link
Contributor

Because latitude / longitude translate to y/x more than x/y

@flovilmart
Copy link
Contributor

We can't find the actual underlying by creating proper reproduction in the tests.

@dplewis
Copy link
Member

dplewis commented May 28, 2017

Hi.

I've encountered the reversing issue. Since Postgres uses WGS84 Longitude goes first.

If you want fix the reversing it happened on this line. updateObjectByQuery.

https://github.com/parse-community/parse-server/blob/master/src/Adapters/Storage/Postgres/PostgresStorageAdapter.js#L925

Old

values.push(fieldName, fieldValue.latitude, fieldValue.longitude);

It should be written like.

values.push(fieldName, fieldValue.longitude, fieldValue.latitude);

I can do a PR and test for this

@flovilmart
Copy link
Contributor

That would be good! Thanks!

@flovilmart
Copy link
Contributor

Closing as supersed by #3874

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants