forked from MorphiaOrg/morphia
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Geo API 589] Preparation for Geo API updates - adding test coverage …
…and improving documentation of existing Geo features.
- Loading branch information
Showing
7 changed files
with
482 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
134 changes: 134 additions & 0 deletions
134
morphia/src/test/java/org/mongodb/morphia/geo/LegacyCoordsTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
package org.mongodb.morphia.geo; | ||
|
||
import com.mongodb.DBObject; | ||
import com.mongodb.MongoException; | ||
import org.junit.Test; | ||
import org.mongodb.morphia.TestBase; | ||
import org.mongodb.morphia.query.Query; | ||
|
||
import java.util.List; | ||
|
||
import static org.hamcrest.CoreMatchers.is; | ||
import static org.hamcrest.CoreMatchers.notNullValue; | ||
import static org.hamcrest.CoreMatchers.nullValue; | ||
import static org.junit.Assert.assertThat; | ||
import static org.mongodb.morphia.testutil.IndexMatcher.doesNotHaveIndexNamed; | ||
import static org.mongodb.morphia.testutil.IndexMatcher.hasIndexNamed; | ||
|
||
/** | ||
* This test shows how to define an entity that uses the legacy co-ordinate pairs standard, which works with MongoDB server versions 2.2 and | ||
* earlier. If you are using a server version higher than 2.2 (i.e. 2.4 and onwards) you should store location information as <a | ||
* href="http://docs.mongodb.org/manual/reference/glossary/#term-geojson">GeoJSON</a> and consult the documentation for indexes and queries | ||
* that work on this format. Storing the location as GeoJSON gives you access to a wider range of queries. | ||
* <p/> | ||
* This set of tests should run on all server versions. | ||
*/ | ||
public class LegacyCoordsTest extends TestBase { | ||
@Test | ||
public void shouldCreateA2dIndexOnAnEntityWithArrayOfCoordinates() { | ||
// given | ||
PlaceWithLegacyCoords pointA = new PlaceWithLegacyCoords(new double[]{3.1, 5.2}, "Point A"); | ||
getDs().save(pointA); | ||
|
||
// when | ||
getDs().ensureIndexes(); | ||
|
||
// then | ||
List<DBObject> indexes = getDs().getCollection(PlaceWithLegacyCoords.class).getIndexInfo(); | ||
assertThat(indexes, hasIndexNamed("location_2d")); | ||
} | ||
|
||
@Test | ||
public void shouldReturnAllLocationsOrderedByDistanceFromQueryLocationWhenPerformingNearQuery() throws Exception { | ||
// given | ||
final PlaceWithLegacyCoords nearbyPlace = new PlaceWithLegacyCoords(new double[]{1.1, 2.3}, "Nearby Place"); | ||
getDs().save(nearbyPlace); | ||
final PlaceWithLegacyCoords furtherAwayPlace = new PlaceWithLegacyCoords(new double[]{10.1, 12.3}, "Further Away Place"); | ||
getDs().save(furtherAwayPlace); | ||
getDs().ensureIndexes(); | ||
|
||
// when | ||
final List<PlaceWithLegacyCoords> found = getDs().find(PlaceWithLegacyCoords.class) | ||
.field("location") | ||
.near(1.0, 2.0) | ||
.asList(); | ||
|
||
// then | ||
assertThat(found, is(notNullValue())); | ||
assertThat(found.size(), is(2)); | ||
assertThat(found.get(0), is(nearbyPlace)); | ||
assertThat(found.get(1), is(furtherAwayPlace)); | ||
} | ||
|
||
@Test | ||
public void shouldReturnOnlyThosePlacesWithinTheGivenRadius() throws Exception { | ||
// given | ||
final PlaceWithLegacyCoords nearbyPlace = new PlaceWithLegacyCoords(new double[]{1.1, 2.3}, "Nearby Place"); | ||
getDs().save(nearbyPlace); | ||
final PlaceWithLegacyCoords furtherAwayPlace = new PlaceWithLegacyCoords(new double[]{10.1, 12.3}, "Further Away Place"); | ||
getDs().save(furtherAwayPlace); | ||
getDs().ensureIndexes(); | ||
|
||
// when | ||
final List<PlaceWithLegacyCoords> found = getDs().find(PlaceWithLegacyCoords.class) | ||
.field("location") | ||
.near(1.0, 2.0, 1.5) | ||
.asList(); | ||
// then | ||
assertThat(found, is(notNullValue())); | ||
assertThat(found.size(), is(1)); | ||
assertThat(found.get(0), is(nearbyPlace)); | ||
} | ||
|
||
@Test | ||
public void shouldNotReturnAnyResultsIfNoLocationsWithinGivenRadius() throws Exception { | ||
// given | ||
final PlaceWithLegacyCoords nearbyPlace = new PlaceWithLegacyCoords(new double[]{1.1, 2.3}, "Nearby Place"); | ||
getDs().save(nearbyPlace); | ||
getDs().ensureIndexes(); | ||
|
||
// when | ||
Query<PlaceWithLegacyCoords> locationQuery = getDs().find(PlaceWithLegacyCoords.class) | ||
.field("location") | ||
.near(1.0, 2.0, 0.1); | ||
// then | ||
assertThat(locationQuery.asList().size(), is(0)); | ||
assertThat(locationQuery.get(), is(nullValue())); | ||
} | ||
|
||
@Test | ||
public void shouldFindPointWithExactMatch() { | ||
// given | ||
final PlaceWithLegacyCoords nearbyPlace = new PlaceWithLegacyCoords(new double[]{1.1, 2.3}, "Nearby Place"); | ||
getDs().save(nearbyPlace); | ||
getDs().ensureIndexes(); | ||
|
||
// when | ||
List<PlaceWithLegacyCoords> found = getDs().find(PlaceWithLegacyCoords.class) | ||
.field("location") | ||
.equal(new double[]{1.1, 2.3}) | ||
.asList(); | ||
|
||
// then | ||
assertThat(found, is(notNullValue())); | ||
assertThat(found.size(), is(1)); | ||
assertThat(found.get(0), is(nearbyPlace)); | ||
} | ||
|
||
@Test(expected = MongoException.class) | ||
public void shouldThrowAnExceptionIfQueryingWithoutA2dIndex() throws Exception { | ||
// given | ||
final PlaceWithLegacyCoords nearbyPlace = new PlaceWithLegacyCoords(new double[]{1.1, 2.3}, "Nearby Place"); | ||
getDs().save(nearbyPlace); | ||
List<DBObject> indexes = getDs().getCollection(PlaceWithLegacyCoords.class).getIndexInfo(); | ||
assertThat(indexes, doesNotHaveIndexNamed("location_2d")); | ||
|
||
// when | ||
getDs().find(PlaceWithLegacyCoords.class) | ||
.field("location") | ||
.near(0, 0) | ||
.get(); | ||
|
||
// then expect the Exception | ||
} | ||
} |
174 changes: 174 additions & 0 deletions
174
morphia/src/test/java/org/mongodb/morphia/geo/LegacyCoordsWithWithinQueries.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
package org.mongodb.morphia.geo; | ||
|
||
import org.junit.Test; | ||
import org.mongodb.morphia.TestBase; | ||
import org.mongodb.morphia.query.Shape; | ||
|
||
import java.util.List; | ||
|
||
import static org.hamcrest.CoreMatchers.is; | ||
import static org.hamcrest.CoreMatchers.nullValue; | ||
import static org.junit.Assert.assertThat; | ||
|
||
/** | ||
* Although this tests the old legacy coordinate system of storing location, this set of tests shows the functionality that's available with | ||
* these coordinates in later versions of the server that also support GeoJSON. In order to get full geo querying functionality, you should | ||
* use GeoJSON for storing your location not legacy co-ordinates. | ||
* <p/> | ||
* This test requires server version 2.4 or above as it uses $geoWithin. | ||
*/ | ||
public class LegacyCoordsWithWithinQueries extends TestBase { | ||
@Test | ||
public void shouldReturnOnlyThePointsWithinTheGivenCircle() throws Exception { | ||
// given | ||
checkMinServerVersion(2.4); | ||
|
||
final PlaceWithLegacyCoords expectedPoint = new PlaceWithLegacyCoords(new double[]{1.1, 2.3}, "Near point"); | ||
getDs().save(expectedPoint); | ||
final PlaceWithLegacyCoords otherPoint = new PlaceWithLegacyCoords(new double[]{3.1, 5.2}, "Further point"); | ||
getDs().save(otherPoint); | ||
getDs().ensureIndexes(); | ||
|
||
// when | ||
final List<PlaceWithLegacyCoords> found = getDs().find(PlaceWithLegacyCoords.class) | ||
.field("location") | ||
.within(Shape.center(new Shape.Point(1, 2), 1.1)) | ||
.asList(); | ||
|
||
// then | ||
assertThat(found.size(), is(1)); | ||
assertThat(found.get(0), is(expectedPoint)); | ||
} | ||
|
||
@Test | ||
public void shouldReturnPointOnBoundaryOfQueryCircle() throws Exception { | ||
// given | ||
checkMinServerVersion(2.4); | ||
|
||
final PlaceWithLegacyCoords expectedPoint = new PlaceWithLegacyCoords(new double[]{1, 1}, "place"); | ||
getDs().save(expectedPoint); | ||
getDs().ensureIndexes(); | ||
|
||
// when - search with circle with an edge that exactly covers the point | ||
final PlaceWithLegacyCoords found = getDs().find(PlaceWithLegacyCoords.class) | ||
.field("location") | ||
.within(Shape.center(new Shape.Point(0, 1), 1)) | ||
.get(); | ||
// then | ||
assertThat(found, is(expectedPoint)); | ||
} | ||
|
||
@Test | ||
public void shouldReturnPointOnBoundaryOfQueryCircleWithSphericalGeometry() throws Exception { | ||
// given | ||
checkMinServerVersion(2.4); | ||
|
||
final PlaceWithLegacyCoords expectedPoint = new PlaceWithLegacyCoords(new double[]{1, 1}, "place"); | ||
getDs().save(expectedPoint); | ||
getDs().ensureIndexes(); | ||
|
||
// when - search with circle with an edge that exactly covers the point | ||
final PlaceWithLegacyCoords found = getDs().find(PlaceWithLegacyCoords.class) | ||
.field("location") | ||
.within(Shape.centerSphere(new Shape.Point(0, 1), 1)) | ||
.get(); | ||
// then | ||
assertThat(found, is(expectedPoint)); | ||
} | ||
|
||
@Test | ||
public void shouldNotReturnAnyPointsIfNothingInsideCircle() throws Exception { | ||
// given | ||
checkMinServerVersion(2.4); | ||
|
||
final PlaceWithLegacyCoords point = new PlaceWithLegacyCoords(new double[]{1, 1}, "place"); | ||
getDs().save(point); | ||
getDs().ensureIndexes(); | ||
|
||
// when - search with circle that does not cover the only point | ||
final PlaceWithLegacyCoords found = getDs().find(PlaceWithLegacyCoords.class) | ||
.field("location") | ||
.within(Shape.center(new Shape.Point(2, 2), 0.5)) | ||
.get(); | ||
// then | ||
assertThat(found, is(nullValue())); | ||
} | ||
|
||
@Test | ||
public void shouldReturnPointThatIsFullyInsideTheQueryBox() throws Exception { | ||
// given | ||
checkMinServerVersion(2.4); | ||
|
||
final PlaceWithLegacyCoords expectedPoint = new PlaceWithLegacyCoords(new double[]{1, 1}, "place"); | ||
getDs().save(expectedPoint); | ||
getDs().ensureIndexes(); | ||
|
||
// when - search with a box that covers the whole point | ||
final PlaceWithLegacyCoords found = getDs().find(PlaceWithLegacyCoords.class) | ||
.field("location") | ||
.within(Shape.box(new Shape.Point(0, 0), new Shape.Point(2, 2))) | ||
.get(); | ||
// then | ||
assertThat(found, is(expectedPoint)); | ||
} | ||
|
||
@Test | ||
public void shouldNotReturnAnyValuesWhenTheQueryBoxDoesNotContainAnyPoints() throws Exception { | ||
// given | ||
checkMinServerVersion(2.4); | ||
|
||
final PlaceWithLegacyCoords point = new PlaceWithLegacyCoords(new double[]{1, 1}, "place"); | ||
getDs().save(point); | ||
getDs().ensureIndexes(); | ||
|
||
// when - search with a box that does not cover the point | ||
final PlaceWithLegacyCoords found = getDs().find(PlaceWithLegacyCoords.class) | ||
.field("location") | ||
.within(Shape.box(new Shape.Point(0, 0), new Shape.Point(0.5, 0.5))) | ||
.get(); | ||
// then | ||
assertThat(found, is(nullValue())); | ||
} | ||
|
||
@Test | ||
public void shouldReturnAPointThatIsFullyWithinQueryPolygon() throws Exception { | ||
// given | ||
checkMinServerVersion(2.4); | ||
|
||
final PlaceWithLegacyCoords expectedPoint = new PlaceWithLegacyCoords(new double[]{1, 1}, "place"); | ||
getDs().save(expectedPoint); | ||
getDs().ensureIndexes(); | ||
|
||
// when - search with polygon that contains expected point | ||
final PlaceWithLegacyCoords found = getDs().find(PlaceWithLegacyCoords.class) | ||
.field("location") | ||
.within(Shape.polygon(new Shape.Point(0, 0), | ||
new Shape.Point(0, 5), | ||
new Shape.Point(2, 3), | ||
new Shape.Point(1, 0))) | ||
.get(); | ||
// then | ||
assertThat(found, is(expectedPoint)); | ||
} | ||
|
||
@Test | ||
public void shouldNotReturnAnyValuesWhenTheQueryPolygonDoesNotContainAnyPoints() throws Exception { | ||
// given | ||
checkMinServerVersion(2.4); | ||
|
||
final PlaceWithLegacyCoords point = new PlaceWithLegacyCoords(new double[]{7.3, 9.2}, "place"); | ||
getDs().save(point); | ||
getDs().ensureIndexes(); | ||
|
||
// when - search with polygon that's nowhere near the given point | ||
final PlaceWithLegacyCoords found = getDs().find(PlaceWithLegacyCoords.class) | ||
.field("location") | ||
.within(Shape.polygon(new Shape.Point(0, 0), | ||
new Shape.Point(0, 5), | ||
new Shape.Point(2, 3), | ||
new Shape.Point(1, 0))) | ||
.get(); | ||
// then | ||
assertThat(found, is(nullValue())); | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
morphia/src/test/java/org/mongodb/morphia/geo/PlaceWithLegacyCoords.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package org.mongodb.morphia.geo; | ||
|
||
import org.mongodb.morphia.annotations.Indexed; | ||
import org.mongodb.morphia.utils.IndexDirection; | ||
|
||
import java.util.Arrays; | ||
|
||
@SuppressWarnings("unused") | ||
class PlaceWithLegacyCoords { | ||
@Indexed(IndexDirection.GEO2D) | ||
private double[] location = new double[2]; | ||
private String name; | ||
|
||
PlaceWithLegacyCoords(final double[] location, final String name) { | ||
this.location = location; | ||
this.name = name; | ||
} | ||
|
||
PlaceWithLegacyCoords() { | ||
} | ||
|
||
// equals(), hashCode() and toString() all needed for testing | ||
@Override | ||
public boolean equals(final Object o) { | ||
if (this == o) { | ||
return true; | ||
} | ||
if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
|
||
PlaceWithLegacyCoords place = (PlaceWithLegacyCoords) o; | ||
|
||
if (!Arrays.equals(location, place.location)) { | ||
return false; | ||
} | ||
if (!name.equals(place.name)) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
int result = Arrays.hashCode(location); | ||
result = 31 * result + name.hashCode(); | ||
return result; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "Place{" | ||
+ "location=" + Arrays.toString(location) | ||
+ ", name='" + name + '\'' | ||
+ '}'; | ||
} | ||
} |
Oops, something went wrong.