Repository: parse-community/Parse-SDK-JS
Pull request #1570 (2022-10-08 19:46:53)

feat: localDatastore support for unsorted distance queries
### New Pull Request Checklist
<!--
    Check every following box [x] before submitting your PR.
    Click the "Preview" tab for better readability.
    Thanks for contributing to Parse Platform!
-->

- [x] I am not disclosing a [vulnerability](https://github.com/parse-community/parse-server/blob/master/SECURITY.md).
- [x] I am creating this PR in reference to an [issue](https://github.com/parse-community/Parse-SDK-JS/issues?q=is%3Aissue).

### Issue Description
<!-- Add a brief description of the issue this PR solves. -->

Related issue: https://github.com/parse-community/Parse-SDK-JS/issues/1571

### Approach
<!-- Add a description of the approach in this PR. -->

### TODOs before merging
<!--
    Add TODOs that need to be completed before merging this PR.
    Delete TODOs that do not apply to this PR.
-->

- [x] Add tests

parse-github-assistant[bot]: 
### Thanks for opening this pull request!

- ❌ Please fill out all fields with a placeholder `FILL_THIS_OUT`, otherwise your pull request will be closed. If a field does not apply to the pull request, fill in `n/a`.

<!-- parse-issue-bot-meta-tag-id {"requireDetailFields":true} -->


codecov[bot]: # [Codecov](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/1570?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community) Report
Base: **99.94**% // Head: **99.94**% // Increases project coverage by **`+0.00%`** :tada:
> Coverage data is based on head [(`cd06af0`)](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/1570?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community) compared to base [(`4864d54`)](https://codecov.io/gh/parse-community/Parse-SDK-JS/commit/4864d54e342e379d2d17a07f935966be7e19fa1b?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community).
> Patch coverage: 100.00% of modified lines in pull request are covered.

<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##            alpha    #1570   +/-   ##
=======================================
  Coverage   99.94%   99.94%           
=======================================
  Files          61       61           
  Lines        5955     5961    +6     
  Branches     1360     1361    +1     
=======================================
+ Hits         5952     5958    +6     
  Misses          3        3           
```


| [Impacted Files](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/1570?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community) | Coverage Δ | |
|---|---|---|
| [src/OfflineQuery.js](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/1570/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community#diff-c3JjL09mZmxpbmVRdWVyeS5qcw==) | `100.00% <100.00%> (ø)` | |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/parse-community/Parse-SDK-JS/pull/1570?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=parse-community).

mtrezza: @dplewis If click on "Details" for the failing "Commit Message" test, you'll see that we don't currently use a scope in the commit message.
parse-github-assistant[bot]: I will reformat the title to use the proper commit message syntax.

Patch:
diff --git a/src/OfflineQuery.js b/src/OfflineQuery.js
index 46167a5..f76cfa0 100644
--- a/src/OfflineQuery.js
+++ b/src/OfflineQuery.js
@@ -513,9 +513,25 @@ function matchesKeyConstraints(className, object, objects, key, constraints) {
       return true;
     }
     case '$geoWithin': {
-      const points = compareTo.$polygon.map(geoPoint => [geoPoint.latitude, geoPoint.longitude]);
-      const polygon = new ParsePolygon(points);
-      return polygon.containsPoint(object[key]);
+      if (compareTo.$polygon) {
+        const points = compareTo.$polygon.map(geoPoint => [
+          geoPoint.latitude,
+          geoPoint.longitude,
+        ]);
+        const polygon = new ParsePolygon(points);
+        return polygon.containsPoint(object[key]);
+      }
+      if (compareTo.$centerSphere) {
+        const [WGS84Point, maxDistance] = compareTo.$centerSphere;
+        const centerPoint = new ParseGeoPoint({
+          latitude: WGS84Point[1],
+          longitude: WGS84Point[0],
+        });
+        const point = new ParseGeoPoint(object[key]);
+        const distance = point.radiansTo(centerPoint);
+        return distance <= maxDistance;
+      }
+      break;
     }
     case '$geoIntersects': {
       const polygon = new ParsePolygon(object[key].coordinates);


Test patch:
diff --git a/integration/test/ParseLocalDatastoreTest.js b/integration/test/ParseLocalDatastoreTest.js
index c532ca0..19d2245 100644
--- a/integration/test/ParseLocalDatastoreTest.js
+++ b/integration/test/ParseLocalDatastoreTest.js
@@ -2735,6 +2735,26 @@ function runTest(controller) {
       assert.equal(objects.length, 1);
     });
 
+    it(`${controller.name} supports withinKilometers`, async () => {
+      const object = new TestObject();
+      const firstPoint = new Parse.GeoPoint({ latitude: 40.0, longitude: -30.0 });
+      object.set({ location: firstPoint });
+      await object.save();
+      await object.pin();
+
+      const sorted = false;
+      const query = new Parse.Query(TestObject);
+      query.withinKilometers(
+        'location',
+        new Parse.GeoPoint({ latitude: 40.0, longitude: -30.0 }),
+        2,
+        sorted
+      );
+      query.fromLocalDatastore();
+      const results = await query.find();
+      assert.equal(results.length, 1);
+    });
+
     it(`${controller.name} supports withinPolygon`, async () => {
       const sacramento = new TestObject();
       sacramento.set('location', new Parse.GeoPoint(38.52, -121.5));
diff --git a/src/__tests__/OfflineQuery-test.js b/src/__tests__/OfflineQuery-test.js
index 76e4320..ae67a84 100644
--- a/src/__tests__/OfflineQuery-test.js
+++ b/src/__tests__/OfflineQuery-test.js
@@ -471,6 +471,15 @@ describe('OfflineQuery', () => {
     expect(matchesQuery(q.className, pt, [], q)).toBe(true);
   });
 
+  it('matches $centerSphere queries', () => {
+    const pt = new ParseObject('Checkin');
+    pt.set('location', new ParseGeoPoint(40, 40));
+
+    const q = new ParseQuery('Checkin');
+    q.withinRadians('location', new ParseGeoPoint(30, 30), 0.3, false);
+    expect(matchesQuery(q.className, pt, [], q)).toBe(true);
+  });
+
   it('matches $within queries', () => {
     const caltrainStation = new ParseObject('Checkin');
     caltrainStation