浏览代码

Added API 'sensorIdGET'

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

+ 8 - 7
sql/init.sql

@@ -103,26 +103,27 @@ ALTER SEQUENCE maplog.driver_to_action_id_seq OWNED BY maplog.driver_to_action.i
 ALTER TABLE ONLY maplog.driver_to_action ALTER COLUMN id SET DEFAULT nextval('maplog.driver_to_action_id_seq'::regclass);
 
 CREATE TABLE maplog.phenomenon (
-    phenomenon_id INTEGER NOT NULL PRIMARY KEY,
-    phenomenon_name TEXT NOT NULL,
+    id INTEGER NOT NULL PRIMARY KEY,
+    name TEXT NOT NULL,
     uom CHARACTER VARYING(30) NOT NULL,
     uom_link TEXT
 );
 ALTER TABLE maplog.phenomenon OWNER TO senslog;
 
-CREATE SEQUENCE maplog.phenomenon_phenomenon_id_seq AS INTEGER START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
+CREATE SEQUENCE maplog.phenomenon_id_seq AS INTEGER START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1;
 
-ALTER TABLE maplog.phenomenon_phenomenon_id_seq OWNER TO senslog;
+ALTER TABLE maplog.phenomenon_id_seq OWNER TO senslog;
 
-ALTER SEQUENCE maplog.phenomenon_phenomenon_id_seq OWNED BY maplog.phenomenon.phenomenon_id;
+ALTER SEQUENCE maplog.phenomenon_id_seq OWNED BY maplog.phenomenon.id;
 
-ALTER TABLE ONLY maplog.phenomenon ALTER COLUMN phenomenon_id SET DEFAULT nextval('maplog.phenomenon_phenomenon_id_seq'::regclass);
+ALTER TABLE ONLY maplog.phenomenon ALTER COLUMN id SET DEFAULT nextval('maplog.phenomenon_id_seq'::regclass);
 
 
 CREATE TABLE maplog.sensor (
     sensor_id BIGINT NOT NULL PRIMARY KEY,
     sensor_name CHARACTER VARYING(100) UNIQUE NOT NULL,
     sensor_type TEXT,
+    description TEXT,
     io_id INTEGER,
     phenomenon_id INTEGER NOT NULL
 );
@@ -223,7 +224,7 @@ CREATE INDEX fki_dta_unitid_fk ON maplog.driver_to_action USING btree (unit_id);
 
 ALTER TABLE ONLY maplog.obs_telemetry ADD CONSTRAINT obss_unitid_fk FOREIGN KEY (unit_id) REFERENCES maplog.unit(unit_id) ON UPDATE CASCADE ON DELETE CASCADE;
 
-ALTER TABLE ONLY maplog.sensor ADD CONSTRAINT sens_phenom_fk FOREIGN KEY (phenomenon_id) REFERENCES maplog.phenomenon(phenomenon_id);
+ALTER TABLE ONLY maplog.sensor ADD CONSTRAINT sens_phenom_fk FOREIGN KEY (phenomenon_id) REFERENCES maplog.phenomenon(id);
 
 ALTER TABLE ONLY maplog.user_to_campaign ADD CONSTRAINT u2c_campid FOREIGN KEY (campaign_id) REFERENCES maplog.campaign(campaign_id) ON UPDATE CASCADE ON DELETE CASCADE;
 

+ 40 - 0
src/main/java/cz/senslog/telemetry/database/domain/Phenomenon.java

