|
|
@@ -4,6 +4,7 @@ import cz.senslog.telemetry.database.DataNotFoundException;
|
|
|
import cz.senslog.telemetry.database.PagingRetrieve;
|
|
|
import cz.senslog.telemetry.database.SortType;
|
|
|
import cz.senslog.telemetry.database.domain.*;
|
|
|
+import cz.senslog.telemetry.database.domain.Filter;
|
|
|
import io.vertx.core.Future;
|
|
|
import io.vertx.pgclient.PgPool;
|
|
|
import io.vertx.sqlclient.Row;
|
|
|
@@ -22,6 +23,8 @@ import java.util.function.Function;
|
|
|
import java.util.stream.Collectors;
|
|
|
import java.util.stream.StreamSupport;
|
|
|
|
|
|
+import static java.lang.String.format;
|
|
|
+import static java.util.Optional.of;
|
|
|
import static java.util.stream.Collectors.toList;
|
|
|
|
|
|
public class MapLogRepository implements SensLogRepository {
|
|
|
@@ -120,7 +123,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
row.getString("name"),
|
|
|
row.getString("description")
|
|
|
))
|
|
|
- .collect(Collectors.toList())
|
|
|
+ .collect(toList())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@@ -136,7 +139,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
.map(RowSet::iterator)
|
|
|
.map(iterator -> iterator.hasNext() ? ROW_TO_SIMPLE_UNIT.apply(iterator.next()) : null)
|
|
|
.map(Optional::ofNullable)
|
|
|
- .map(p -> p.orElseThrow(() -> new DataNotFoundException(String.format("Unit IMEI '%s' not found.", imei))));
|
|
|
+ .map(p -> p.orElseThrow(() -> new DataNotFoundException(format("Unit IMEI '%s' not found.", imei))));
|
|
|
}
|
|
|
|
|
|
private static final Function<Row, Sensor> ROW_TO_SENSOR = (row) -> Sensor.of(
|
|
|
@@ -161,7 +164,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
.map(RowSet::iterator)
|
|
|
.map(iterator -> iterator.hasNext() ? ROW_TO_SENSOR.apply(iterator.next()) : null)
|
|
|
.map(Optional::ofNullable)
|
|
|
- .map(p -> p.orElseThrow(() -> new DataNotFoundException(String.format("Sensor ID '%d' not found.", sensorId))));
|
|
|
+ .map(p -> p.orElseThrow(() -> new DataNotFoundException(format("Sensor ID '%d' not found.", sensorId))));
|
|
|
}
|
|
|
|
|
|
private static final Function<Row, Sensor> ROW_TO_BASIC_SENSOR = (row) -> Sensor.of(
|
|
|
@@ -183,7 +186,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
.map(RowSet::iterator)
|
|
|
.map(iterator -> iterator.hasNext() ? ROW_TO_BASIC_SENSOR.apply(iterator.next()) : null)
|
|
|
.map(Optional::ofNullable)
|
|
|
- .map(p -> p.orElseThrow(() -> new DataNotFoundException(String.format("Sensor for Unit(%d) and IO(%d) not found.", unitId, ioID))));
|
|
|
+ .map(p -> p.orElseThrow(() -> new DataNotFoundException(format("Sensor for Unit(%d) and IO(%d) not found.", unitId, ioID))));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -198,7 +201,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
row.getInteger("io_id"),
|
|
|
Phenomenon.of(row.getLong("phenomenon_id"), null),
|
|
|
row.getString("description")
|
|
|
- )).collect(Collectors.toList())
|
|
|
+ )).collect(toList())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@@ -214,7 +217,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
row.getLong("sensor_id"),
|
|
|
row.getString("name"),
|
|
|
row.getString("type")
|
|
|
- )).collect(Collectors.toList())
|
|
|
+ )).collect(toList())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@@ -227,7 +230,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
row.getLong("sensor_id"),
|
|
|
row.getString("name"),
|
|
|
row.getString("type")
|
|
|
- )).collect(Collectors.toList())
|
|
|
+ )).collect(toList())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@@ -244,7 +247,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
row.getLong("sensor_id"),
|
|
|
row.getString("name"),
|
|
|
row.getString("type")
|
|
|
- )).collect(Collectors.toList())
|
|
|
+ )).collect(toList())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@@ -260,7 +263,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
.map(RowSet::iterator)
|
|
|
.map(iterator -> iterator.hasNext() ? ROW_TO_SENSOR.apply(iterator.next()) : null)
|
|
|
.map(Optional::ofNullable)
|
|
|
- .map(p -> p.orElseThrow(() -> new DataNotFoundException(String.format("Sensor ID '%d' not found in Campaign(%d) and Unit(%d).", sensorId, campaignId, unitId))));
|
|
|
+ .map(p -> p.orElseThrow(() -> new DataNotFoundException(format("Sensor ID '%d' not found in Campaign(%d) and Unit(%d).", sensorId, campaignId, unitId))));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -271,7 +274,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
.map(row -> Phenomenon.of(
|
|
|
row.getLong("id"),
|
|
|
row.getString("name")
|
|
|
- )).collect(Collectors.toList())
|
|
|
+ )).collect(toList())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@@ -289,7 +292,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
.map(RowSet::iterator)
|
|
|
.map(iterator -> iterator.hasNext() ? ROW_TO_PHENOMENON.apply(iterator.next()) : null)
|
|
|
.map(Optional::ofNullable)
|
|
|
- .map(p -> p.orElseThrow(() -> new DataNotFoundException(String.format("Phenomenon ID '%d' not found.", phenomenonId))));
|
|
|
+ .map(p -> p.orElseThrow(() -> new DataNotFoundException(format("Phenomenon ID '%d' not found.", phenomenonId))));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -305,7 +308,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
row.getString("description"),
|
|
|
row.getOffsetDateTime("from_time"),
|
|
|
row.getOffsetDateTime("to_time")
|
|
|
- )).collect(Collectors.toList())
|
|
|
+ )).collect(toList())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@@ -333,7 +336,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
.map(RowSet::iterator)
|
|
|
.map(iterator -> iterator.hasNext() ? ROW_TO_DRIVER.apply(iterator.next()) : null)
|
|
|
.map(Optional::ofNullable)
|
|
|
- .map(p -> p.orElseThrow(() -> new DataNotFoundException(String.format("Driver ID '%d' not found.", driverId))));
|
|
|
+ .map(p -> p.orElseThrow(() -> new DataNotFoundException(format("Driver ID '%d' not found.", driverId))));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -392,7 +395,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
.map(RowSet::iterator)
|
|
|
.map(iterator -> iterator.hasNext() ? ROW_TO_ACTION.apply(iterator.next()) : null)
|
|
|
.map(Optional::ofNullable)
|
|
|
- .map(p -> p.orElseThrow(() -> new DataNotFoundException(String.format("Action ID '%d' not found for Driver(%d).", actionId, driverId))));
|
|
|
+ .map(p -> p.orElseThrow(() -> new DataNotFoundException(format("Action ID '%d' not found for Driver(%d).", actionId, driverId))));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -404,7 +407,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
.map(RowSet::iterator)
|
|
|
.map(iterator -> iterator.hasNext() ? ROW_TO_ACTION.apply(iterator.next()) : null)
|
|
|
.map(Optional::ofNullable)
|
|
|
- .map(p -> p.orElseThrow(() -> new DataNotFoundException(String.format("Action ID '%d' not found for Driver(%d) and Unit(%d).", actionId, driverId, unitId))));
|
|
|
+ .map(p -> p.orElseThrow(() -> new DataNotFoundException(format("Action ID '%d' not found for Driver(%d) and Unit(%d).", actionId, driverId, unitId))));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -440,7 +443,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
.map(RowSet::iterator)
|
|
|
.map(iterator -> iterator.hasNext() ? ROW_TO_EVENT.apply(iterator.next()) : null)
|
|
|
.map(Optional::ofNullable)
|
|
|
- .map(p -> p.orElseThrow(() -> new DataNotFoundException(String.format("Event ID '%d' not found.", eventId))));
|
|
|
+ .map(p -> p.orElseThrow(() -> new DataNotFoundException(format("Event ID '%d' not found.", eventId))));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -490,7 +493,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
row.getOffsetDateTime("from_time"),
|
|
|
row.getOffsetDateTime("to_time")
|
|
|
))
|
|
|
- .collect(Collectors.toList())
|
|
|
+ .collect(toList())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@@ -515,7 +518,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
.map(RowSet::iterator)
|
|
|
.map(iterator -> iterator.hasNext() ? ROW_TO_CAMPAIGN_UNIT.apply(iterator.next()) : null)
|
|
|
.map(Optional::ofNullable)
|
|
|
- .map(p -> p.orElseThrow(() -> new DataNotFoundException(String.format("Unit ID '%d' not found for Campaign(%d).", unitId, campaignId))));
|
|
|
+ .map(p -> p.orElseThrow(() -> new DataNotFoundException(format("Unit ID '%d' not found for Campaign(%d).", unitId, campaignId))));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -528,7 +531,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
.map(RowSet::iterator)
|
|
|
.map(iterator -> iterator.hasNext() ? ROW_TO_UNIT.apply(iterator.next()) : null)
|
|
|
.map(Optional::ofNullable)
|
|
|
- .map(p -> p.orElseThrow(() -> new DataNotFoundException(String.format("Unit ID '%d' not found for Driver(%d).", unitId, driverId))));
|
|
|
+ .map(p -> p.orElseThrow(() -> new DataNotFoundException(format("Unit ID '%d' not found for Driver(%d).", unitId, driverId))));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -541,7 +544,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
.map(RowSet::iterator)
|
|
|
.map(iterator -> iterator.hasNext() ? ROW_TO_UNIT.apply(iterator.next()) : null)
|
|
|
.map(Optional::ofNullable)
|
|
|
- .map(p -> p.orElseThrow(() -> new DataNotFoundException(String.format("Unit ID '%d' not found for Driver(%d) and Action(%d).", unitId, driverId, actionId))));
|
|
|
+ .map(p -> p.orElseThrow(() -> new DataNotFoundException(format("Unit ID '%d' not found for Driver(%d) and Action(%d).", unitId, driverId, actionId))));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -577,7 +580,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
row.getOffsetDateTime("from_time"),
|
|
|
row.getOffsetDateTime("to_time")
|
|
|
))
|
|
|
- .collect(Collectors.toList())
|
|
|
+ .collect(toList())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@@ -595,7 +598,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
.map(RowSet::iterator)
|
|
|
.map(it -> it.hasNext() ? ROW_TO_CAMPAIGN.apply(it.next()) : null)
|
|
|
.map(Optional::ofNullable)
|
|
|
- .map(p -> p.orElseThrow(() -> new DataNotFoundException(String.format("Campaign ID '%d' not found.", campaignId))));
|
|
|
+ .map(p -> p.orElseThrow(() -> new DataNotFoundException(format("Campaign ID '%d' not found.", campaignId))));
|
|
|
}
|
|
|
|
|
|
public static final Function<Row, Unit> ROW_TO_UNIT = (row) -> Unit.of(
|
|
|
@@ -612,7 +615,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
.map(RowSet::iterator)
|
|
|
.map(iterator -> iterator.hasNext() ? ROW_TO_UNIT.apply(iterator.next()) : null)
|
|
|
.map(Optional::ofNullable)
|
|
|
- .map(p -> p.orElseThrow(() -> new DataNotFoundException(String.format("Unit ID '%d' not found.", unitId))));
|
|
|
+ .map(p -> p.orElseThrow(() -> new DataNotFoundException(format("Unit ID '%d' not found.", unitId))));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -627,7 +630,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
row.getString("name"),
|
|
|
row.getString("imei"),
|
|
|
row.getString("description")
|
|
|
- )).collect(Collectors.toList())
|
|
|
+ )).collect(toList())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@@ -637,13 +640,13 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
.execute(Tuple.of(campaignId))
|
|
|
.map(rs -> StreamSupport.stream(rs.spliterator(), false)
|
|
|
.map(r -> r.getLong("unit_id"))
|
|
|
- .collect(Collectors.toList())
|
|
|
+ .collect(toList())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public Future<List<UnitTelemetry>> findObservationsByCampaignId(
|
|
|
- long campaignId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit
|
|
|
+ long campaignId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters
|
|
|
) {
|
|
|
String whereTimestampClause;
|
|
|
Tuple tupleParams;
|
|
|
@@ -661,6 +664,29 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
tupleParams = Tuple.of(campaignId, offset, limit, zone.getId());
|
|
|
}
|
|
|
|
|
|
+ StringBuilder whereFiltersClause = new StringBuilder();
|
|
|
+ for (Filter filter : filters) {
|
|
|
+ String opt = filter.getOperation().getDbOperand();
|
|
|
+ float optValue = filter.getOperationValue();
|
|
|
+ switch (filter.getType()) {
|
|
|
+ case UNIT -> {
|
|
|
+ switch (filter.getAttribute()) {
|
|
|
+ case SPEED -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND tel.speed %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case LONGITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_X (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case LATITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_Y (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case ALTITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_Z (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ case SENSOR -> {
|
|
|
+ switch (filter.getAttribute()) {
|
|
|
+ case ID -> of(tupleParams.addLong(filter.getAttributeValueAsLong()).addFloat(optValue))
|
|
|
+ .map(p -> format(" AND (tel.observed_values::jsonb ->> $%d::bigint::text::varchar)::integer %s $%d", p.size()-1, opt, p.size()))
|
|
|
+ .ifPresent(whereFiltersClause::append);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
String sql = "SELECT tel.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, " +
|
|
|
@@ -670,7 +696,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
"FROM maplog.obs_telemetry AS tel " +
|
|
|
"JOIN maplog.unit_to_campaign AS utc ON tel.unit_id = utc.unit_id " +
|
|
|
"JOIN maplog.campaign AS c ON c.id = utc.campaign_id " +
|
|
|
- "WHERE utc.campaign_id = $1 AND " + whereTimestampClause + " " +
|
|
|
+ "WHERE utc.campaign_id = $1 AND " + whereTimestampClause + whereFiltersClause + " " +
|
|
|
"ORDER BY tel.time_stamp OFFSET $2 LIMIT $3;";
|
|
|
|
|
|
return client.preparedQuery(sql)
|
|
|
@@ -688,15 +714,15 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
r.getFloat("speed"),
|
|
|
r.getJsonObject("observed_values")
|
|
|
))
|
|
|
- .collect(Collectors.toList())
|
|
|
+ .collect(toList())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByCampaignIdWithPaging(
|
|
|
- long campaignId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit
|
|
|
+ long campaignId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters
|
|
|
) {
|
|
|
- return findObservationsByCampaignId(campaignId, from, to, zone, offset, limit+1)
|
|
|
+ return findObservationsByCampaignId(campaignId, from, to, zone, offset, limit+1, filters)
|
|
|
.map(data -> {
|
|
|
boolean hasNext = data.size() > limit;
|
|
|
if (hasNext) {
|
|
|
@@ -708,7 +734,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
|
|
|
@Override
|
|
|
public Future<List<UnitTelemetry>> findObservationsByCampaignIdAndUnitId(
|
|
|
- long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit
|
|
|
+ long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters
|
|
|
) {
|
|
|
String whereTimestampClause;
|
|
|
Tuple tupleParams;
|
|
|
@@ -726,6 +752,29 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
tupleParams = Tuple.of(campaignId, unitId, offset, limit, zone.getId());
|
|
|
}
|
|
|
|
|
|
+ StringBuilder whereFiltersClause = new StringBuilder();
|
|
|
+ for (Filter filter : filters) {
|
|
|
+ String opt = filter.getOperation().getDbOperand();
|
|
|
+ float optValue = filter.getOperationValue();
|
|
|
+ switch (filter.getType()) {
|
|
|
+ case UNIT -> {
|
|
|
+ switch (filter.getAttribute()) {
|
|
|
+ case SPEED -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND tel.speed %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case LONGITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_X (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case LATITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_Y (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case ALTITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_Z (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ case SENSOR -> {
|
|
|
+ switch (filter.getAttribute()) {
|
|
|
+ case ID -> of(tupleParams.addLong(filter.getAttributeValueAsLong()).addFloat(optValue))
|
|
|
+ .map(p -> format(" AND (tel.observed_values::jsonb ->> $%d::bigint::text::varchar)::integer %s $%d", p.size()-1, opt, p.size()))
|
|
|
+ .ifPresent(whereFiltersClause::append);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
String sql = "SELECT tel.id, tel.unit_id, tel.observed_values::json, tel.speed, " +
|
|
|
"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, " +
|
|
|
@@ -734,7 +783,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
"ST_M (tel.the_geom) AS angle " +
|
|
|
"FROM maplog.obs_telemetry AS tel " +
|
|
|
"JOIN maplog.unit_to_campaign utc on tel.unit_id = utc.unit_id " +
|
|
|
- "WHERE utc.campaign_id = $1 AND utc.unit_id = $2 AND " + whereTimestampClause + " " +
|
|
|
+ "WHERE utc.campaign_id = $1 AND utc.unit_id = $2 AND " + whereTimestampClause + whereFiltersClause + " " +
|
|
|
"ORDER BY tel.time_stamp OFFSET $3 LIMIT $4;";
|
|
|
|
|
|
return client.preparedQuery(sql)
|
|
|
@@ -751,15 +800,15 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
r.getFloat("angle")),
|
|
|
r.getFloat("speed"),
|
|
|
r.getJsonObject("observed_values")))
|
|
|
- .collect(Collectors.toList())
|
|
|
+ .collect(toList())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByCampaignIdAndUnitIdWithPaging(
|
|
|
- long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit
|
|
|
+ long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters
|
|
|
) {
|
|
|
- return findObservationsByCampaignIdAndUnitId(campaignId, unitId, from, to, zone, offset, limit+1)
|
|
|
+ return findObservationsByCampaignIdAndUnitId(campaignId, unitId, from, to, zone, offset, limit+1, filters)
|
|
|
.map(data -> {
|
|
|
boolean hasNext = data.size() > limit;
|
|
|
if (hasNext) {
|
|
|
@@ -771,7 +820,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
|
|
|
@Override
|
|
|
public Future<List<UnitTelemetry>> findObservationsByEventId(
|
|
|
- long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit
|
|
|
+ long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters
|
|
|
) {
|
|
|
String whereTimestampClause;
|
|
|
Tuple tupleParams;
|
|
|
@@ -789,6 +838,29 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
tupleParams = Tuple.of(eventId, offset, limit, zone.getId());
|
|
|
}
|
|
|
|
|
|
+ StringBuilder whereFiltersClause = new StringBuilder();
|
|
|
+ for (Filter filter : filters) {
|
|
|
+ String opt = filter.getOperation().getDbOperand();
|
|
|
+ float optValue = filter.getOperationValue();
|
|
|
+ switch (filter.getType()) {
|
|
|
+ case UNIT -> {
|
|
|
+ switch (filter.getAttribute()) {
|
|
|
+ case SPEED -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND tel.speed %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case LONGITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_X (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case LATITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_Y (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case ALTITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_Z (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ case SENSOR -> {
|
|
|
+ switch (filter.getAttribute()) {
|
|
|
+ case ID -> of(tupleParams.addLong(filter.getAttributeValueAsLong()).addFloat(optValue))
|
|
|
+ .map(p -> format(" AND (tel.observed_values::jsonb ->> $%d::bigint::text::varchar)::integer %s $%d", p.size()-1, opt, p.size()))
|
|
|
+ .ifPresent(whereFiltersClause::append);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
String sql = "SELECT tel.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, " +
|
|
|
@@ -797,7 +869,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
"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 + " " +
|
|
|
+ "WHERE dta.id = $1 AND " + whereTimestampClause + whereFiltersClause + " " +
|
|
|
"ORDER BY tel.time_stamp OFFSET $2 LIMIT $3";
|
|
|
|
|
|
return client.preparedQuery(sql)
|
|
|
@@ -814,15 +886,15 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
r.getFloat("angle")),
|
|
|
r.getFloat("speed"),
|
|
|
r.getJsonObject("observed_values")))
|
|
|
- .collect(Collectors.toList())
|
|
|
+ .collect(toList())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public Future<PagingRetrieve<List<UnitTelemetry>>> findObservationsByEventIdWithPaging(
|
|
|
- long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit
|
|
|
+ long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters
|
|
|
) {
|
|
|
- return findObservationsByEventId(eventId, from, to, zone, offset, limit+1)
|
|
|
+ return findObservationsByEventId(eventId, from, to, zone, offset, limit+1, filters)
|
|
|
.map(data -> {
|
|
|
boolean hasNext = data.size() > limit;
|
|
|
if (hasNext) {
|
|
|
@@ -834,7 +906,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
|
|
|
@Override
|
|
|
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, List<Filter> filters
|
|
|
) {
|
|
|
String whereTimestampClause;
|
|
|
Tuple tupleParams;
|
|
|
@@ -852,6 +924,29 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
tupleParams = Tuple.of(campaignId, unitId, sensorId, offset, limit, zone.getId());
|
|
|
}
|
|
|
|
|
|
+ StringBuilder whereFiltersClause = new StringBuilder();
|
|
|
+ for (Filter filter : filters) {
|
|
|
+ String opt = filter.getOperation().getDbOperand();
|
|
|
+ float optValue = filter.getOperationValue();
|
|
|
+ switch (filter.getType()) {
|
|
|
+ case UNIT -> {
|
|
|
+ switch (filter.getAttribute()) {
|
|
|
+ case SPEED -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND tel.speed %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case LONGITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_X (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case LATITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_Y (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case ALTITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_Z (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ case SENSOR -> {
|
|
|
+ switch (filter.getAttribute()) {
|
|
|
+ case ID -> of(tupleParams.addLong(filter.getAttributeValueAsLong()).addFloat(optValue))
|
|
|
+ .map(p -> format(" AND (tel.observed_values::jsonb ->> $%d::bigint::text::varchar)::integer %s $%d", p.size()-1, opt, p.size()))
|
|
|
+ .ifPresent(whereFiltersClause::append);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
String sql = "SELECT tel.id, (tel.observed_values::jsonb ->> $3::bigint::text::varchar)::integer AS value, tel.speed, " +
|
|
|
"tel.time_stamp, $6 AS zone_id, " + // ::timestamp with time zone at time zone $6 AS time_stamp
|
|
|
"ST_X (ST_Transform (tel.the_geom, 4326)) AS long, " +
|
|
|
@@ -861,8 +956,8 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
"FROM maplog.obs_telemetry AS tel " +
|
|
|
"JOIN maplog.unit_to_sensor uts on tel.unit_id = uts.unit_id " +
|
|
|
"JOIN maplog.unit_to_campaign utc on tel.unit_id = utc.unit_id " +
|
|
|
- "WHERE utc.campaign_id = $1 AND utc.unit_id = $2 AND uts.sensor_id = $3 AND observed_values::jsonb -> $3::bigint::text::varchar IS NOT NULL " +
|
|
|
- "AND " + whereTimestampClause + " ORDER BY tel.time_stamp OFFSET $4 LIMIT $5";
|
|
|
+ "WHERE utc.campaign_id = $1 AND utc.unit_id = $2 AND uts.sensor_id = $3 AND observed_values::jsonb -> $3::bigint::text::varchar IS NOT NULL " + whereFiltersClause +
|
|
|
+ " AND " + whereTimestampClause + " ORDER BY tel.time_stamp OFFSET $4 LIMIT $5";
|
|
|
|
|
|
return client.preparedQuery(sql)
|
|
|
.execute(tupleParams)
|
|
|
@@ -877,15 +972,15 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
r.getFloat("alt"),
|
|
|
r.getFloat("angle")),
|
|
|
r.getFloat("speed")))
|
|
|
- .collect(Collectors.toList())
|
|
|
+ .collect(toList())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public Future<PagingRetrieve<List<SensorTelemetry>>> findObservationsByCampaignIdAndUnitIdAndSensorIdWithPaging(
|
|
|
- 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, List<Filter> filters
|
|
|
) {
|
|
|
- return findObservationsByCampaignIdAndUnitIdAndSensorId(campaignId, unitId, sensorId, from, to, zone, offset, limit+1)
|
|
|
+ return findObservationsByCampaignIdAndUnitIdAndSensorId(campaignId, unitId, sensorId, from, to, zone, offset, limit+1, filters)
|
|
|
.map(data -> {
|
|
|
boolean hasNext = data.size() > limit;
|
|
|
if (hasNext) {
|
|
|
@@ -897,7 +992,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
|
|
|
@Override
|
|
|
public Future<List<UnitLocation>> findLocationsByCampaignIdAndUnitId(
|
|
|
- long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit
|
|
|
+ long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters
|
|
|
) {
|
|
|
String whereTimestampClause;
|
|
|
Tuple tupleParams;
|
|
|
@@ -915,6 +1010,29 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
tupleParams = Tuple.of(campaignId, unitId, offset, limit, zone.getId());
|
|
|
}
|
|
|
|
|
|
+ StringBuilder whereFiltersClause = new StringBuilder();
|
|
|
+ for (Filter filter : filters) {
|
|
|
+ String opt = filter.getOperation().getDbOperand();
|
|
|
+ float optValue = filter.getOperationValue();
|
|
|
+ switch (filter.getType()) {
|
|
|
+ case UNIT -> {
|
|
|
+ switch (filter.getAttribute()) {
|
|
|
+ case SPEED -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND tel.speed %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case LONGITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_X (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case LATITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_Y (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case ALTITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_Z (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ case SENSOR -> {
|
|
|
+ switch (filter.getAttribute()) {
|
|
|
+ case ID -> of(tupleParams.addLong(filter.getAttributeValueAsLong()).addFloat(optValue))
|
|
|
+ .map(p -> format(" AND (tel.observed_values::jsonb ->> $%d::bigint::text::varchar)::integer %s $%d", p.size()-1, opt, p.size()))
|
|
|
+ .ifPresent(whereFiltersClause::append);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
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, " +
|
|
|
@@ -922,7 +1040,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
"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.campaign_id = $1 AND utc.unit_id = $2 AND " + whereTimestampClause + " " +
|
|
|
+ "WHERE utc.campaign_id = $1 AND utc.unit_id = $2 AND " + whereTimestampClause + whereFiltersClause + " " +
|
|
|
"ORDER BY tel.time_stamp OFFSET $3 LIMIT $4;";
|
|
|
|
|
|
return client.preparedQuery(sql)
|
|
|
@@ -937,15 +1055,15 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
r.getFloat("alt")
|
|
|
)
|
|
|
))
|
|
|
- .collect(Collectors.toList())
|
|
|
+ .collect(toList())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public Future<PagingRetrieve<List<UnitLocation>>> findLocationsByCampaignIdAndUnitIdWithPaging(
|
|
|
- long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit
|
|
|
+ long campaignId, long unitId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters
|
|
|
) {
|
|
|
- return findLocationsByCampaignIdAndUnitId(campaignId, unitId, from, to, zone, offset, limit+1)
|
|
|
+ return findLocationsByCampaignIdAndUnitId(campaignId, unitId, from, to, zone, offset, limit+1, filters)
|
|
|
.map(data -> {
|
|
|
boolean hasNext = data.size() > limit;
|
|
|
if (hasNext) {
|
|
|
@@ -957,7 +1075,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
|
|
|
@Override
|
|
|
public Future<List<UnitLocation>> findLocationsByEventId(
|
|
|
- long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit
|
|
|
+ long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters
|
|
|
) {
|
|
|
String whereTimestampClause;
|
|
|
Tuple tupleParams;
|
|
|
@@ -975,13 +1093,36 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
tupleParams = Tuple.of(eventId, offset, limit, zone.getId());
|
|
|
}
|
|
|
|
|
|
+ StringBuilder whereFiltersClause = new StringBuilder();
|
|
|
+ for (Filter filter : filters) {
|
|
|
+ String opt = filter.getOperation().getDbOperand();
|
|
|
+ float optValue = filter.getOperationValue();
|
|
|
+ switch (filter.getType()) {
|
|
|
+ case UNIT -> {
|
|
|
+ switch (filter.getAttribute()) {
|
|
|
+ case SPEED -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND tel.speed %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case LONGITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_X (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case LATITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_Y (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case ALTITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_Z (ST_Transform (tel.the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ case SENSOR -> {
|
|
|
+ switch (filter.getAttribute()) {
|
|
|
+ case ID -> of(tupleParams.addLong(filter.getAttributeValueAsLong()).addFloat(optValue))
|
|
|
+ .map(p -> format(" AND (tel.observed_values::jsonb ->> $%d::bigint::text::varchar)::integer %s $%d", p.size()-1, opt, p.size()))
|
|
|
+ .ifPresent(whereFiltersClause::append);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
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 + " " +
|
|
|
+ "WHERE dta.id = $1 AND " + whereTimestampClause + whereFiltersClause + " " +
|
|
|
"ORDER BY tel.time_stamp OFFSET $2 LIMIT $3";
|
|
|
|
|
|
return client.preparedQuery(sql)
|
|
|
@@ -996,15 +1137,15 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
r.getFloat("alt")
|
|
|
)
|
|
|
))
|
|
|
- .collect(Collectors.toList())
|
|
|
+ .collect(toList())
|
|
|
);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public Future<PagingRetrieve<List<UnitLocation>>> findLocationsByEventIdWithPaging(
|
|
|
- long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit
|
|
|
+ long eventId, OffsetDateTime from, OffsetDateTime to, ZoneId zone, int offset, int limit, List<Filter> filters
|
|
|
) {
|
|
|
- return findLocationsByEventId(eventId, from, to, zone, offset, limit+1)
|
|
|
+ return findLocationsByEventId(eventId, from, to, zone, offset, limit+1, filters)
|
|
|
.map(data -> {
|
|
|
boolean hasNext = data.size() > limit;
|
|
|
if (hasNext) {
|
|
|
@@ -1016,7 +1157,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
|
|
|
@Override
|
|
|
public Future<List<UnitLocation>> findUnitsLocationsByCampaignId(
|
|
|
- long campaignId, int limitPerUnit, OffsetDateTime from, OffsetDateTime to, ZoneId zone, SortType sort
|
|
|
+ long campaignId, int limitPerUnit, OffsetDateTime from, OffsetDateTime to, ZoneId zone, SortType sort, List<Filter> filters
|
|
|
) {
|
|
|
String whereTimestampClause;
|
|
|
Tuple tupleParams;
|
|
|
@@ -1034,6 +1175,29 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
tupleParams = Tuple.of(campaignId, limitPerUnit, zone.getId());
|
|
|
}
|
|
|
|
|
|
+ StringBuilder whereFiltersClause = new StringBuilder();
|
|
|
+ for (Filter filter : filters) {
|
|
|
+ String opt = filter.getOperation().getDbOperand();
|
|
|
+ float optValue = filter.getOperationValue();
|
|
|
+ switch (filter.getType()) {
|
|
|
+ case UNIT -> {
|
|
|
+ switch (filter.getAttribute()) {
|
|
|
+ case SPEED -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND speed %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case LONGITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_X (ST_Transform (the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case LATITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_Y (ST_Transform (the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ case ALTITUDE -> of(tupleParams.addFloat(optValue)).map(p -> format(" AND ST_Z (ST_Transform (the_geom, 4326)) %s $%d", opt, p.size())).ifPresent(whereFiltersClause::append);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ case SENSOR -> {
|
|
|
+ switch (filter.getAttribute()) {
|
|
|
+ case ID -> of(tupleParams.addLong(filter.getAttributeValueAsLong()).addFloat(optValue))
|
|
|
+ .map(p -> format(" AND (observed_values::jsonb ->> $%d::bigint::text::varchar)::integer %s $%d", p.size()-1, opt, p.size()))
|
|
|
+ .ifPresent(whereFiltersClause::append);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
String sql = "SELECT unit_id, time_stamp, $3 AS zone_id, " + // ::timestamp with time zone at time zone $5 AS time_stamp
|
|
|
"ST_X (ST_Transform (the_geom, 4326)) AS long, " +
|
|
|
"ST_Y (ST_Transform (the_geom, 4326)) AS lat, " +
|
|
|
@@ -1041,7 +1205,7 @@ public class MapLogRepository implements SensLogRepository {
|
|
|
"ST_M (the_geom) AS angle " +
|
|
|
"FROM (SELECT *, row_number() OVER (PARTITION BY unit_id ORDER BY time_stamp "+ sort.name() +" ) AS rn " +
|
|
|
"FROM (SELECT obs.* FROM maplog.obs_telemetry obs JOIN maplog.unit_to_campaign utc ON obs.unit_id = utc.unit_id "+whereTimestampClause+") AS data) AS g " +
|
|
|
- "WHERE rn <= $2";
|
|
|
+ "WHERE rn <= $2" + whereFiltersClause;
|
|
|
|
|
|
return client.preparedQuery(sql)
|
|
|
.execute(tupleParams)
|