Skip to content

Commit e44e33e

Browse files
madsbflovilmart
authored andcommitted
Adds withinPolygon support for Polygon object (parse-community#4067)
* Whitespace * Add Polygon type to $polygon query * Add tests Polygon object in $polygon query $geoIntersects queries * Refactor * Postgres support * More tests * Remove duplicate test * Missing semicolon * fix tests
1 parent 7660e82 commit e44e33e

File tree

3 files changed

+158
-18
lines changed

3 files changed

+158
-18
lines changed

spec/ParseGeoPoint.spec.js

+110
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,116 @@ describe('Parse.GeoPoint testing', () => {
496496
}, done.fail);
497497
});
498498

499+
it('supports withinPolygon Polygon object', (done) => {
500+
const inbound = new Parse.GeoPoint(1.5, 1.5);
501+
const onbound = new Parse.GeoPoint(10, 10);
502+
const outbound = new Parse.GeoPoint(20, 20);
503+
const obj1 = new Parse.Object('Polygon', {location: inbound});
504+
const obj2 = new Parse.Object('Polygon', {location: onbound});
505+
const obj3 = new Parse.Object('Polygon', {location: outbound});
506+
const polygon = {
507+
__type: 'Polygon',
508+
coordinates: [
509+
[0, 0],
510+
[10, 0],
511+
[10, 10],
512+
[0, 10],
513+
[0, 0]
514+
]
515+
}
516+
Parse.Object.saveAll([obj1, obj2, obj3]).then(() => {
517+
const where = {
518+
location: {
519+
$geoWithin: {
520+
$polygon: polygon
521+
}
522+
}
523+
};
524+
return rp.post({
525+
url: Parse.serverURL + '/classes/Polygon',
526+
json: { where, '_method': 'GET' },
527+
headers: {
528+
'X-Parse-Application-Id': Parse.applicationId,
529+
'X-Parse-Javascript-Key': Parse.javaScriptKey
530+
}
531+
});
532+
}).then((resp) => {
533+
expect(resp.results.length).toBe(2);
534+
done();
535+
}, done.fail);
536+
});
537+
538+
it('invalid Polygon object withinPolygon', (done) => {
539+
const point = new Parse.GeoPoint(1.5, 1.5);
540+
const obj = new Parse.Object('Polygon', {location: point});
541+
const polygon = {
542+
__type: 'Polygon',
543+
coordinates: [
544+
[0, 0],
545+
[10, 0],
546+
]
547+
}
548+
obj.save().then(() => {
549+
const where = {
550+
location: {
551+
$geoWithin: {
552+
$polygon: polygon
553+
}
554+
}
555+
};
556+
return rp.post({
557+
url: Parse.serverURL + '/classes/Polygon',
558+
json: { where, '_method': 'GET' },
559+
headers: {
560+
'X-Parse-Application-Id': Parse.applicationId,
561+
'X-Parse-Javascript-Key': Parse.javaScriptKey
562+
}
563+
});
564+
}).then((resp) => {
565+
fail(`no request should succeed: ${JSON.stringify(resp)}`);
566+
done();
567+
}).catch((err) => {
568+
expect(err.error.code).toEqual(Parse.Error.INVALID_JSON);
569+
done();
570+
});
571+
});
572+
573+
it('out of bounds Polygon object withinPolygon', (done) => {
574+
const point = new Parse.GeoPoint(1.5, 1.5);
575+
const obj = new Parse.Object('Polygon', {location: point});
576+
const polygon = {
577+
__type: 'Polygon',
578+
coordinates: [
579+
[0, 0],
580+
[181, 0],
581+
[0, 10]
582+
]
583+
}
584+
obj.save().then(() => {
585+
const where = {
586+
location: {
587+
$geoWithin: {
588+
$polygon: polygon
589+
}
590+
}
591+
};
592+
return rp.post({
593+
url: Parse.serverURL + '/classes/Polygon',
594+
json: { where, '_method': 'GET' },
595+
headers: {
596+
'X-Parse-Application-Id': Parse.applicationId,
597+
'X-Parse-Javascript-Key': Parse.javaScriptKey
598+
}
599+
});
600+
}).then((resp) => {
601+
fail(`no request should succeed: ${JSON.stringify(resp)}`);
602+
done();
603+
}).catch((err) => {
604+
expect(err.error.code).toEqual(1);
605+
done();
606+
});
607+
});
608+
499609
it('invalid input withinPolygon', (done) => {
500610
const point = new Parse.GeoPoint(1.5, 1.5);
501611
const obj = new Parse.Object('Polygon', {location: point});

src/Adapters/Storage/Mongo/MongoTransform.js

+24-9
Original file line numberDiff line numberDiff line change
@@ -905,19 +905,34 @@ function transformConstraint(constraint, field) {
905905

906906
case '$geoWithin': {
907907
const polygon = constraint[key]['$polygon'];
908-
if (!(polygon instanceof Array)) {
909-
throw new Parse.Error(
910-
Parse.Error.INVALID_JSON,
911-
'bad $geoWithin value; $polygon should contain at least 3 GeoPoints'
912-
);
913-
}
914-
if (polygon.length < 3) {
908+
let points;
909+
if (typeof polygon === 'object' && polygon.__type === 'Polygon') {
910+
if (!polygon.coordinates || polygon.coordinates.length < 3) {
911+
throw new Parse.Error(
912+
Parse.Error.INVALID_JSON,
913+
'bad $geoWithin value; Polygon.coordinates should contain at least 3 lon/lat pairs'
914+
);
915+
}
916+
points = polygon.coordinates;
917+
} else if (polygon instanceof Array) {
918+
if (polygon.length < 3) {
919+
throw new Parse.Error(
920+
Parse.Error.INVALID_JSON,
921+
'bad $geoWithin value; $polygon should contain at least 3 GeoPoints'
922+
);
923+
}
924+
points = polygon;
925+
} else {
915926
throw new Parse.Error(
916927
Parse.Error.INVALID_JSON,
917-
'bad $geoWithin value; $polygon should contain at least 3 GeoPoints'
928+
'bad $geoWithin value; $polygon should be Polygon object or Array of Parse.GeoPoint\'s'
918929
);
919930
}
920-
const points = polygon.map((point) => {
931+
points = points.map((point) => {
932+
if (point instanceof Array && point.length === 2) {
933+
Parse.GeoPoint._validate(point[1], point[0]);
934+
return point;
935+
}
921936
if (!GeoPointCoder.isValidJSON(point)) {
922937
throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad $geoWithin value');
923938
} else {

src/Adapters/Storage/Postgres/PostgresStorageAdapter.js

+24-9
Original file line numberDiff line numberDiff line change
@@ -537,19 +537,34 @@ const buildWhereClause = ({ schema, query, index }): WhereClause => {
537537

538538
if (fieldValue.$geoWithin && fieldValue.$geoWithin.$polygon) {
539539
const polygon = fieldValue.$geoWithin.$polygon;
540-
if (!(polygon instanceof Array)) {
541-
throw new Parse.Error(
542-
Parse.Error.INVALID_JSON,
543-
'bad $geoWithin value; $polygon should contain at least 3 GeoPoints'
544-
);
545-
}
546-
if (polygon.length < 3) {
540+
let points;
541+
if (typeof polygon === 'object' && polygon.__type === 'Polygon') {
542+
if (!polygon.coordinates || polygon.coordinates.length < 3) {
543+
throw new Parse.Error(
544+
Parse.Error.INVALID_JSON,
545+
'bad $geoWithin value; Polygon.coordinates should contain at least 3 lon/lat pairs'
546+
);
547+
}
548+
points = polygon.coordinates;
549+
} else if ((polygon instanceof Array)) {
550+
if (polygon.length < 3) {
551+
throw new Parse.Error(
552+
Parse.Error.INVALID_JSON,
553+
'bad $geoWithin value; $polygon should contain at least 3 GeoPoints'
554+
);
555+
}
556+
points = polygon;
557+
} else {
547558
throw new Parse.Error(
548559
Parse.Error.INVALID_JSON,
549-
'bad $geoWithin value; $polygon should contain at least 3 GeoPoints'
560+
'bad $geoWithin value; $polygon should be Polygon object or Array of Parse.GeoPoint\'s'
550561
);
551562
}
552-
const points = polygon.map((point) => {
563+
points = points.map((point) => {
564+
if (point instanceof Array && point.length === 2) {
565+
Parse.GeoPoint._validate(point[1], point[0]);
566+
return `(${point[0]}, ${point[1]})`;
567+
}
553568
if (typeof point !== 'object' || point.__type !== 'GeoPoint') {
554569
throw new Parse.Error(Parse.Error.INVALID_JSON, 'bad $geoWithin value');
555570
} else {

0 commit comments

Comments
 (0)