@@ -0,0 +1,40 @@
+package cz.senslog.telemetry.database.domain;
+
+public class Phenomenon {
+
+    private final int id;
+    private final String name;
+    private final String uom;
+    private final String uomLink;
+
+    public static Phenomenon of(int id, String name, String uom, String uomLink) {
+        return new Phenomenon(id, name, uom, uomLink);
+    }
+
+    public static Phenomenon of(int id, String name) {
+        return new Phenomenon(id, name, null, null);
+    }
+
+    private Phenomenon(int id, String name, String uom, String uomLink) {
+        this.id = id;
+        this.name = name;
+        this.uom = uom;
+        this.uomLink = uomLink;
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getUom() {
+        return uom;
+    }
+
+    public String getUomLink() {
+        return uomLink;
+    }
+}

+ 14 - 8
src/main/java/cz/senslog/telemetry/database/domain/Sensor.java

@@ -6,22 +6,24 @@ public class Sensor {
     private final String name;
     private final String type;
     private final int ioID;
-    private final int phenomenonId;
+    private final Phenomenon phenomenon;
+    private final String description;
 
-    public static Sensor of(long sensorId, String name, String type, int ioID, int phenomenonId) {
-        return new Sensor(sensorId, name, type, ioID, phenomenonId);
+    public static Sensor of(long sensorId, String name, String type, int ioID, Phenomenon phenomenon, String description) {
+        return new Sensor(sensorId, name, type, ioID, phenomenon, description);
     }
 
     public static Sensor of(long sensorId, String name, int ioId) {
-        return of(sensorId, name, null, ioId, -1);
+        return of(sensorId, name, null, ioId, null, null);
     }
 
-    private Sensor(long sensorId, String name, String type, int ioID, int phenomenonId) {
+    private Sensor(long sensorId, String name, String type, int ioID, Phenomenon phenomenon, String description) {
         this.sensorId = sensorId;
         this.name = name;
         this.type = type;
         this.ioID = ioID;
-        this.phenomenonId = phenomenonId;
+        this.phenomenon = phenomenon;
+        this.description = description;
     }
 
     public long getSensorId() {
@@ -40,7 +42,11 @@ public class Sensor {
         return ioID;
     }
 
-    public int getPhenomenonId() {
-        return phenomenonId;
+    public Phenomenon getPhenomenon() {
+        return phenomenon;
+    }
+
+    public String getDescription() {
+        return description;
     }
 }

+ 29 - 5
src/main/java/cz/senslog/telemetry/database/repository/MapLogRepository.java

@@ -143,29 +143,53 @@ public class MapLogRepository implements SensLogRepository {
             row.getString("sensor_name"),
             row.getString("sensor_type"),
             row.getInteger("io_id"),
-            row.getInteger("phenomenon_id")
+            Phenomenon.of(
+                    row.getInteger("phenomenon_id"),
+                    row.getString("phenomenon_name")
+            ),
+            row.getString("description")
+    );
+
+    @Override
+    public Future<Sensor> findSensorById(long sensorId) {
+        return client.preparedQuery("SELECT s.sensor_id, s.sensor_name, s.sensor_type, s.io_id, s.description, p.id AS phenomenon_id, p.name AS phenomenon_name, p.uom, p.uom_link " +
+                        "FROM maplog.sensor AS s " +
+                        "JOIN maplog.phenomenon p on p.id = s.phenomenon_id " +
+                        "WHERE s.sensor_id = $1")
+                .execute(Tuple.of(sensorId))
+                .map(RowSet::iterator)
+                .map(iterator -> iterator.hasNext() ? ROW_TO_SENSOR.apply(iterator.next()) : null);
+    }
+
+    private static final Function<Row, Sensor> ROW_TO_BASIC_SENSOR = (row) -> Sensor.of(
+            row.getLong("sensor_id"),
+            row.getString("sensor_name"),
+            row.getString("sensor_type"),
+            row.getInteger("io_id"),
+            Phenomenon.of(row.getInteger("phenomenon_id"), null),
+            row.getString("description")
     );
 
     @Override
     public Future<Sensor> findSensorByIOAndUnitId(int ioID, long unitId) {
-        return client.preparedQuery("SELECT s.sensor_id, s.sensor_name, s.sensor_type, s.io_id, s.phenomenon_id " +
+        return client.preparedQuery("SELECT s.sensor_id, s.sensor_name, s.sensor_type, s.io_id, s.phenomenon_id, s.description " +
                         "FROM maplog.sensor AS s " +
                         "JOIN maplog.unit_to_sensor uts ON s.sensor_id = uts.sensor_id " +
                         "WHERE s.io_id = $1 AND uts.unit_id = $2")
                 .execute(Tuple.of(ioID, unitId))
                 .map(RowSet::iterator)
-                .map(iterator -> iterator.hasNext() ? ROW_TO_SENSOR.apply(iterator.next()) : null);
+                .map(iterator -> iterator.hasNext() ? ROW_TO_BASIC_SENSOR.apply(iterator.next()) : null);
     }
 
     @Override
     public Future<List<Sensor>> findSensorsByUnitId(long unitId) {
-        return client.preparedQuery("SELECT s.sensor_id, s.sensor_name, s.sensor_type, s.io_id, s.phenomenon_id " +
+        return client.preparedQuery("SELECT s.sensor_id, s.sensor_name, s.sensor_type, s.io_id, s.phenomenon_id, s.description " +
                         "FROM maplog.unit_to_sensor AS uts " +
                         "JOIN maplog.sensor s on s.sensor_id = uts.sensor_id " +
                         "WHERE UTS.unit_id = $1")
                 .execute(Tuple.of(unitId))
                 .map(rs -> StreamSupport.stream(rs.spliterator(), false)
-                        .map(ROW_TO_SENSOR).collect(Collectors.toList())
+                        .map(ROW_TO_BASIC_SENSOR).collect(Collectors.toList())
                 );
     }
 

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

@@ -52,6 +52,11 @@ public class MockMapLogRepository implements SensLogRepository {
     }
 
     @Override
+    public Future<Sensor> findSensorById(long sensorId) {
+        return Future.succeededFuture(Sensor.of(sensorId, "mock(name)", "mock(type)", -1, null, "mock(description)"));
+    }
+
+    @Override
     public Future<Sensor> findSensorByIOAndUnitId(int ioID, long unitId) {
         return Future.succeededFuture(Sensor.of(12345, "no name", ioID));
     }

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

@@ -25,7 +25,12 @@ public interface SensLogRepository {
     Future<Unit> findUnitById(long unitId);
 
     Future<Unit> findUnitByIMEI(String imei);
+
+
+    Future<Sensor> findSensorById(long sensorId);
     Future<Sensor> findSensorByIOAndUnitId(int ioID, long unitId);
+
+
     Future<List<Campaign>> allCampaigns();
     Future<Campaign> findCampaignById(long campaignId);
     Future<List<Long>> findUnitIdsByCampaignId(long campaignId);

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

@@ -58,7 +58,6 @@ public final class HttpVertxServer extends AbstractVerticle {
                     openAPIRouterBuilder.operation("campaignIdUnitsGET").handler(apiHandler::campaignIdUnitsGET);
                     openAPIRouterBuilder.operation("campaignIdUnitsObservationsGET").handler(apiHandler::campaignIdUnitsObservationsGET);
                     openAPIRouterBuilder.operation("campaignIdUnitsObservationsLocationsGET").handler(apiHandler::campaignIdUnitsObservationsLocationsGET);
-
                     openAPIRouterBuilder.operation("campaignIdUnitIdObservationsGET").handler(apiHandler::campaignIdUnitIdObservationsGET);
                     openAPIRouterBuilder.operation("campaignIdUnitIdLocationsGET").handler(apiHandler::campaignIdUnitIdLocationsGET);
 
@@ -67,6 +66,9 @@ public final class HttpVertxServer extends AbstractVerticle {
                     openAPIRouterBuilder.operation("unitIdSensorsGET").handler(apiHandler::unitIdSensorsGET);
                     openAPIRouterBuilder.operation("unitIdCampaignsGET").handler(apiHandler::unitIdCampaignsGET);
 
+
+                    openAPIRouterBuilder.operation("sensorIdGET").handler(apiHandler::sensorIdGET);
+
                     Router mainRouter = openAPIRouterBuilder.createRouter();
 //                    mainRouter.route().handler(LoggerHandler.create());
 //                    mainRouter.route().handler(rc -> logger.info("HTTP Request '{}'.", rc.request().absoluteURI()));

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

@@ -15,6 +15,7 @@ import org.apache.logging.log4j.Logger;
 import java.time.OffsetDateTime;
 import java.time.ZoneId;
 import java.util.List;
+import java.util.Objects;
 import java.util.function.BiFunction;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -521,4 +522,27 @@ public class OpenAPIHandler {
                         ))).collect(toList())).encode()))
                 .onFailure(th -> rc.fail(400, th));
     }
+
+    public void sensorIdGET(RoutingContext rc) {
+        String host =  hostURLFull(rc.request());
+
+        long sensorId = Long.parseLong(rc.pathParam("sensorId"));
+
+        List<String> paramNavigationLinks = rc.queryParam("navigationLinks");
+        boolean navigationLinks = paramNavigationLinks.isEmpty() ? DEFAULT_NAVIGATION_LINKS : parseBoolean(paramNavigationLinks.get(0));
+
+        repo.findSensorById(sensorId)
+                .onSuccess(s -> rc.response().end((navigationLinks ? JsonObject.of(
+                                "self@NavigationLink", String.format("%s/sensors/%d", host, s.getSensorId()),
+                                "Units@NavigationLink", String.format("%s/sensors/%d/units", host, s.getSensorId()  ),
+                                "Phenomenon@NavigationLink", String.format("%s/phenomenons/%d", host, s.getPhenomenon().getId())
+                        ) : JsonObject.of()).mergeIn(JsonObject.of(
+                                "id", s.getSensorId(),
+                                "name", s.getName(),
+                                "description", s.getDescription(),
+                                "type", s.getType(),
+                                "phenomenon", s.getPhenomenon().getName()
+                        )).encode())
+                        .onFailure(th -> rc.fail(400, th)));
+    }
 }

+ 17 - 31
src/main/resources/openAPISpec.yaml

@@ -706,18 +706,24 @@ paths:
               schema:
                 $ref: '#/components/schemas/Error'
 
-  /sensors/{id}:
+  /sensors/{sensorId}:
     get:
       operationId: sensorIdGET
       summary: Publish info about the sensor
       parameters:
         - in: path
-          name: id
+          name: sensorId
           schema:
             type: integer
             format: int64
           required: true
           description: Numeric ID of the sensor to get
+        - in: query
+          name: navigationLinks
+          schema:
+            type: boolean
+            default: true
+          description: Option to disable @NavigationLinks in a response
       responses:
         200:
           description: JSON Object of info about the sensor
@@ -1466,59 +1472,39 @@ components:
     SensorDetailInfo:
       type: object
       required:
-        - self@NavigationLink
-        - Phenomenon@NavigationLink
-        - Units@NavigationLink
-        - id
+        - sensorId
         - name
-        - type
         - phenomenon
       properties:
         self@NavigationLink:
           type: string
           format: uri
-        Phenomenon@NavigationLink:
+        Units@NavigationLink:
           type: string
           format: uri
-        Units@NavigationLink:
+        Phenomenon@NavigationLink:
           type: string
           format: uri
-        id:
+        sensorId:
           type: integer
           format: int64
         name:
           type: string
-        description:
+        phenomenon:
           type: string
         type:
           type: string
-        minRange:
-          type: integer
-          format: int64
-        maxRange:
-          type: integer
-          format: int64
-        phenomenon:
-          type: object
-          properties:
-            name:
-              type: string
-            uom:
-              type: string
-              maxLength: 30
+        description:
+          type: string
       example:
         self@NavigationLink: "<domain>/sensors/105"
         Phenomenon@NavigationLink: "<domain>/phenomenons/15"
         Units@NavigationLink: "<domain>/sensors/105/units"
-        id: 105
+        sensorId: 105
         name: "Sensor 105"
         description: "Description of the sensor 105"
         type: "type of sensor"
-        minRange: 0
-        maxRange: 1000
-        phenomenon:
-          name: "Temperature"
-          uom: "uom"
+        phenomenon: "Temperature"
 
     SensorUnitBasicInfo:
       type: object