Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cwms-data-api/src/main/java/cwms/cda/api/Controllers.java
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ public final class Controllers {
public static final String INCLUDE_ALIASES = "include-aliases";
public static final String MIN_NUMBER = "min-number";
public static final String MAX_NUMBER = "max-number";
public static final String MEASUREMENT_ID = "measurement-id";
public static final String MIN_HEIGHT = "min-height";
public static final String MAX_HEIGHT = "max-height";
public static final String MIN_FLOW = "min-flow";
Expand Down
27 changes: 17 additions & 10 deletions cwms-data-api/src/main/java/cwms/cda/api/MeasurementController.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import static cwms.cda.api.Controllers.MAX_FLOW;
import static cwms.cda.api.Controllers.MAX_HEIGHT;
import static cwms.cda.api.Controllers.MAX_NUMBER;
import static cwms.cda.api.Controllers.MEASUREMENT_ID;
import static cwms.cda.api.Controllers.MIN_FLOW;
import static cwms.cda.api.Controllers.MIN_HEIGHT;
import static cwms.cda.api.Controllers.MIN_NUMBER;
Expand All @@ -48,6 +49,7 @@
import static cwms.cda.api.Controllers.TIMEZONE;
import static cwms.cda.api.Controllers.TIME_FORMAT_DESC;
import static cwms.cda.api.Controllers.UNIT_SYSTEM;
import static cwms.cda.api.Controllers.queryParamAsClass;
import static cwms.cda.api.Controllers.queryParamAsDouble;
import static cwms.cda.api.Controllers.queryParamAsInstant;
import static cwms.cda.api.Controllers.requiredParam;
Expand All @@ -63,6 +65,7 @@
import cwms.cda.data.dao.MeasurementDao;
import cwms.cda.data.dto.StatusResponse;
import cwms.cda.data.dto.measurement.Measurement;
import cwms.cda.data.dto.measurement.MeasurementLegacy;
import cwms.cda.formatters.ContentType;
import cwms.cda.formatters.Formats;
import io.javalin.apibuilder.CrudHandler;
Expand Down Expand Up @@ -103,8 +106,9 @@ private Timer.Context markAndTime(String subject) {
queryParams = {
@OpenApiParam(name = OFFICE_MASK, description = "Office id mask for filtering measurements. Use null to retrieve measurements for all offices."),
@OpenApiParam(name = ID_MASK, description = "Location id mask for filtering measurements. Use null to retrieve measurements for all locations."),
@OpenApiParam(name = MIN_NUMBER, description = "Minimum measurement number-id for filtering measurements."),
@OpenApiParam(name = MAX_NUMBER, description = "Maximum measurement number-id for filtering measurements."),
@OpenApiParam(name = MEASUREMENT_ID, description = "Measurement ID filter. Supports UUIDs (and optionally integer IDs). This filter has precedence over min-number and max-number filters."),
@OpenApiParam(name = MIN_NUMBER, type = Integer.class, description = "Minimum measurement number-id for filtering measurements. Only applies to integer measurement IDs."),
@OpenApiParam(name = MAX_NUMBER, type = Integer.class, description = "Maximum measurement number-id for filtering measurements. Only applies to integer measurement IDs."),
@OpenApiParam(name = BEGIN, description = "The start of the time window to delete. " +
TIME_FORMAT_DESC + " A null value is treated as an unbounded start."),
@OpenApiParam(name = END, description = "The end of the time window to delete." +
Expand All @@ -128,8 +132,9 @@ private Timer.Context markAndTime(String subject) {
},
responses = {
@OpenApiResponse(status = "200", content = {
@OpenApiContent(isArray = true, type = Formats.JSONV1, from = Measurement.class),
@OpenApiContent(isArray = true, type = Formats.JSON, from = Measurement.class)
@OpenApiContent(isArray = true, type = Formats.JSONV2, from = Measurement.class),
@OpenApiContent(isArray = true, type = Formats.JSONV1, from = MeasurementLegacy.class),
@OpenApiContent(isArray = true, type = Formats.JSON, from = MeasurementLegacy.class)
})
},
description = "Returns matching measurement data.",
Expand All @@ -144,6 +149,7 @@ public void getAll(@NotNull Context ctx) {
Instant maxDate = queryParamAsInstant(ctx, END);
String minNum = ctx.queryParam(MIN_NUMBER);
String maxNum = ctx.queryParam(MAX_NUMBER);
String measurementId = ctx.queryParam(MEASUREMENT_ID);
Number minHeight = queryParamAsDouble(ctx, MIN_HEIGHT);
Number maxHeight = queryParamAsDouble(ctx, MAX_HEIGHT);
Number minFlow = queryParamAsDouble(ctx, MIN_FLOW);
Expand All @@ -154,7 +160,7 @@ public void getAll(@NotNull Context ctx) {
DSLContext dsl = getDslContext(ctx);
MeasurementDao dao = new MeasurementDao(dsl);
List<Measurement> measurements = dao.retrieveMeasurements(officeId, locationId, minDate, maxDate, unitSystem,
minHeight, maxHeight, minFlow, maxFlow, minNum, maxNum, agency, quality);
minHeight, maxHeight, minFlow, maxFlow, minNum, maxNum, agency, quality, measurementId);
String formatHeader = ctx.header(Header.ACCEPT);
ContentType contentType = Formats.parseHeader(formatHeader, Measurement.class);
ctx.contentType(contentType.toString());
Expand Down Expand Up @@ -182,8 +188,9 @@ public void getOne(@NotNull Context ctx, @NotNull String locationId) {
@OpenApi(
requestBody = @OpenApiRequestBody(
content = {
@OpenApiContent(isArray = true, from = Measurement.class, type = Formats.JSONV1),
@OpenApiContent(isArray = true, from = Measurement.class, type = Formats.JSON)
@OpenApiContent(isArray = true, from = Measurement.class, type = Formats.JSONV2),
@OpenApiContent(isArray = true, from = MeasurementLegacy.class, type = Formats.JSONV1),
@OpenApiContent(isArray = true, from = MeasurementLegacy.class, type = Formats.JSON)
},
required = true),
queryParams = {
Expand Down Expand Up @@ -234,8 +241,8 @@ public void update(@NotNull Context ctx, @NotNull String locationId) {
+ "to be used if the format of the " + BEGIN + "and " + END
+ " parameters do not include offset or time zone information. "
+ "Defaults to UTC."),
@OpenApiParam(name = MIN_NUMBER, description = "Specifies the min number-id of the measurement to delete."),
@OpenApiParam(name = MAX_NUMBER, description = "Specifies the max number-id of the measurement to delete."),
@OpenApiParam(name = MIN_NUMBER, type = Integer.class, description = "Specifies the min number-id of the measurement to delete. Only applies to integer measurement IDs."),
@OpenApiParam(name = MAX_NUMBER, type = Integer.class, description = "Specifies the max number-id of the measurement to delete. Only applies to integer measurement IDs."),
},
description = "Delete an existing measurement.",
method = HttpMethod.DELETE,
Expand All @@ -255,7 +262,7 @@ public void delete(@NotNull Context ctx, @NotNull String locationId) {
try (Timer.Context ignored = markAndTime(DELETE)) {
DSLContext dsl = getDslContext(ctx);
MeasurementDao dao = new MeasurementDao(dsl);
dao.deleteMeasurements(officeId, locationId, minDate, maxDate,minNum, maxNum);
dao.deleteMeasurements(officeId, locationId, minDate, maxDate, minNum, maxNum, null);
StatusResponse re = new StatusResponse(officeId, "Measurement successfully deleted for specified location-id.", locationId);
ctx.status(HttpServletResponse.SC_OK).json(re);
}
Expand Down
60 changes: 32 additions & 28 deletions cwms-data-api/src/main/java/cwms/cda/data/dao/MeasurementDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import cwms.cda.api.enums.UnitSystem;
import cwms.cda.api.errors.FieldException;
import cwms.cda.api.errors.NotFoundException;
import cwms.cda.data.dto.CwmsDTOPaginated;
import cwms.cda.data.dto.CwmsId;
import cwms.cda.data.dto.CwmsIdTimeExtentsEntry;
import cwms.cda.data.dto.TimeExtents;
Expand Down Expand Up @@ -72,6 +74,7 @@
import org.jooq.impl.DSL;
import static org.jooq.impl.DSL.max;
import static org.jooq.impl.DSL.min;

import usace.cwms.db.jooq.codegen.packages.CWMS_STREAM_PACKAGE;
import usace.cwms.db.jooq.codegen.tables.AV_STREAMFLOW_MEAS;
import usace.cwms.db.jooq.codegen.udt.records.STREAMFLOW_MEAS2_T;
Expand All @@ -86,33 +89,31 @@ public MeasurementDao(DSLContext dsl) {
super(dsl);
}

/**
* Retrieve a list of measurements
*
* @param officeId - the office id
* @param locationId - the location id for filtering
* @param unitSystem - the unit system to use for the returned data
* @return a list of measurements
*/
public List<Measurement> retrieveMeasurements(String officeId, String locationId, Instant minDateMask, Instant maxDateMask, String unitSystem,
Number minHeight, Number maxHeight, Number minFlow, Number maxFlow, String minNum, String maxNum,
String agencies, String qualities) {
String agencies, String qualities, String measurementId) {
return connectionResult(dsl, conn -> {
setOffice(conn, officeId);
Timestamp minTimestamp = buildTimestamp(minDateMask);
Timestamp maxTimestamp = buildTimestamp(maxDateMask);
return retrieveMeasurementsJooq(conn, officeId, locationId, unitSystem, minHeight, maxHeight, minFlow, maxFlow, minNum, maxNum, agencies, qualities, minTimestamp, maxTimestamp);
return retrieveMeasurementsJooq(conn, officeId, locationId, unitSystem, minHeight, maxHeight, minFlow, maxFlow, minNum, maxNum, agencies, qualities, minTimestamp, maxTimestamp, measurementId);
});
}

private static List<Measurement> retrieveMeasurementsJooq(Connection conn, String officeId, String locationId, String unitSystem, Number minHeight, Number maxHeight, Number minFlow, Number maxFlow, String minNum, String maxNum, String agencies, String qualities, Timestamp minTimestamp, Timestamp maxTimestamp) throws JsonProcessingException {
String xml = CWMS_STREAM_PACKAGE.call_RETRIEVE_MEAS_XML(DSL.using(conn).configuration(), locationId, unitSystem, minTimestamp, maxTimestamp,
minHeight, maxHeight, minFlow, maxFlow, minNum, maxNum, agencies, qualities, "UTC", officeId);
List<Measurement> retVal = fromDbXml(xml);
if(retVal.isEmpty()) {
private static List<Measurement> retrieveMeasurementsJooq(Connection conn, String officeId, String locationId, String unitSystem, Number minHeight, Number maxHeight, Number minFlow, Number maxFlow, String minNum, String maxNum, String agencies, String qualities, Timestamp minTimestamp, Timestamp maxTimestamp, String measurementId) throws JsonProcessingException {
String xml;
if (measurementId == null) {
xml = CWMS_STREAM_PACKAGE.call_RETRIEVE_MEAS_XML(DSL.using(conn).configuration(), locationId, unitSystem, minTimestamp, maxTimestamp,
minHeight, maxHeight, minFlow, maxFlow, minNum, maxNum, agencies, qualities, "UTC", officeId);
} else {
xml = CWMS_STREAM_PACKAGE.call_RETRIEVE_STREAMFLOW_MEAS_XML_BY_ID(DSL.using(conn).configuration(), locationId, measurementId, unitSystem, minTimestamp, maxTimestamp,
minHeight, maxHeight, minFlow, maxFlow, agencies, qualities, "UTC", officeId);
}
List<Measurement> measurements = fromDbXml(xml);
if (measurements.isEmpty()) {
throw new NotFoundException("No measurements found.");
}
return retVal;
return measurements;
}

/**
Expand Down Expand Up @@ -142,15 +143,21 @@ private void storeMeasurementsJooq(Connection conn, List<Measurement> measuremen
* @param minNum
*/
public void deleteMeasurements(String officeId, String locationId, Instant minDateMask, Instant maxDateMask, String minNum,
String maxNum) {
String maxNum, String measurementId) {
connection(dsl, conn -> {
setOffice(conn, officeId);
Timestamp minTimestamp = buildTimestamp(minDateMask);
Timestamp maxTimestamp = buildTimestamp(maxDateMask);
String timeZoneId = "UTC";
verifyMeasurementsExists(conn, officeId, locationId, maxNum, maxNum);
CWMS_STREAM_PACKAGE.call_DELETE_STREAMFLOW_MEAS(DSL.using(conn).configuration(), locationId, minNum, minTimestamp, maxTimestamp,
null, null, null, null, maxNum, maxNum, null, null, timeZoneId, officeId);
verifyMeasurementsExists(conn, officeId, locationId, minNum, maxNum, measurementId);
String minNumF = minNum;
String maxNumF = maxNum;
if(measurementId != null) {
minNumF = null;
maxNumF = null;
}
CWMS_STREAM_PACKAGE.call_DELETE_STREAMFLOW_MEAS(DSL.using(conn).configuration(), locationId, "EN", minTimestamp, maxTimestamp,
null, null, null, null, minNumF, maxNumF, null, null, timeZoneId, officeId);
});
}

Expand Down Expand Up @@ -181,12 +188,9 @@ public List<CwmsIdTimeExtentsEntry> retrieveMeasurementTimeExtentsMap(String off
.build());
}

private void verifyMeasurementsExists(Connection conn, String officeId, String locationId, String minNum, String maxNum) throws JsonProcessingException {
private void verifyMeasurementsExists(Connection conn, String officeId, String locationId, String minNum, String maxNum, String measurementId) throws JsonProcessingException {
List<Measurement> measurements = retrieveMeasurementsJooq(conn, officeId, locationId, UnitSystem.EN.toString(),
null, null, null, null, minNum, maxNum, null, null, null, null);
if (measurements.isEmpty()) {
throw new NotFoundException("Could not find measurements for " + locationId + " in office " + officeId + ".");
}
null, null, null, null, minNum, maxNum, null, null, null, null, measurementId);
}

static List<Measurement> fromDbXml(String xml) throws JsonProcessingException {
Expand All @@ -207,7 +211,7 @@ static Measurement fromJooqMeasurementRecord(STREAMFLOW_MEAS2_T record) {
.withName(locationTemplate.getLocationId())
.withOfficeId(locationTemplate.getOfficeId())
.build())
.withNumber(record.getMEAS_NUMBER())
.withMeasurementId(record.getMEAS_NUMBER())
.withAgency(record.getAGENCY_ID())
.withParty(record.getPARTY())
.withUsed(parseBool(record.getUSED()))
Expand Down Expand Up @@ -270,7 +274,7 @@ static MeasurementXmlDto convertMeasurementToXmlDto(Measurement meas)
.withHeightUnit(meas.getHeightUnit())
.withInstant(meas.getInstant())
.withLocationId(meas.getLocationId())
.withNumber(meas.getNumber())
.withNumber(meas.getMeasurementId())
.withOfficeId(meas.getOfficeId())
.withParty(meas.getParty())
.withTempUnit(meas.getTempUnit())
Expand Down Expand Up @@ -300,7 +304,7 @@ static Measurement convertMeasurementFromXmlDto(MeasurementXmlDto dto) {
.withName(dto.getLocationId())
.withOfficeId(dto.getOfficeId())
.build())
.withNumber(dto.getNumber())
.withMeasurementId(dto.getNumber())
.withParty(dto.getParty())
.withTempUnit(dto.getTempUnit())
.withUsed(dto.isUsed())
Expand Down
Loading
Loading