summaryrefslogtreecommitdiff
path: root/src/mongo/db/matcher/expression_geo_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/matcher/expression_geo_test.cpp')
-rw-r--r--src/mongo/db/matcher/expression_geo_test.cpp415
1 files changed, 415 insertions, 0 deletions
diff --git a/src/mongo/db/matcher/expression_geo_test.cpp b/src/mongo/db/matcher/expression_geo_test.cpp
index 4115285de18..4c2d81cbfa8 100644
--- a/src/mongo/db/matcher/expression_geo_test.cpp
+++ b/src/mongo/db/matcher/expression_geo_test.cpp
@@ -33,11 +33,13 @@
#include <memory>
+#include "mongo/db/exec/document_value/document_value_test_util.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/json.h"
#include "mongo/db/matcher/expression.h"
#include "mongo/db/matcher/expression_geo.h"
+
namespace mongo {
TEST(ExpressionGeoTest, Geo1) {
@@ -153,6 +155,143 @@ TEST(ExpressionGeoTest, GeoNearEquivalent) {
}
}
+
+TEST(ExpressionGeoTest, SerializeGeoExpressions) {
+ SerializationOptions opts = {};
+ opts.transformIdentifiers = true;
+ opts.literalPolicy = LiteralSerializationPolicy::kToDebugTypeString;
+ {
+ BSONObj query = fromjson("{$within: {$box: [{x: 4, y: 4}, [6, 6]]}}");
+ std::unique_ptr<GeoMatchExpression> ge(makeGeoMatchExpression(query));
+
+ ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
+ R"({"$within":{"$box":"?array<>"}})",
+ ge->getSerializedRightHandSide(opts));
+ }
+ {
+ BSONObj query = fromjson(
+ "{$geoWithin: {$geometry: {type: \"MultiPolygon\", coordinates: [[[[20.0, 70.0],[30.0, "
+ "70.0],[30.0, 50.0],[20.0, 50.0],[20.0, 70.0]]]]}}}");
+ std::unique_ptr<GeoMatchExpression> ge(makeGeoMatchExpression(query));
+ ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
+ R"({
+ "$geoWithin": {
+ "$geometry": {
+ "type": "MultiPolygon",
+ "coordinates": "?array<?array>"
+ }
+ }
+ })",
+ ge->getSerializedRightHandSide(opts));
+ }
+ {
+ BSONObj query = fromjson(
+ R"({
+ "$geoIntersects": {
+ "$geometry": {
+ "type": "MultiPolygon",
+ "coordinates": [[[
+ [-20.0, -70.0],
+ [-30.0, -70.0],
+ [-30.0, -50.0],
+ [-20.0, -50.0],
+ [-20.0, -70.0]
+ ]]]
+ }
+ }
+ })");
+ std::unique_ptr<GeoMatchExpression> ge(makeGeoMatchExpression(query));
+ ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
+ R"({
+ "$geoIntersects": {
+ "$geometry": {
+ "type": "MultiPolygon",
+ "coordinates": "?array<?array>"
+ }
+ }
+ })",
+ ge->getSerializedRightHandSide(opts));
+ }
+ {
+ BSONObj query1 = fromjson(
+ R"({$within: {
+ $geometry: {
+ type: 'Polygon',
+ coordinates: [[[0, 0], [3, 6], [6, 1], [0, 0]]]
+ }
+ }})");
+ std::unique_ptr<GeoMatchExpression> ge(makeGeoMatchExpression(query1));
+ ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
+ R"({"$within":{"$geometry":{"type":"Polygon","coordinates":"?array<?array>"}}})",
+ ge->getSerializedRightHandSide(opts));
+ }
+ {
+ BSONObj query = fromjson(
+ "{$near: {$maxDistance: 100, "
+ "$geometry: {type: 'Point', coordinates: [0, 0]}}}");
+ std::unique_ptr<GeoNearMatchExpression> gne(makeGeoNearMatchExpression(query));
+ ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
+ R"({
+ "$near": {
+ "$maxDistance": "?number",
+ "$geometry": {
+ "type": "Point",
+ "coordinates": "?array<?number>"
+ }
+ }
+ })",
+ gne->getSerializedRightHandSide(opts));
+ }
+ {
+ BSONObj query = fromjson("{ $nearSphere: [0,0], $minDistance: 1, $maxDistance: 3 }");
+ std::unique_ptr<GeoNearMatchExpression> gne(makeGeoNearMatchExpression(query));
+ ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
+ R"({
+ "$nearSphere": "?array<?number>",
+ "$minDistance": "?number",
+ "$maxDistance": "?number"
+ })",
+ gne->getSerializedRightHandSide(opts));
+ }
+
+ {
+ BSONObj query = fromjson("{$near : [0, 0, 1] }");
+ std::unique_ptr<GeoNearMatchExpression> gne(makeGeoNearMatchExpression(query));
+ ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
+ R"({"$near":"?array<?number>"})",
+ gne->getSerializedRightHandSide(opts));
+ }
+ {
+ BSONObj query = fromjson("{$geoNear: [0, 0, 100]}");
+ std::unique_ptr<GeoNearMatchExpression> gne(makeGeoNearMatchExpression(query));
+ ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
+ R"({"$geoNear":"?array<?number>"})",
+ gne->getSerializedRightHandSide(opts));
+ }
+ {
+ BSONObj query = fromjson("{$geoNear: [0, 10], $maxDistance: 80 }");
+ std::unique_ptr<GeoNearMatchExpression> gne(makeGeoNearMatchExpression(query));
+ ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
+ R"({"$geoNear":"?array<?number>","$maxDistance":"?number"})",
+ gne->getSerializedRightHandSide(opts));
+ }
+ {
+ BSONObj query = fromjson("{$geoIntersects: {$geometry: [0, 0]}}");
+ std::unique_ptr<GeoMatchExpression> ge(makeGeoMatchExpression(query));
+ ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
+ R"({"$geoIntersects":{"$geometry":["?number","?number"]}})",
+ ge->getSerializedRightHandSide(opts));
+ }
+ {
+ // Make sure we reject arrays with <2 or >2 elements.
+ BSONObj query = fromjson("{$geoIntersects: {$geometry: [0, 0, 1]}}");
+ std::unique_ptr<GeoExpression> gq(new GeoExpression);
+ ASSERT_NOT_OK(gq->parseFrom(query));
+ query = fromjson("{$geoIntersects: {$geometry: [0]}}");
+ ASSERT_NOT_OK(gq->parseFrom(query));
+ }
+}
+
/**
* A geo expression being not equivalent to another expression.
*/
@@ -182,4 +321,280 @@ TEST(ExpressionGeoTest, GeoNearNotEquivalent) {
gne2(makeGeoNearMatchExpression(query2));
ASSERT(!gne1->equivalent(gne2.get()));
}
+
+TEST(ExpressionGeoTest, SerializeWithCRSIFSpecifiedWithChangedOptions) {
+ BSONObj query1 = fromjson(
+ "{$within: {$geometry: {type: 'Polygon',"
+ "coordinates: [[[0, 0], [3, 6], [6, 1], [0, 0]]],"
+ "crs: {"
+ "type: 'name',"
+ "properties: { name: 'urn:x-mongodb:crs:strictwinding:EPSG:4326' }"
+ "}}}}");
+ std::unique_ptr<GeoMatchExpression> ge1(makeGeoMatchExpression(query1));
+ auto opts = SerializationOptions{LiteralSerializationPolicy::kToRepresentativeParseableValue};
+ auto serialized = ge1->getSerializedRightHandSide(opts);
+ ASSERT_BSONOBJ_EQ_AUTO(
+ R"({
+ "$within": {
+ "$geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 1
+ ],
+ [
+ 1,
+ 1
+ ],
+ [
+ 0,
+ 0
+ ]
+ ]
+ ],
+ "crs": {
+ "type": "name",
+ "properties": {
+ "name": "urn:x-mongodb:crs:strictwinding:EPSG:4326"
+ }
+ }
+ }
+ }
+ })",
+ serialized);
+ serialized = ge1->getSerializedRightHandSide(opts);
+ ASSERT_BSONOBJ_EQ_AUTO(
+ R"({
+ "$within": {
+ "$geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 1
+ ],
+ [
+ 1,
+ 1
+ ],
+ [
+ 0,
+ 0
+ ]
+ ]
+ ],
+ "crs": {
+ "type": "name",
+ "properties": {
+ "name": "urn:x-mongodb:crs:strictwinding:EPSG:4326"
+ }
+ }
+ }
+ }
+ })",
+ serialized);
+}
+
+template <typename CreateFn>
+void assertRepresentativeShapeIsStable(BSONObj inputExpr,
+ BSONObj expectedRepresentativeExpr,
+ CreateFn createFn) {
+ auto opts = SerializationOptions{LiteralSerializationPolicy::kToRepresentativeParseableValue};
+ auto ge(createFn(inputExpr));
+
+ auto serializedExpr = ge->getSerializedRightHandSide(opts);
+ ASSERT_BSONOBJ_EQ(serializedExpr, expectedRepresentativeExpr);
+
+ auto roundTripped = createFn(serializedExpr);
+ ASSERT_BSONOBJ_EQ(roundTripped->getSerializedRightHandSide(opts), serializedExpr);
+}
+
+void assertRepresentativeGeoShapeIsStable(BSONObj inputExpr, BSONObj expectedRepresentativeExpr) {
+ assertRepresentativeShapeIsStable(
+ inputExpr, expectedRepresentativeExpr, [](const BSONObj& input) {
+ return makeGeoMatchExpression(input);
+ });
+}
+
+void assertRepresentativeGeoNearShapeIsStable(BSONObj inputExpr,
+ BSONObj expectedRepresentativeExpr) {
+ assertRepresentativeShapeIsStable(
+ inputExpr, expectedRepresentativeExpr, [](const BSONObj& input) {
+ return makeGeoNearMatchExpression(input);
+ });
+}
+
+TEST(ExpressionGeoTest, RoundTripSerializeGeoExpressions) {
+ assertRepresentativeGeoShapeIsStable(fromjson("{$within: {$box: [{x: 4, y: 4}, [6, 6]]}}"),
+ fromjson("{$within: {$box: [[1, 1],[1, 1]]}}"));
+
+ assertRepresentativeGeoShapeIsStable(
+ fromjson(
+ R"({$geoWithin: {$geometry: {type: "MultiPolygon", coordinates: [[[[20.0, 70.0],[30.0, 70.0],[30.0, 50.0],[20.0, 50.0],[20.0, 70.0]]]]}}})"),
+ fromjson(
+ R"({$geoWithin: {$geometry: {type: "MultiPolygon", coordinates: [[[[0, 0],[0, 1],[1, 1],[0, 0]]]]}}})"));
+
+ assertRepresentativeGeoShapeIsStable(fromjson(R"({
+ "$geoIntersects": {
+ "$geometry": {
+ "type": "MultiPolygon",
+ "coordinates": [[[
+ [-20.0, -70.0],
+ [-30.0, -70.0],
+ [-30.0, -50.0],
+ [-20.0, -50.0],
+ [-20.0, -70.0]
+ ]]]
+ }
+ }
+ })"),
+ fromjson(R"({
+ "$geoIntersects": {
+ "$geometry": {
+ "type": "MultiPolygon",
+ "coordinates": [[[[0, 0],[0, 1],[1, 1],[0, 0]]]]
+ }
+ }
+ })"));
+
+ assertRepresentativeGeoShapeIsStable(fromjson(R"({$within: {
+ $geometry: {
+ type: 'Polygon',
+ coordinates: [[[0, 0], [3, 6], [6, 1], [0, 0]]]
+ }
+ }})"),
+ fromjson(R"({$within: {
+ $geometry: {
+ type: 'Polygon',
+ coordinates: [[[0, 0],[0, 1],[1, 1],[0, 0]]]
+ }
+ }})"));
+
+ assertRepresentativeGeoNearShapeIsStable(
+ fromjson("{$near: {$maxDistance: 100, $geometry: {type: 'Point', coordinates: [0, 0]}}}"),
+ fromjson("{$near: {$maxDistance: 1, $geometry: {type: 'Point', coordinates: [1, 1]}}}"));
+
+ assertRepresentativeGeoNearShapeIsStable(
+ fromjson("{$nearSphere: [0,0], $minDistance: 2, $maxDistance: 4 }"),
+ fromjson("{$nearSphere: [1,1], $minDistance: 1, $maxDistance: 1 }"));
+
+ assertRepresentativeGeoNearShapeIsStable(
+ fromjson("{$minDistance: 2, $maxDistance: 4, $nearSphere: [0,0]}"),
+ fromjson("{$minDistance: 1, $maxDistance: 1, $nearSphere: [1,1]}"));
+
+ assertRepresentativeGeoNearShapeIsStable(fromjson("{$near: [0, 0, 1]}"),
+ fromjson("{$near: [1, 1]}"));
+
+ assertRepresentativeGeoNearShapeIsStable(fromjson("{$geoNear: [0, 0, 100]}"),
+ fromjson("{$geoNear: [1, 1]}"));
+
+ assertRepresentativeGeoNearShapeIsStable(fromjson("{$geoNear: [0, 10], $maxDistance: 80 }"),
+ fromjson("{$geoNear: [1, 1], $maxDistance: 1}"));
+
+ assertRepresentativeGeoShapeIsStable(fromjson("{$geoIntersects: {$geometry: [0, 0]}}"),
+ fromjson("{$geoIntersects: {$geometry: [1, 1]}}"));
+ // Test scenario with new $geometry query not specifying the geometry type.
+ assertRepresentativeGeoNearShapeIsStable(
+ fromjson("{$geoNear: { $geometry: {coordinates: [0, 10]}}}"),
+ fromjson("{$geoNear: { $geometry: {coordinates: [1, 1]}}}"));
+
+ // Test scenario with new $geometry query specifying invalid type.
+ assertRepresentativeGeoNearShapeIsStable(
+ fromjson("{$geoNear: { $geometry: { type: 'b.c', coordinates: [0, 10]}}}"),
+ fromjson("{$geoNear: { $geometry: {type: 'b.c', coordinates: [1, 1]}}}"));
+
+ // Test scenario with $nearSphere without $geometry and no type specified
+ assertRepresentativeGeoNearShapeIsStable(fromjson(R"({"$nearSphere":{"coordinates":[0,0]}})"),
+ fromjson(R"({"$nearSphere":{"coordinates":[1,1]}})"));
+
+ // Test case with first field of $geometry as numeric field, arbitrary coordinate naming.
+ assertRepresentativeGeoShapeIsStable(
+ fromjson(R"({"$geoIntersects":{"$geometry":{"shardOptions":40,"y":5}}})"),
+ fromjson(R"({"$geoIntersects":{"$geometry":{"shardOptions":1,"y":1}}})"));
+
+ assertRepresentativeGeoShapeIsStable(fromjson(R"({
+ "$geoIntersects": {
+ "$geometry": {
+ "type": "MultiLineString",
+ "coordinates": [[
+ [2, 0],
+ [2, 2]
+ ], [
+ [0, 4],
+ [1, 4]
+ ]]
+ }
+ }
+ })"),
+ fromjson(R"({
+ "$geoIntersects": {
+ "$geometry": {
+ "type": "MultiLineString",
+ "coordinates": [[[0, 0], [1, 1]],[[0, 0], [1, 1]]]
+ }
+ }
+ })"));
+
+ assertRepresentativeGeoShapeIsStable(fromjson(R"({
+ "$geoIntersects": {
+ "$geometry": {
+ "type": "LineString",
+ "coordinates": [
+ [2, 0],
+ [2, 2]
+ ]
+ }
+ }
+ })"),
+ fromjson(R"({
+ "$geoIntersects": {
+ "$geometry": {
+ "type": "LineString",
+ "coordinates": [[0, 0], [1, 1]]
+ }
+ }
+ })"));
+
+ assertRepresentativeGeoShapeIsStable(fromjson(R"({
+ "$geoIntersects": {
+ "$geometry": {
+ "type": "GeometryCollection",
+ "geometries": [{
+ "type": "LineString",
+ "coordinates": [
+ [2, 0],
+ [2, 2]
+ ]
+ }, {
+ type: 'Point', coordinates: [2, 2]
+ }]
+ }
+ }
+ })"),
+ fromjson(R"({
+ "$geoIntersects": {
+ "$geometry": {
+ "type": "GeometryCollection",
+ "geometries": [{
+ "type": "LineString",
+ "coordinates": [[0, 0], [1, 1]]
+ }, {
+ type: 'Point', coordinates: [1, 1]
+ }]
+ }
+ }
+ })"));
+}
+
} // namespace mongo