diff --git a/cwms-data-api/src/main/java/cwms/cda/api/LevelsController.java b/cwms-data-api/src/main/java/cwms/cda/api/LevelsController.java index d51bd0c87..7505a4cfc 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/LevelsController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/LevelsController.java @@ -67,7 +67,6 @@ import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import cwms.cda.api.enums.UnitSystem; -import cwms.cda.api.errors.CdaError; import cwms.cda.data.dao.LocationLevelsDao; import cwms.cda.data.dao.LocationLevelsDaoImpl; import cwms.cda.data.dto.LocationLevel; @@ -206,10 +205,8 @@ public void delete(@NotNull Context ctx, @NotNull String levelId) { + " the default English units for their parameters." + "\n* `SI` " + "Specifies the SI unit system. Location level values will be in " - + "the default SI units for their parameters." - + "\n* `Other` " - + "Any unit returned in the response to the units URI request that is " - + "appropriate for the requested parameters. "), + + "the default SI units for their parameters. " + + "\n\nThe default unit system is SI."), @OpenApiParam(name = DATUM, description = "Specifies the elevation datum of" + " the response. This field affects only elevation location levels. " + "Valid values for this field are:" @@ -280,8 +277,7 @@ public void getAll(@NotNull Context ctx) { boolean isLegacyVersion = version.equals("1"); - if (format.isEmpty() && !isLegacyVersion) - { + if (format.isEmpty() && !isLegacyVersion) { String cursor = ctx.queryParamAsClass(PAGE, String.class) .getOrDefault(""); int pageSize = ctx.queryParamAsClass(PAGE_SIZE, Integer.class) @@ -315,12 +311,9 @@ public void getAll(@NotNull Context ctx) { ctx.status(HttpServletResponse.SC_OK); ctx.result(results); requestResultSize.update(results.length()); - if (isLegacyVersion) - { + if (isLegacyVersion) { ctx.contentType(contentType.toString()); - } - else - { + } else { ctx.contentType(contentType.getType()); } } @@ -338,14 +331,24 @@ public void getAll(@NotNull Context ctx) { @OpenApiParam(name = OFFICE, required = true, description = "Specifies the " + "office of the Location Level to be returned"), @OpenApiParam(name = EFFECTIVE_DATE, required = true, description = "Specifies " - + "the effective date of Location Level to be returned"), + + "the effective date of Location Level to be returned. " + + "Expected formats are `YYYY-MM-DDTHH:MM` or `YYYY-MM-DDTHH:MM:SS`"), @OpenApiParam(name = TIMEZONE, description = "Specifies the time zone of " + "the values of the effective date field (unless otherwise " + "specified), as well as the time zone of any times in the response." + " If this field is not specified, the default time zone of UTC " + "shall be used."), - @OpenApiParam(name = UNIT, description = "Desired unit for " - + "the values retrieved.") + @OpenApiParam(name = UNIT, description = "Specifies the unit or unit system" + + " of the response. Valid values for the unit field are:" + + "\n* `EN` " + + "Specifies English unit system. Location level values will be in" + + " the default English units for their parameters." + + "\n* `SI` " + + "Specifies the SI unit system. Location level values will be in " + + "the default SI units for their parameters." + + "\n* `Other` " + + "Any unit returned in the response to the units URI request that is " + + "appropriate for the requested parameters. "), }, responses = { @OpenApiResponse(status = STATUS_200,content = { diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dao/LocationLevelsDaoImpl.java b/cwms-data-api/src/main/java/cwms/cda/data/dao/LocationLevelsDaoImpl.java index 470e89000..f8e99faeb 100644 --- a/cwms-data-api/src/main/java/cwms/cda/data/dao/LocationLevelsDaoImpl.java +++ b/cwms-data-api/src/main/java/cwms/cda/data/dao/LocationLevelsDaoImpl.java @@ -62,7 +62,6 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.TimeZone; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; @@ -184,8 +183,10 @@ private static class LevelLookup { private final JDomLocationLevelRef locationLevelRef; private final Date effectiveDate; - public LevelLookup(String officeId, String locLevelId, String attributeId, String attributeValue, String attributeUnits, Date effectiveDate) { - this(new JDomLocationLevelRef(officeId, locLevelId, attributeId, attributeValue, attributeUnits), effectiveDate); + public LevelLookup(String officeId, String locLevelId, String attributeId, String attributeValue, + String attributeUnits, Date effectiveDate) { + this(new JDomLocationLevelRef(officeId, locLevelId, attributeId, attributeValue, attributeUnits), + effectiveDate); } public LevelLookup(JDomLocationLevelRef locationLevelRef, Date effectiveDate) { @@ -203,7 +204,8 @@ public boolean equals(Object o) { } LevelLookup that = (LevelLookup) o; - return Objects.equals(locationLevelRef, that.locationLevelRef) && Objects.equals(effectiveDate, that.effectiveDate); + return Objects.equals(locationLevelRef, that.locationLevelRef) + && Objects.equals(effectiveDate, that.effectiveDate); } @Override @@ -242,13 +244,12 @@ private static SEASONAL_VALUE_TAB_T getSeasonalValues(LocationLevel locationLeve List seasonalValues = locationLevel.getSeasonalValues(); SEASONAL_VALUE_TAB_T pSeasonalValues = null; - if(seasonalValues != null && !seasonalValues.isEmpty()) { + if (seasonalValues != null && !seasonalValues.isEmpty()) { pSeasonalValues = new SEASONAL_VALUE_TAB_T(); - for(SeasonalValueBean seasonalValue : seasonalValues) - { + for(SeasonalValueBean seasonalValue : seasonalValues) { SEASONAL_VALUE_T seasonalValueT = new SEASONAL_VALUE_T(); seasonalValueT.setOFFSET_MINUTES(toBigDecimal(seasonalValue.getOffsetMinutes())); - if(seasonalValue.getOffsetMonths() != null) { + if (seasonalValue.getOffsetMonths() != null) { seasonalValueT.setOFFSET_MONTHS(seasonalValue.getOffsetMonths().byteValue()); } seasonalValueT.setVALUE(toBigDecimal(seasonalValue.getValue())); @@ -330,6 +331,11 @@ public LocationLevel retrieveLocationLevel(String locationLevelName, String pUni return connectionResult(dsl, c -> { String units = pUnits; Configuration configuration = getDslContext(c, officeId).configuration(); + if (units != null && (units.equalsIgnoreCase("SI") + || units.equalsIgnoreCase("EN"))) { + units = CWMS_UTIL_PACKAGE.call_GET_DEFAULT_UNITS(configuration, + locationLevelName.split("\\.")[1], units); + } RETRIEVE_LOCATION_LEVEL3 level = CWMS_LEVEL_PACKAGE.call_RETRIEVE_LOCATION_LEVEL3( configuration, locationLevelName, units, date, "UTC", null, null, units, @@ -464,12 +470,12 @@ private void addSeasonalValue(Record r, // offset.setDaysHoursMinutesString(dayToSecond.toString()); // } // seasonalValuesImpl.setOffset(offset); - // TODO: LocationLevel is missing seasonal origin and offset. + // TODO: LocationLevel is missing seasonal origin and offset. String calOffset = r.get(view.CALENDAR_OFFSET); String timeOffset = r.get(view.TIME_OFFSET); JDomSeasonalIntervalImpl newSeasonalOffset = buildSeasonalOffset(calOffset, timeOffset); - SeasonalValueBean seasonalValue = buildSeasonalValueBean(seasonalLevel, newSeasonalOffset) ; + SeasonalValueBean seasonalValue = buildSeasonalValueBean(seasonalLevel, newSeasonalOffset); builder.withSeasonalValue(seasonalValue); } } diff --git a/cwms-data-api/src/test/java/cwms/cda/api/LevelsControllerTestIT.java b/cwms-data-api/src/test/java/cwms/cda/api/LevelsControllerTestIT.java index e0a37eddc..103a30441 100644 --- a/cwms-data-api/src/test/java/cwms/cda/api/LevelsControllerTestIT.java +++ b/cwms-data-api/src/test/java/cwms/cda/api/LevelsControllerTestIT.java @@ -345,9 +345,102 @@ void test_get_all_location_level() throws Exception { assertThat(response.path("levels[1].constant-value"), floatCloseTo(2.0, 0.01)); } + @Test + void test_get_one_units() throws Exception { + createLocation("level_as_single_value", true, OFFICE); + String levelId = "level_as_single_value.Stor.Ave.1Day.Regulating"; + ZonedDateTime time = ZonedDateTime.of(2023, 6, 1, 0, 0, 0, 0, ZoneId.of("America/Los_Angeles")); + LocationLevel level = new LocationLevel.Builder(levelId, time) + .withOfficeId(OFFICE) + .withConstantValue(1.0) + .withLevelUnitsId("ac-ft") + .build(); + CwmsDataApiSetupCallback.getDatabaseLink().connection(c -> { + DSLContext dsl = dslContext(c, OFFICE); + LocationLevelsDaoImpl dao = new LocationLevelsDaoImpl(dsl); + dao.storeLocationLevel(level); + }); + + //Read level with unit + given() + .log().ifValidationFails(LogDetail.ALL,true) + .accept(Formats.JSONV2) + .contentType(Formats.JSONV2) + .queryParam(Controllers.OFFICE, OFFICE) + .queryParam(UNIT, "SI") + .queryParam(EFFECTIVE_DATE, time.toInstant().toString()) + .when() + .redirects().follow(true) + .redirects().max(3) + .get("/levels/{level-id}", levelId) + .then() + .log().ifValidationFails(LogDetail.ALL,true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .body("level-units-id", equalTo("m3")) + // I think we need to create a custom matcher. + // This really shouldn't use equals but due to a quirk in + // RestAssured it appears to be necessary. + .body("constant-value", equalTo(1233.4818f)); // 1 ac-ft to m3 + + given() + .log().ifValidationFails(LogDetail.ALL,true) + .accept(Formats.JSONV2) + .contentType(Formats.JSONV2) + .queryParam("office", OFFICE) + .queryParam(EFFECTIVE_DATE, time.toInstant().toString()) + .queryParam(UNIT, "ac-ft") + .when() + .redirects().follow(true) + .redirects().max(3) + .get("/levels/{level-id}", levelId) + .then() + .assertThat() + .log().ifValidationFails(LogDetail.ALL,true) + .statusCode(is(HttpServletResponse.SC_OK)) + .body("level-units-id",equalTo("ac-ft")) + .body("constant-value",equalTo(1.0F)); + + given() + .log().ifValidationFails(LogDetail.ALL,true) + .accept(Formats.JSONV2) + .contentType(Formats.JSONV2) + .queryParam("office", OFFICE) + .queryParam(EFFECTIVE_DATE, time.toInstant().toString()) + .queryParam(UNIT, "EN") + .when() + .redirects().follow(true) + .redirects().max(3) + .get("/levels/{level-id}", levelId) + .then() + .assertThat() + .log().ifValidationFails(LogDetail.ALL,true) + .statusCode(is(HttpServletResponse.SC_OK)) + .body("level-units-id",equalTo("ac-ft")) + .body("constant-value",equalTo(1.0F)); + + given() + .log().ifValidationFails(LogDetail.ALL,true) + .accept(Formats.JSONV2) + .contentType(Formats.JSONV2) + .queryParam("office", OFFICE) + .queryParam(EFFECTIVE_DATE, time.toInstant().toString()) + .queryParam(UNIT, "ft3") + .when() + .redirects().follow(true) + .redirects().max(3) + .get("/levels/{level-id}", levelId) + .then() + .log().ifValidationFails(LogDetail.ALL,true) + .assertThat() + .statusCode(is(HttpServletResponse.SC_OK)) + .body("level-units-id",equalTo("ft3")) + .body("constant-value",equalTo(43560.0F)); + } + @ParameterizedTest @EnumSource(GetAllTestNewAliases.class) - void test_get_all_aliases_new(GetAllTestNewAliases test) throws Exception + void test_get_all_aliases_new(GetAllTestNewAliases test) { given() .log().ifValidationFails(LogDetail.ALL, true) @@ -367,7 +460,7 @@ void test_get_all_aliases_new(GetAllTestNewAliases test) throws Exception @ParameterizedTest @EnumSource(GetAllTestLegacy.class) - void test_get_all_aliases_legacy(GetAllTestLegacy test) throws Exception + void test_get_all_aliases_legacy(GetAllTestLegacy test) { given() .log().ifValidationFails(LogDetail.ALL, true)