浏览代码

Added API 'eventIdObservationsGET'

Lukas Cerny 1 年之前
父节点
当前提交
f0ad3a5225

+ 64 - 0
src/main/java/cz/senslog/telemetry/database/repository/MapLogRepository.java

@@ -730,6 +730,70 @@ public class MapLogRepository implements SensLogRepository {
     }
     }
 
 
     @Override
     @Override
+    public Future<List<UnitTelemetry>> findObservationsByEventId(
+            long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit
+    ) {
+
+        String whereTimestampClause;
+        Tuple tupleParams;
+        if (from != null && to != null) {
+            whereTimestampClause = "tel.time_stamp >= (CASE WHEN $5 < dta.from_time THEN $5 ELSE dta.from_time END) AND tel.time_stamp <= (CASE WHEN dta.to_time IS NULL OR $6 < dta.to_time THEN $6 ELSE dta.to_time END)";
+            tupleParams = Tuple.of(eventId, offset, limit, zone.getId(), from, to);
+        } else if (from != null) {
+            whereTimestampClause = "tel.time_stamp >= (CASE WHEN $5 < dta.from_time THEN $5 ELSE dta.from_time END) AND tel.time_stamp <= (CASE WHEN dta.to_time IS NULL THEN now() ELSE dta.to_time END)";
+            tupleParams = Tuple.of(eventId, offset, limit, zone.getId(), from);
+        } else if (to != null) {
+            whereTimestampClause = "tel.time_stamp >= dta.from_time AND tel.time_stamp <= (CASE WHEN dta.to_time IS NULL OR $5 < dta.to_time THEN $5 ELSE dta.to_time END)";
+            tupleParams = Tuple.of(eventId, offset, limit, zone.getId(), to);
+        } else {
+            whereTimestampClause = "tel.time_stamp >= dta.from_time AND tel.time_stamp <= (CASE WHEN dta.to_time IS NULL THEN now() ELSE dta.to_time END)";
+            tupleParams = Tuple.of(eventId, offset, limit, zone.getId());
+        }
+
+        String sql = "SELECT tel.obs_id, tel.unit_id, tel.observed_values::json, tel.speed, " +
+                        "tel.time_stamp, $4 AS zone_id, " + // ::timestamp with time zone at time zone $4 AS time_stamp
+                        "ST_X (ST_Transform (tel.the_geom, 4326)) AS long, " +
+                        "ST_Y (ST_Transform (tel.the_geom, 4326)) AS lat, " +
+                        "ST_Z (ST_Transform (tel.the_geom, 4326)) AS alt, " +
+                        "ST_M (tel.the_geom) AS angle " +
+                        "FROM maplog.obs_telemetry AS tel " +
+                    "JOIN maplog.driver_to_action dta on tel.unit_id = dta.unit_id " +
+                "WHERE dta.id = $1 AND " + whereTimestampClause + " " +
+                "ORDER BY tel.time_stamp OFFSET $2 LIMIT $3";
+
+        return client.preparedQuery(sql)
+                .execute(tupleParams)
+                .map(rs -> StreamSupport.stream(rs.spliterator(), false)
+                        .map(r -> UnitTelemetry.of(
+                                r.getLong("obs_id"),
+                                r.getLong("unit_id"),
+                                r.getOffsetDateTime("time_stamp"),
+                                Location.of(
+                                        r.getFloat("long"),
+                                        r.getFloat("lat"),
+                                        r.getFloat("alt"),
+                                        r.getFloat("angle")),
+                                r.getFloat("speed"),
+                                r.getJsonObject("observed_values")))
+                        .collect(Collectors.toList()))
+                .onFailure(logger::catching);
+    }
+
+    @Override
+    public Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByEventIdWithPaging(
+            long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit
+    ) {
+        return findObservationsByEventId(eventId, from, to, zone, offset, limit+1)
+                .map(data -> {
+                    boolean hasNext = data.size() > limit;
+                    if (hasNext) {
+                        data.remove(data.size() - 1);
+                    }
+                    return new PagingRetrieve<>(hasNext, data.size(), data);
+                });
+    }
+
+    @Override
     public Future<List<SensorTelemetry>> findObservationsByCampaignIdAndUnitIdAndSensorId(
     public Future<List<SensorTelemetry>> findObservationsByCampaignIdAndUnitIdAndSensorId(
             long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit
             long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit
     ) {
     ) {

+ 10 - 0
src/main/java/cz/senslog/telemetry/database/repository/MockMapLogRepository.java

@@ -106,6 +106,16 @@ public class MockMapLogRepository implements SensLogRepository {
     }
     }
 
 
     @Override
     @Override
+    public Future<List<UnitTelemetry>> findObservationsByEventId(long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit) {
+        return Future.succeededFuture(Collections.emptyList());
+    }
+
+    @Override
+    public Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByEventIdWithPaging(long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit) {
+        return Future.succeededFuture(new PagingRetrieve<>(false, 0, Collections.emptyList()));
+    }
+
+    @Override
     public Future<List<SensorTelemetry>> findObservationsByCampaignIdAndUnitIdAndSensorId(long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit) {
     public Future<List<SensorTelemetry>> findObservationsByCampaignIdAndUnitIdAndSensorId(long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit) {
         return Future.succeededFuture(Collections.emptyList());
         return Future.succeededFuture(Collections.emptyList());
     }
     }

+ 3 - 0
src/main/java/cz/senslog/telemetry/database/repository/SensLogRepository.java

@@ -68,6 +68,9 @@ public interface SensLogRepository {
     Future<List<UnitTelemetry>> findObservationsByCampaignIdAndUnitId(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit);
     Future<List<UnitTelemetry>> findObservationsByCampaignIdAndUnitId(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit);
     Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByCampaignIdAndUnitIdWithPaging(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit);
     Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByCampaignIdAndUnitIdWithPaging(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit);
 
 
+    Future<List<UnitTelemetry>> findObservationsByEventId(long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit);
+    Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByEventIdWithPaging(long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit);
+
     Future<List<SensorTelemetry>> findObservationsByCampaignIdAndUnitIdAndSensorId(long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit);
     Future<List<SensorTelemetry>> findObservationsByCampaignIdAndUnitIdAndSensorId(long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit);
     Future<PagingRetrieve<List<SensorTelemetry>>> findObservationsByCampaignIdAndUnitIdAndSensorIdWithPaging(long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit);
     Future<PagingRetrieve<List<SensorTelemetry>>> findObservationsByCampaignIdAndUnitIdAndSensorIdWithPaging(long campaignId, long unitId, long sensorId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit);
 
 

+ 1 - 0
src/main/java/cz/senslog/telemetry/server/HttpVertxServer.java

@@ -91,6 +91,7 @@ public final class HttpVertxServer extends AbstractVerticle {
                     openAPIRouterBuilder.operation("driverIdUnitIdActionIdEventsGET").handler(apiHandler::driverIdUnitIdActionIdEventsGET);
                     openAPIRouterBuilder.operation("driverIdUnitIdActionIdEventsGET").handler(apiHandler::driverIdUnitIdActionIdEventsGET);
 
 
                     openAPIRouterBuilder.operation("eventIdGET").handler(apiHandler::eventIdGET);
                     openAPIRouterBuilder.operation("eventIdGET").handler(apiHandler::eventIdGET);
+                    openAPIRouterBuilder.operation("eventIdObservationsGET").handler(apiHandler::eventIdObservationsGET);
 
 
 
 
                     Router mainRouter = openAPIRouterBuilder.createRouter();
                     Router mainRouter = openAPIRouterBuilder.createRouter();

+ 77 - 0
src/main/java/cz/senslog/telemetry/server/OpenAPIHandler.java

@@ -1079,4 +1079,81 @@ public class OpenAPIHandler {
                         )).encode())
                         )).encode())
                         .onFailure(th -> rc.fail(400, th)));
                         .onFailure(th -> rc.fail(400, th)));
     }
     }
