Pārlūkot izejas kodu

Added API 'eventIdObservationsGET'

Lukas Cerny 1 gadu atpakaļ
vecāks
revīzija
f0ad3a5225

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

@@ -730,6 +730,70 @@ public class MapLogRepository implements SensLogRepository {
     }
 
     @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(
             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
+    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) {
         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<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<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("eventIdGET").handler(apiHandler::eventIdGET);
+                    openAPIRouterBuilder.operation("eventIdObservationsGET").handler(apiHandler::eventIdObservationsGET);
 
 
                     Router mainRouter = openAPIRouterBuilder.createRouter();

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

@@ -1079,4 +1079,81 @@ public class OpenAPIHandler {
                         )).encode())
                         .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'
 
   /drivers/{driverId}/units/{unitId}/actions/{actionId}/events:
-    get:
+    get: # done
       operationId: driverIdUnitIdActionIdEventsGET
       summary: Publish basic info about events that where performed on the unit byt the driver with the specific action
       parameters:
@@ -776,7 +776,7 @@ paths:
 
 
   /events/{eventId}:
-    get:
+    get: # done
       operationId: eventIdGET
       summary: Publish basic info about events that where performed on the unit byt the driver with the specific action
       parameters:
@@ -802,9 +802,6 @@ paths:
       operationId: eventIdObservationsGET
       summary: Publish telemetry observations created by the driver while performing specific action on the unit at the time/event
       parameters:
-        - $ref: '#/components/parameters/driverIdParam'
-        - $ref: '#/components/parameters/unitIdParam'
-        - $ref: '#/components/parameters/actionIdParam'
         - $ref: '#/components/parameters/eventIdParam'
         - $ref: '#/components/parameters/zoneParam'
         - $ref: '#/components/parameters/offsetParam'
@@ -829,9 +826,6 @@ paths:
       operationId: eventIdLocationsGET
       summary: Publish locations created by the driver while performing specific action on the unit at the time/event
       parameters:
-        - $ref: '#/components/parameters/driverIdParam'
-        - $ref: '#/components/parameters/unitIdParam'
-        - $ref: '#/components/parameters/actionIdParam'
         - $ref: '#/components/parameters/eventIdParam'
         - $ref: '#/components/parameters/fromParam'
         - $ref: '#/components/parameters/toParam'
@@ -1467,12 +1461,12 @@ components:
           type: string
           format: uri
           x-graph-properties:
-            linkTo: driverIdUnitIdActionIdEventIdGET
+            linkTo: eventIdGET
         next@NavigationLink:
           type: string
           format: uri
           x-graph-properties:
-            linkTo: driverIdUnitIdActionIdEventIdObservationsGET
+            linkTo: eventIdObservationsGET
       properties:
         Event@NavigationLink:
           $ref: '#/components/schemas/ActionEventObservation/x-NavigationLinks/Event@NavigationLink'
@@ -1492,8 +1486,8 @@ components:
           items:
             $ref: '#/components/schemas/UnitDataObservation'
       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: []
         size: 500
         hasNext: true