Bladeren bron

Added API 'eventIdLocationsGET'

Lukas Cerny 1 jaar geleden
bovenliggende
commit
22a98c38bd

+ 67 - 9
src/main/java/cz/senslog/telemetry/database/repository/MapLogRepository.java

@@ -733,7 +733,6 @@ public class MapLogRepository implements SensLogRepository {
     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) {
@@ -877,14 +876,14 @@ public class MapLogRepository implements SensLogRepository {
         }
 
         String sql = "SELECT tel.unit_id, tel.time_stamp, $5 AS zone_id, " + // ::timestamp with time zone at time zone $5 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 " +
-                "FROM maplog.obs_telemetry AS tel " +
-                "JOIN maplog.unit u on u.unit_id = tel.unit_id " +
-                "JOIN maplog.unit_to_campaign utc on tel.unit_id = utc.unit_id " +
-                "WHERE utc.camp_id = $1 AND utc.unit_id = $2 AND " + whereTimestampClause + " " +
-                "ORDER BY tel.time_stamp OFFSET $3 LIMIT $4;";
+                        "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 " +
+                    "FROM maplog.obs_telemetry AS tel " +
+                    "JOIN maplog.unit u on u.unit_id = tel.unit_id " +
+                    "JOIN maplog.unit_to_campaign utc on tel.unit_id = utc.unit_id " +
+                    "WHERE utc.camp_id = $1 AND utc.unit_id = $2 AND " + whereTimestampClause + " " +
+                    "ORDER BY tel.time_stamp OFFSET $3 LIMIT $4;";
 
         return client.preparedQuery(sql)
                 .execute(tupleParams)
@@ -917,6 +916,65 @@ public class MapLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<UnitLocation>> findLocationsByEventId(
+            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.unit_id, 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 " +
+                    "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 -> UnitLocation.of(
+                                r.getLong("unit_id"),
+                                r.getOffsetDateTime("time_stamp"),
+                                Location.of(
+                                        r.getFloat("long"),
+                                        r.getFloat("lat"),
+                                        r.getFloat("alt")
+                                )
+                        ))
+                        .collect(Collectors.toList()))
+                .onFailure(logger::catching);
+    }
+
+    @Override
+    public Future<PagingRetrieve<List<UnitLocation>>> findLocationsByEventIdWithPaging(
+            long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit
+    ) {
+        return findLocationsByEventId(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<UnitLocation>> findUnitsLocationsByCampaignId(
             long campaignId, int limitPerUnit, OffsetDateTime from, OffsetDateTime to, ZoneId zone, SortType sort
     ) {

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

@@ -136,6 +136,16 @@ public class MockMapLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<List<UnitLocation>> findLocationsByEventId(long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit) {
+        return Future.succeededFuture(Collections.emptyList());
+    }
+
+    @Override
+    public Future<PagingRetrieve<List<UnitLocation>>> findLocationsByEventIdWithPaging(long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit) {
+        return Future.succeededFuture(new PagingRetrieve<>(false, 0, Collections.emptyList()));
+    }
+
+    @Override
     public Future<Map<Long, Sensor>> findSensorsByUnitIdGroupById(long unitId) {
         return Future.succeededFuture(Collections.emptyMap());
     }

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

@@ -77,5 +77,8 @@ public interface SensLogRepository {
     Future<List<UnitLocation>> findLocationsByCampaignIdAndUnitId(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit);
     Future<PagingRetrieve<List<UnitLocation>>> findLocationsByCampaignIdAndUnitIdWithPaging(long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit);
 
+    Future<List<UnitLocation>> findLocationsByEventId(long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit);
+    Future<PagingRetrieve<List<UnitLocation>>> findLocationsByEventIdWithPaging(long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit);
+
     Future<List<UnitLocation>> findUnitsLocationsByCampaignId(long campaignId, int limitPerUnit, OffsetDateTime from, OffsetDateTime to, ZoneId zone, SortType sort);
 }

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

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

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

@@ -406,7 +406,7 @@ public class OpenAPIHandler {
                     .map(e -> String.format("%s=%s", e.getKey(), e.getValue()))
                     .collect(Collectors.joining("&"));
             long newOffset = offset + dataSize;
-            return String.format("%s/campaigns/%d/units/%d/observations?offset=%d&%s", host, campaignId, unitId, newOffset, urlParams);
+            return String.format("%s/campaigns/%d/units/%d/observations/locations?offset=%d&%s", host, campaignId, unitId, newOffset, urlParams);
         };
 
         if (filter.isEmpty()) {
@@ -1156,4 +1156,80 @@ public class OpenAPIHandler {
                 )).encode()))
                 .onFailure(th -> rc.fail(400, th));
     }
+
+    public void eventIdLocationsGET(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/locations?offset=%d%s", host, eventId, newOffset, (urlParams.isEmpty() ? "" : "&"+urlParams));
+        };
+
+        repo.findLocationsByEventIdWithPaging(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(l -> JsonObject.of(
+                                        "timestamp", OffsetDateTime.ofInstant(l.getTimestamp().toInstant(), zone).format(ISO_OFFSET_DATE_TIME),
+                                        "location", JsonArray.of(
+                                                l.getLocation().getLongitude(),
+                                                l.getLocation().getLatitude(),
+                                                l.getLocation().getAltitude()
+                                        )
+                                )).collect(toList()))
+                )).encode()))
+                .onFailure(th -> rc.fail(400, th));
+    }
 }

+ 4 - 4
src/main/resources/openAPISpec.yaml

@@ -1716,12 +1716,12 @@ components:
           type: string
           format: uri
           x-graph-properties:
-            linkTo: driverIdUnitIdActionIdEventIdGET
+            linkTo: eventIdGET
         next@NavigationLink:
           type: string
           format: uri
           x-graph-properties:
-            linkTo: driverIdUnitIdActionIdEventIdLocationsGET
+            linkTo: eventIdLocationsGET
       properties:
         Event@NavigationLink:
           $ref: '#/components/schemas/ActionEventLocation/x-NavigationLinks/Event@NavigationLink'
@@ -1750,8 +1750,8 @@ components:
                 items:
                   type: integer
       example:
-        Event@NavigationLink: "<domain>/drivers/42/units/105/actions/258/events/999"
-        next@NavigationLink: "<domain>/drivers/42/units/25/actions/258/events/999/observations/locations?offset=500"
+        Event@NavigationLink: "<domain>/events/999"
+        next@NavigationLink: "<domain>/events/999/observations/locations?offset=500"
         params:
           offset: 0
           limit: 500