+
+    public void eventIdObservationsGET(RoutingContext rc) {
+        String host =  hostURLFull(rc.request());
+        JsonObject paramsJson = new JsonObject();
+
+        int eventId = Integer.parseInt(rc.pathParam("eventId"));
+
+        List<String> paramFrom = rc.queryParam("from");
+        OffsetDateTime from = TernaryCondition.<OffsetDateTime>ternaryIf(paramFrom::isEmpty, () -> null, () -> {
+            paramsJson.put("from", paramFrom.get(0));
+            return OffsetDateTime.parse(paramFrom.get(0));
+        });
+
+        List<String> paramTo = rc.queryParam("to");
+        OffsetDateTime to = TernaryCondition.<OffsetDateTime>ternaryIf(paramTo::isEmpty, () -> null,() -> {
+            paramsJson.put("to", paramTo.get(0));
+            return OffsetDateTime.parse(paramTo.get(0));
+        });
+
+        List<String> paramZone = rc.queryParam("zone");
+        ZoneId zone = TernaryCondition.<ZoneId>ternaryIf(paramZone::isEmpty, ZoneId.of("UTC"), () -> {
+            paramsJson.put("zone", paramZone.get(0));
+            return ZoneId.of(paramZone.get(0));
+        });
+
+        List<String> paramOffset = rc.queryParam("offset");
+        int offset = TernaryCondition.<Integer>ternaryIf(paramOffset::isEmpty, 0, () -> {
+            paramsJson.put("offset", paramOffset.get(0));
+            return Integer.parseInt(paramOffset.get(0));
+        });
+
+        List<String> paramLimit = rc.queryParam("limit");
+        int limit = TernaryCondition.<Integer>ternaryIf(paramLimit::isEmpty, DEFAULT_MAX_DATA_LIMIT, () -> {
+            paramsJson.put("limit", paramLimit.get(0));
+            return Integer.parseInt(paramLimit.get(0));
+        });
+
+        List<String> paramNavigationLinks = rc.queryParam("navigationLinks");
+        boolean navigationLinks = TernaryCondition.<Boolean>ternaryIf(paramNavigationLinks::isEmpty, true, () -> {
+            paramsJson.put("navigationLinks", paramNavigationLinks.get(0));
+            return parseBoolean(paramNavigationLinks.get(0));
+        });
+
+        JsonObject navLinks = navigationLinks ? JsonObject.of(
+                "Event@NavigationLink", String.format("%s/events/%d", host, eventId)
+        ) : JsonObject.of();
+
+        Function<Long, String> createNextNavLink = dataSize -> {
+            String urlParams = paramsJson.stream()
+                    .filter(e -> !e.getKey().equals("offset"))
+                    .map(e -> String.format("%s=%s", e.getKey(), e.getValue()))
+                    .collect(Collectors.joining("&"));
+            long newOffset = offset + dataSize;
+            return String.format("%s/events/%d/observations?offset=%d%s", host, eventId, newOffset, (urlParams.isEmpty() ? "" : "&"+urlParams));
+        };
+
+        repo.findObservationsByEventIdWithPaging(eventId, from, to, zone, offset, limit)
+                .onSuccess(paging -> rc.response().end(navLinks.mergeIn(navigationLinks && paging.hasNext() ? JsonObject.of(
+                        "next@NavigationLink", createNextNavLink.apply(paging.size())
+                ) : JsonObject.of()).mergeIn(JsonObject.of(
+                        "params", paramsJson,
+                        "size", paging.size(),
+                        "offset", offset,
+                        "hasNext", paging.hasNext(),
+                        "data", new JsonArray(
+                                paging.data().stream().map(o -> JsonObject.of(
+                                        "timestamp", OffsetDateTime.ofInstant(o.getTimestamp().toInstant(), zone).format(ISO_OFFSET_DATE_TIME),
+                                        "speed", o.getSpeed(),
+                                        "location", JsonObject.of(
+                                                "longitude", o.getLocation().getLongitude(),
+                                                "latitude", o.getLocation().getLatitude(),
+                                                "altitude", o.getLocation().getAltitude()),
+                                        "observedValues", o.getObservedValues()
+                                )).collect(toList()))
+                )).encode()))
+                .onFailure(th -> rc.fail(400, th));
+    }
 }
 }

