diff --git a/pom.xml b/pom.xml
index d60314ea..dc35011b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -207,6 +207,11 @@
mapbox-sdk-geojson
5.8.0
+
+ org.geotools
+ gt-main
+ 31.3
+
@@ -356,4 +361,21 @@
+
+
+
+ osgeo
+ OSGeo Release Repository
+ https://repo.osgeo.org/repository/release/
+ false
+ true
+
+
+ osgeo-snapshot
+ OSGeo Snapshot Repository
+ https://repo.osgeo.org/repository/snapshot/
+ true
+ false
+
+
diff --git a/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java b/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java
index 1f6410bd..fc3f43fa 100644
--- a/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java
+++ b/src/main/java/org/entur/lamassu/controller/GraphQLQueryController.java
@@ -18,6 +18,7 @@
import org.entur.lamassu.model.entities.Station;
import org.entur.lamassu.model.entities.Vehicle;
import org.entur.lamassu.model.provider.FeedProvider;
+import org.entur.lamassu.service.BoundingBoxQueryParameters;
import org.entur.lamassu.service.FeedProviderService;
import org.entur.lamassu.service.GeoSearchService;
import org.entur.lamassu.service.RangeQueryParameters;
@@ -71,6 +72,10 @@ public Collection getVehicles(
Double lat,
Double lon,
Double range,
+ Double minimumLatitude,
+ Double minimumLongitude,
+ Double maximumLatitude,
+ Double maximumLongitude,
Integer count,
List codespaces,
List systems,
@@ -84,17 +89,10 @@ public Collection getVehicles(
return vehicleCache.getAll(ids);
}
- validateRange(range);
validateCount(count);
validateCodespaces(codespaces);
validateSystems(systems);
- var queryParams = new RangeQueryParameters();
- queryParams.setLat(lat);
- queryParams.setLon(lon);
- queryParams.setRange(range);
- queryParams.setCount(count);
-
var filterParams = new VehicleFilterParameters();
filterParams.setCodespaces(codespaces);
filterParams.setSystems(systems);
@@ -103,10 +101,54 @@ public Collection getVehicles(
filterParams.setPropulsionTypes(propulsionTypes);
filterParams.setIncludeReserved(includeReserved);
filterParams.setIncludeDisabled(includeDisabled);
+ filterParams.setCount(count);
+
+ if (
+ isBoundingBoxSearch(
+ minimumLatitude,
+ minimumLongitude,
+ maximumLatitude,
+ maximumLongitude
+ )
+ ) {
+ var boundingBoxQueryParameters = new BoundingBoxQueryParameters();
+ boundingBoxQueryParameters.setMinimumLatitude(minimumLatitude);
+ boundingBoxQueryParameters.setMinimumLongitude(minimumLongitude);
+ boundingBoxQueryParameters.setMaximumLatitude(maximumLatitude);
+ boundingBoxQueryParameters.setMaximumLongitude(maximumLongitude);
+
+ logger.debug(
+ "getVehicles called boundingBoxQueryParameters={} filter={}",
+ boundingBoxQueryParameters,
+ filterParams
+ );
+
+ return geoSearchService.getVehiclesInBoundingBox(
+ boundingBoxQueryParameters,
+ filterParams
+ );
+ } else if (isRangeSearch(range, lat, lon)) {
+ validateRange(range);
- logger.debug("getVehicles called query={} filter={}", queryParams, filterParams);
+ var rangeQueryParameters = new RangeQueryParameters();
+ rangeQueryParameters.setLat(lat);
+ rangeQueryParameters.setLon(lon);
+ rangeQueryParameters.setRange(range);
- return geoSearchService.getVehiclesNearby(queryParams, filterParams);
+ logger.debug(
+ "getVehicles called rangeQueryParameters={} filter={}",
+ rangeQueryParameters,
+ filterParams
+ );
+
+ return geoSearchService.getVehiclesWithinRange(rangeQueryParameters, filterParams);
+ } else {
+ throw new GraphqlErrorException.Builder()
+ .message(
+ "You must either specify lat, lon and range OR minimumLatitude, minimumLongitude, maximumLatitude and maximumLongitude"
+ )
+ .build();
+ }
}
public Vehicle getVehicle(String id) {
@@ -118,6 +160,10 @@ public Collection getStations(
Double lat,
Double lon,
Double range,
+ Double minimumLatitude,
+ Double minimumLongitude,
+ Double maximumLatitude,
+ Double maximumLongitude,
Integer count,
List codespaces,
List systems,
@@ -129,27 +175,77 @@ public Collection getStations(
return stationCache.getAll(ids);
}
- validateRange(range);
validateCount(count);
validateCodespaces(codespaces);
validateSystems(systems);
- var queryParams = new RangeQueryParameters();
- queryParams.setLat(lat);
- queryParams.setLon(lon);
- queryParams.setRange(range);
- queryParams.setCount(count);
-
var filterParams = new StationFilterParameters();
filterParams.setCodespaces(codespaces);
filterParams.setSystems(systems);
filterParams.setOperators(operators);
filterParams.setAvailableFormFactors(availableFormFactors);
filterParams.setAvailablePropulsionTypes(availablePropulsionTypes);
+ filterParams.setCount(count);
- logger.debug("getStations called query={} filter={}", queryParams, filterParams);
+ if (
+ isBoundingBoxSearch(
+ minimumLatitude,
+ minimumLongitude,
+ maximumLatitude,
+ maximumLongitude
+ )
+ ) {
+ var boundingBoxQueryParameters = new BoundingBoxQueryParameters();
+ boundingBoxQueryParameters.setMinimumLatitude(minimumLatitude);
+ boundingBoxQueryParameters.setMinimumLongitude(minimumLongitude);
+ boundingBoxQueryParameters.setMaximumLatitude(maximumLatitude);
+ boundingBoxQueryParameters.setMaximumLongitude(maximumLongitude);
+ logger.debug(
+ "getStations called boundingBoxQueryParameters={} filter={}",
+ boundingBoxQueryParameters,
+ filterParams
+ );
+ return geoSearchService.getStationsInBoundingBox(
+ boundingBoxQueryParameters,
+ filterParams
+ );
+ } else if (isRangeSearch(range, lat, lon)) {
+ validateRange(range);
+ var rangeQueryParameters = new RangeQueryParameters();
+ rangeQueryParameters.setLat(lat);
+ rangeQueryParameters.setLon(lon);
+ rangeQueryParameters.setRange(range);
+ logger.debug(
+ "getStations called rangeQueryParameters={} filter={}",
+ rangeQueryParameters,
+ filterParams
+ );
+ return geoSearchService.getStationsWithinRange(rangeQueryParameters, filterParams);
+ } else {
+ throw new GraphqlErrorException.Builder()
+ .message(
+ "You must either specify lat, lon and range OR minimumLatitude, minimumLongitude, maximumLatitude and maximumLongitude"
+ )
+ .build();
+ }
+ }
- return geoSearchService.getStationsNearby(queryParams, filterParams);
+ private boolean isRangeSearch(Double range, Double lat, Double lon) {
+ return range != null && lat != null && lon != null;
+ }
+
+ private boolean isBoundingBoxSearch(
+ Double minimumLatitude,
+ Double minimumLongitude,
+ Double maximumLatitude,
+ Double maximumLongitude
+ ) {
+ return (
+ minimumLatitude != null &&
+ minimumLongitude != null &&
+ maximumLatitude != null &&
+ maximumLongitude != null
+ );
}
public Station getStation(String id) {
diff --git a/src/main/java/org/entur/lamassu/service/BoundingBoxQueryParameters.java b/src/main/java/org/entur/lamassu/service/BoundingBoxQueryParameters.java
new file mode 100644
index 00000000..b4163cb5
--- /dev/null
+++ b/src/main/java/org/entur/lamassu/service/BoundingBoxQueryParameters.java
@@ -0,0 +1,59 @@
+/*
+ *
+ *
+ * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by
+ * * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * * You may not use this work except in compliance with the Licence.
+ * * You may obtain a copy of the Licence at:
+ * *
+ * * https://joinup.ec.europa.eu/software/page/eupl
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the Licence is distributed on an "AS IS" basis,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the Licence for the specific language governing permissions and
+ * * limitations under the Licence.
+ *
+ */
+
+package org.entur.lamassu.service;
+
+public class BoundingBoxQueryParameters {
+
+ private Double minimumLatitude;
+ private Double minimumLongitude;
+ private Double maximumLatitude;
+ private Double maximumLongitude;
+
+ public Double getMinimumLatitude() {
+ return minimumLatitude;
+ }
+
+ public void setMinimumLatitude(Double minimumLatitude) {
+ this.minimumLatitude = minimumLatitude;
+ }
+
+ public Double getMinimumLongitude() {
+ return minimumLongitude;
+ }
+
+ public void setMinimumLongitude(Double minimumLongitude) {
+ this.minimumLongitude = minimumLongitude;
+ }
+
+ public Double getMaximumLatitude() {
+ return maximumLatitude;
+ }
+
+ public void setMaximumLatitude(Double maximumLatitude) {
+ this.maximumLatitude = maximumLatitude;
+ }
+
+ public Double getMaximumLongitude() {
+ return maximumLongitude;
+ }
+
+ public void setMaximumLongitude(Double maximumLongitude) {
+ this.maximumLongitude = maximumLongitude;
+ }
+}
diff --git a/src/main/java/org/entur/lamassu/service/FilterParameters.java b/src/main/java/org/entur/lamassu/service/FilterParameters.java
index 5307904a..a006a6bd 100644
--- a/src/main/java/org/entur/lamassu/service/FilterParameters.java
+++ b/src/main/java/org/entur/lamassu/service/FilterParameters.java
@@ -25,6 +25,7 @@ public class FilterParameters {
private List codespaces;
private List systems;
private List operators;
+ private Integer count;
public List getCodespaces() {
return codespaces;
@@ -49,4 +50,12 @@ public List getOperators() {
public void setOperators(List operators) {
this.operators = operators;
}
+
+ public Integer getCount() {
+ return count;
+ }
+
+ public void setCount(Integer count) {
+ this.count = count;
+ }
}
diff --git a/src/main/java/org/entur/lamassu/service/GeoSearchService.java b/src/main/java/org/entur/lamassu/service/GeoSearchService.java
index 0eb66b9f..9342fc6e 100644
--- a/src/main/java/org/entur/lamassu/service/GeoSearchService.java
+++ b/src/main/java/org/entur/lamassu/service/GeoSearchService.java
@@ -6,14 +6,22 @@
import org.entur.lamassu.model.entities.Vehicle;
public interface GeoSearchService {
- List getVehiclesNearby(
+ List getVehiclesWithinRange(
RangeQueryParameters rangeQueryParameters,
VehicleFilterParameters vehicleFilterParameters
);
- List getStationsNearby(
+ List getVehiclesInBoundingBox(
+ BoundingBoxQueryParameters boundingBoxQueryParameters,
+ VehicleFilterParameters vehicleFilterParameters
+ );
+ List getStationsWithinRange(
RangeQueryParameters rangeQueryParameters,
StationFilterParameters stationFilterParameters
);
+ List getStationsInBoundingBox(
+ BoundingBoxQueryParameters boundingBoxQueryParameters,
+ StationFilterParameters stationFilterParameters
+ );
Collection getVehicleSpatialIndexOrphans();
Collection removeVehicleSpatialIndexOrphans();
}
diff --git a/src/main/java/org/entur/lamassu/service/RangeQueryParameters.java b/src/main/java/org/entur/lamassu/service/RangeQueryParameters.java
index a35a7a1f..70aa914e 100644
--- a/src/main/java/org/entur/lamassu/service/RangeQueryParameters.java
+++ b/src/main/java/org/entur/lamassu/service/RangeQueryParameters.java
@@ -5,7 +5,6 @@ public class RangeQueryParameters {
private Double lat;
private Double lon;
private Double range;
- private Integer count;
public Double getLat() {
return lat;
@@ -30,12 +29,4 @@ public Double getRange() {
public void setRange(Double range) {
this.range = range;
}
-
- public Integer getCount() {
- return count;
- }
-
- public void setCount(Integer count) {
- this.count = count;
- }
}
diff --git a/src/main/java/org/entur/lamassu/service/impl/GeoSearchServiceImpl.java b/src/main/java/org/entur/lamassu/service/impl/GeoSearchServiceImpl.java
index 48298b98..99ef1a61 100644
--- a/src/main/java/org/entur/lamassu/service/impl/GeoSearchServiceImpl.java
+++ b/src/main/java/org/entur/lamassu/service/impl/GeoSearchServiceImpl.java
@@ -13,11 +13,13 @@
import org.entur.lamassu.cache.VehicleSpatialIndexId;
import org.entur.lamassu.model.entities.Station;
import org.entur.lamassu.model.entities.Vehicle;
+import org.entur.lamassu.service.BoundingBoxQueryParameters;
import org.entur.lamassu.service.GeoSearchService;
import org.entur.lamassu.service.RangeQueryParameters;
import org.entur.lamassu.service.StationFilterParameters;
import org.entur.lamassu.service.VehicleFilterParameters;
import org.entur.lamassu.util.SpatialIndexIdFilter;
+import org.geotools.geometry.jts.ReferencedEnvelope;
import org.redisson.api.GeoOrder;
import org.redisson.api.GeoUnit;
import org.springframework.beans.factory.annotation.Autowired;
@@ -45,14 +47,13 @@ public GeoSearchServiceImpl(
}
@Override
- public List getVehiclesNearby(
+ public List getVehiclesWithinRange(
RangeQueryParameters rangeQueryParameters,
VehicleFilterParameters vehicleFilterParameters
) {
Double longitude = rangeQueryParameters.getLon();
Double latitude = rangeQueryParameters.getLat();
Double range = rangeQueryParameters.getRange();
- Integer count = rangeQueryParameters.getCount();
List indexIds = vehicleSpatialIndex.radius(
longitude,
@@ -67,6 +68,8 @@ public List getVehiclesNearby(
.filter(Objects::nonNull)
.filter(id -> SpatialIndexIdFilter.filterVehicle(id, vehicleFilterParameters));
+ Integer count = vehicleFilterParameters.getCount();
+
if (count != null) {
stream = stream.limit(count.longValue());
}
@@ -79,14 +82,34 @@ public List getVehiclesNearby(
}
@Override
- public List getStationsNearby(
+ public List getVehiclesInBoundingBox(
+ BoundingBoxQueryParameters boundingBoxQueryParameters,
+ VehicleFilterParameters vehicleFilterParameters
+ ) {
+ ReferencedEnvelope envelope = GeoUtils.mapToEnvelope(boundingBoxQueryParameters);
+ RangeQueryParameters rangeQueryParameters = GeoUtils.mapToRangeQueryParameters(
+ envelope
+ );
+
+ List vehicles = getVehiclesWithinRange(
+ rangeQueryParameters,
+ vehicleFilterParameters
+ );
+
+ return vehicles
+ .stream()
+ .filter(vehicle -> envelope.contains(vehicle.getLon(), vehicle.getLat()))
+ .toList();
+ }
+
+ @Override
+ public List getStationsWithinRange(
RangeQueryParameters rangeQueryParameters,
StationFilterParameters filterParameters
) {
Double longitude = rangeQueryParameters.getLon();
Double latitude = rangeQueryParameters.getLat();
Double range = rangeQueryParameters.getRange();
- Integer count = rangeQueryParameters.getCount();
List indexIds = stationSpatialIndex.radius(
longitude,
@@ -101,6 +124,8 @@ public List getStationsNearby(
.filter(Objects::nonNull)
.filter(id -> SpatialIndexIdFilter.filterStation(id, filterParameters));
+ Integer count = filterParameters.getCount();
+
if (count != null) {
stream = stream.limit(count.longValue());
}
@@ -112,6 +137,25 @@ public List getStationsNearby(
return stationCache.getAll(stationIds);
}
+ @Override
+ public List getStationsInBoundingBox(
+ BoundingBoxQueryParameters boundingBoxQueryParameters,
+ StationFilterParameters stationFilterParameters
+ ) {
+ ReferencedEnvelope envelope = GeoUtils.mapToEnvelope(boundingBoxQueryParameters);
+ RangeQueryParameters rangeQueryParameters = GeoUtils.mapToRangeQueryParameters(
+ envelope
+ );
+ List stations = getStationsWithinRange(
+ rangeQueryParameters,
+ stationFilterParameters
+ );
+ return stations
+ .stream()
+ .filter(station -> envelope.contains(station.getLon(), station.getLat()))
+ .toList();
+ }
+
@Override
public Collection getVehicleSpatialIndexOrphans() {
var indexIds = vehicleSpatialIndex.getAll();
diff --git a/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java
new file mode 100644
index 00000000..a3fae703
--- /dev/null
+++ b/src/main/java/org/entur/lamassu/service/impl/GeoUtils.java
@@ -0,0 +1,151 @@
+/*
+ *
+ *
+ * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by
+ * * the European Commission - subsequent versions of the EUPL (the "Licence");
+ * * You may not use this work except in compliance with the Licence.
+ * * You may obtain a copy of the Licence at:
+ * *
+ * * https://joinup.ec.europa.eu/software/page/eupl
+ * *
+ * * Unless required by applicable law or agreed to in writing, software
+ * * distributed under the Licence is distributed on an "AS IS" basis,
+ * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * * See the Licence for the specific language governing permissions and
+ * * limitations under the Licence.
+ *
+ */
+
+package org.entur.lamassu.service.impl;
+
+import org.apache.commons.pool.BasePoolableObjectFactory;
+import org.apache.commons.pool.PoolableObjectFactory;
+import org.apache.commons.pool.impl.GenericObjectPool;
+import org.entur.lamassu.service.BoundingBoxQueryParameters;
+import org.entur.lamassu.service.RangeQueryParameters;
+import org.geotools.geometry.jts.JTS;
+import org.geotools.geometry.jts.ReferencedEnvelope;
+import org.geotools.referencing.GeodeticCalculator;
+import org.geotools.referencing.crs.DefaultGeographicCRS;
+import org.jetbrains.annotations.NotNull;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.CoordinateXY;
+
+public class GeoUtils {
+
+ private GeoUtils() {}
+
+ /**
+ * Map the bounding box parameters to a geometric envelope
+ * @param boundingBoxQueryParameters
+ * @return
+ */
+ public static @NotNull ReferencedEnvelope mapToEnvelope(
+ BoundingBoxQueryParameters boundingBoxQueryParameters
+ ) {
+ return new ReferencedEnvelope(
+ boundingBoxQueryParameters.getMinimumLongitude(),
+ boundingBoxQueryParameters.getMaximumLongitude(),
+ boundingBoxQueryParameters.getMinimumLatitude(),
+ boundingBoxQueryParameters.getMaximumLatitude(),
+ DefaultGeographicCRS.WGS84
+ );
+ }
+
+ /**
+ * Uses the center of the envelope, and the radius of the circle the encloses the envelope to
+ * define the coordinates and range of the range query parameters.
+ * @param envelope
+ * @return
+ */
+ public static @NotNull RangeQueryParameters mapToRangeQueryParameters(
+ ReferencedEnvelope envelope
+ ) {
+ RangeQueryParameters rangeQueryParameters = new RangeQueryParameters();
+
+ // The center of the circle that encloses the envelope is equal to the center
+ // of the envelope itself
+ rangeQueryParameters.setLon(envelope.getCenterX());
+ rangeQueryParameters.setLat(envelope.getCenterY());
+
+ // The diameter of the circle that encloses the envelope is equal to the length
+ // of the diagonal of the envelope, hence half this length equals the circle's radius
+ rangeQueryParameters.setRange(getDiagonalLength(envelope) / 2.0);
+ return rangeQueryParameters;
+ }
+
+ /**
+ * Find the great circle distance between the southwest and northeast corners of the envelope,
+ * which we called the diagonal length of the envelope.
+ * @param envelope
+ * @return
+ */
+ private static double getDiagonalLength(ReferencedEnvelope envelope) {
+ GeodeticCalculator geodeticCalculator = null;
+ try {
+ geodeticCalculator = GeodeticCalculatorPoolManager.getInstance().get();
+ Coordinate start = new CoordinateXY(envelope.getMinX(), envelope.getMinY());
+ Coordinate end = new CoordinateXY(envelope.getMaxX(), envelope.getMaxY());
+ geodeticCalculator.setStartingPosition(
+ JTS.toDirectPosition(start, DefaultGeographicCRS.WGS84)
+ );
+ geodeticCalculator.setDestinationPosition(
+ JTS.toDirectPosition(end, DefaultGeographicCRS.WGS84)
+ );
+ return geodeticCalculator.getOrthodromicDistance();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IllegalStateException(
+ "Unable to calculate diagonal length of envelope",
+ e
+ );
+ } catch (Exception e) {
+ throw new IllegalStateException(
+ "Unable to calculate diagonal length of envelope",
+ e
+ );
+ } finally {
+ GeodeticCalculatorPoolManager.getInstance().release(geodeticCalculator);
+ }
+ }
+
+ private static class GeodeticCalculatorPoolManager {
+
+ // pool size can be high, purpose is to not share instances between threads
+ private static final int POOL_SIZE = 100;
+ private static final GeodeticCalculatorPoolManager INSTANCE =
+ new GeodeticCalculatorPoolManager();
+
+ private final GenericObjectPool pool;
+
+ private GeodeticCalculatorPoolManager() {
+ GenericObjectPool.Config config = new GenericObjectPool.Config();
+ config.maxActive = POOL_SIZE;
+ PoolableObjectFactory geodeticCalculatorFactory =
+ new BasePoolableObjectFactory<>() {
+ @Override
+ public GeodeticCalculator makeObject() {
+ return new GeodeticCalculator(DefaultGeographicCRS.WGS84);
+ }
+ };
+
+ pool = new GenericObjectPool<>(geodeticCalculatorFactory, config);
+ }
+
+ public static GeodeticCalculatorPoolManager getInstance() {
+ return INSTANCE;
+ }
+
+ private GeodeticCalculator get() throws Exception {
+ return pool.borrowObject();
+ }
+
+ private void release(GeodeticCalculator gc) {
+ try {
+ pool.returnObject(gc);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
diff --git a/src/main/resources/graphql/schema.graphqls b/src/main/resources/graphql/schema.graphqls
index f1fbbd06..145eb18a 100644
--- a/src/main/resources/graphql/schema.graphqls
+++ b/src/main/resources/graphql/schema.graphqls
@@ -18,6 +18,18 @@ type Query {
"Search radius in meters. Required unless using 'ids'"
range: Int
+ "Bounding box minimum latitude"
+ minimumLatitude: Float
+
+ "Bounding box minimum longitude"
+ minimumLongitude: Float
+
+ "Bounding box maximum latitude"
+ maximumLatitude: Float
+
+ "Bounding box maximum longitude"
+ maximumLongitude: Float
+
"Max results to return."
count: Int
@@ -58,6 +70,18 @@ type Query {
"Search radius in meters. Required unless using 'ids'"
range: Int
+ "Bounding box minimum latitude"
+ minimumLatitude: Float
+
+ "Bounding box minimum longitude"
+ minimumLongitude: Float
+
+ "Bounding box maximum latitude"
+ maximumLatitude: Float
+
+ "Bounding box maximum longitude"
+ maximumLongitude: Float
+
"Max results to return."
count: Int
diff --git a/src/test/java/org/entur/lamassu/integration/GraphQLIntegrationTest.java b/src/test/java/org/entur/lamassu/integration/GraphQLIntegrationTest.java
index bbeb775a..394ecb0b 100644
--- a/src/test/java/org/entur/lamassu/integration/GraphQLIntegrationTest.java
+++ b/src/test/java/org/entur/lamassu/integration/GraphQLIntegrationTest.java
@@ -178,4 +178,35 @@ public void testUnknownOperatorDoesNotThrow() throws IOException {
.isEmpty()
);
}
+
+ @Test
+ public void testVehiclesBoundingBoxQuery() throws IOException {
+ GraphQLResponse response = graphQLTestTemplate.postForResource(
+ "vehicles_bbox_query.graphql"
+ );
+ assertEquals(HttpStatus.OK, response.getStatusCode());
+
+ assertEquals(
+ 2,
+ JsonPath
+ .parse(response.getRawResponse().getBody())
+ .read("$.data.vehicles", List.class)
+ .size()
+ );
+ }
+
+ @Test
+ public void testStationsBoundingBoxQuery() throws IOException {
+ GraphQLResponse response = graphQLTestTemplate.postForResource(
+ "stations_bbox_query.graphql"
+ );
+ assertEquals(HttpStatus.OK, response.getStatusCode());
+ assertEquals(
+ 1,
+ JsonPath
+ .parse(response.getRawResponse().getBody())
+ .read("$.data.stations", List.class)
+ .size()
+ );
+ }
}
diff --git a/src/test/resources/stations_bbox_query.graphql b/src/test/resources/stations_bbox_query.graphql
new file mode 100644
index 00000000..afe332c4
--- /dev/null
+++ b/src/test/resources/stations_bbox_query.graphql
@@ -0,0 +1,14 @@
+{
+ stations(
+ minimumLongitude: 44.0,
+ minimumLatitude: 11.0,
+ maximumLongitude: 45.0
+ maximumLatitude: 12.0
+ count: 1
+ ) {
+ id
+ lat
+ lon
+ }
+}
+,
diff --git a/src/test/resources/vehicles_bbox_query.graphql b/src/test/resources/vehicles_bbox_query.graphql
new file mode 100644
index 00000000..643a323d
--- /dev/null
+++ b/src/test/resources/vehicles_bbox_query.graphql
@@ -0,0 +1,14 @@
+{
+ vehicles(
+ minimumLongitude: 10.0,
+ minimumLatitude: 59.0,
+ maximumLongitude: 11.0
+ maximumLatitude: 60.0
+ count: 2,
+ includeDisabled: true
+ ) {
+ id
+ lat
+ lon
+ }
+}