+ 6 - 12
src/main/resources/openAPISpec.yaml

@@ -749,7 +749,7 @@ paths:
                 $ref: '#/components/schemas/Error'
                 $ref: '#/components/schemas/Error'
 
 
   /drivers/{driverId}/units/{unitId}/actions/{actionId}/events:
   /drivers/{driverId}/units/{unitId}/actions/{actionId}/events:
-    get:
+    get: # done
       operationId: driverIdUnitIdActionIdEventsGET
       operationId: driverIdUnitIdActionIdEventsGET
       summary: Publish basic info about events that where performed on the unit byt the driver with the specific action
       summary: Publish basic info about events that where performed on the unit byt the driver with the specific action
       parameters:
       parameters:
@@ -776,7 +776,7 @@ paths:
 
 
 
 
   /events/{eventId}:
   /events/{eventId}:
-    get:
+    get: # done
       operationId: eventIdGET
       operationId: eventIdGET
       summary: Publish basic info about events that where performed on the unit byt the driver with the specific action
       summary: Publish basic info about events that where performed on the unit byt the driver with the specific action
       parameters:
       parameters:
@@ -802,9 +802,6 @@ paths:
       operationId: eventIdObservationsGET
       operationId: eventIdObservationsGET
       summary: Publish telemetry observations created by the driver while performing specific action on the unit at the time/event
       summary: Publish telemetry observations created by the driver while performing specific action on the unit at the time/event
       parameters:
       parameters:
-        - $ref: '#/components/parameters/driverIdParam'
-        - $ref: '#/components/parameters/unitIdParam'
-        - $ref: '#/components/parameters/actionIdParam'
         - $ref: '#/components/parameters/eventIdParam'
         - $ref: '#/components/parameters/eventIdParam'
         - $ref: '#/components/parameters/zoneParam'
         - $ref: '#/components/parameters/zoneParam'
         - $ref: '#/components/parameters/offsetParam'
         - $ref: '#/components/parameters/offsetParam'
@@ -829,9 +826,6 @@ paths:
       operationId: eventIdLocationsGET
       operationId: eventIdLocationsGET
       summary: Publish locations created by the driver while performing specific action on the unit at the time/event
       summary: Publish locations created by the driver while performing specific action on the unit at the time/event
       parameters:
       parameters:
-        - $ref: '#/components/parameters/driverIdParam'
-        - $ref: '#/components/parameters/unitIdParam'
-        - $ref: '#/components/parameters/actionIdParam'
         - $ref: '#/components/parameters/eventIdParam'
         - $ref: '#/components/parameters/eventIdParam'
         - $ref: '#/components/parameters/fromParam'
         - $ref: '#/components/parameters/fromParam'
         - $ref: '#/components/parameters/toParam'
         - $ref: '#/components/parameters/toParam'
@@ -1467,12 +1461,12 @@ components:
           type: string
           type: string
           format: uri
           format: uri
           x-graph-properties:
           x-graph-properties:
-            linkTo: driverIdUnitIdActionIdEventIdGET
+            linkTo: eventIdGET
         next@NavigationLink:
         next@NavigationLink:
           type: string
           type: string
           format: uri
           format: uri
           x-graph-properties:
           x-graph-properties:
-            linkTo: driverIdUnitIdActionIdEventIdObservationsGET
+            linkTo: eventIdObservationsGET
       properties:
       properties:
         Event@NavigationLink:
         Event@NavigationLink:
           $ref: '#/components/schemas/ActionEventObservation/x-NavigationLinks/Event@NavigationLink'
           $ref: '#/components/schemas/ActionEventObservation/x-NavigationLinks/Event@NavigationLink'
@@ -1492,8 +1486,8 @@ components:
           items:
           items:
             $ref: '#/components/schemas/UnitDataObservation'
             $ref: '#/components/schemas/UnitDataObservation'
       example:
       example:
-        Event@NavigationLink: "<domain>/drivers/42/units/105/actions/258/events/999"
-        next@NavigationLink: "<domain>/drivers/42/units/25/actions/258/events/999/observations?offset=500"
+        Event@NavigationLink: "<domain>/events/999"
+        next@NavigationLink: "<domain>/events/999/observations?offset=500"
         params: []
         params: []
         size: 500
         size: 500
         hasNext: true
         hasNext: true