From 1b8b925ab1960cd0f0a177e05d327ba9009d1d45 Mon Sep 17 00:00:00 2001 From: Andreas Christmann Date: Fri, 14 Jun 2024 08:36:33 -0700 Subject: [PATCH 01/13] ts profile json --- .../timeseriesprofile/timeseriesprofile.json | 8 ++++ .../timeseriesprofileinstance.json | 41 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofile.json create mode 100644 cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileinstance.json diff --git a/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofile.json b/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofile.json new file mode 100644 index 000000000..5222856a6 --- /dev/null +++ b/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofile.json @@ -0,0 +1,8 @@ +{ + "description": "Description", + "parameter-list": ["Temperature","Depth"], + "location-id": "Location", + "office-id": "Office", + "ref-ts-id": "TimeSeries", + "key-parameter": "Depth" +} \ No newline at end of file diff --git a/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileinstance.json b/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileinstance.json new file mode 100644 index 000000000..b6555c4fe --- /dev/null +++ b/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileinstance.json @@ -0,0 +1,41 @@ +{ + "time-series-profile": + { + "location-id": "DET", + "key-parameter": "Depth", + "parameter-list": [ "Temp-Water", "Pres", "%-DO", "Conc-DO", "Cond", "pH", "TurbN", "Depth","Volt-Battery"], + "description": "Demonstration Profile for Couger Lake", + "office-id": "SWT", + "ref-ts-id": "DET.Elev-Forebay.Inst.0.0.Mixed-Rev" + }, + + "value-list" : [ + { + "time-zone": "US/Pacific", + "times" : ["09/09/2019,13:16:01", "09/09/2019,13:17:20"], + "value": + { + "parameter": "Temp-Water", + "unit": "F", + "values": ["1", "2"] + } + }, + { + "value": + { + "parameter": "Pres", + "unit": "mm-hg", + "values": ["1", "2"] + } + }, + { + "value": + { + "parameter": "Depth", + "unit": "ft", + "values": ["1", "2"] + } + } + ] + +} \ No newline at end of file From 32c0927816de7fbd776bef607e03ed8a54e7fbd3 Mon Sep 17 00:00:00 2001 From: Andreas Christmann Date: Tue, 18 Jun 2024 10:32:51 -0700 Subject: [PATCH 02/13] ts profile json --- .../timeseriesprofileinstance.json | 53 ++++++++++--------- .../timeseriesprofileparser.json | 23 ++++++++ 2 files changed, 51 insertions(+), 25 deletions(-) create mode 100644 cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileparser.json diff --git a/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileinstance.json b/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileinstance.json index b6555c4fe..e432b678b 100644 --- a/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileinstance.json +++ b/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileinstance.json @@ -3,39 +3,42 @@ { "location-id": "DET", "key-parameter": "Depth", - "parameter-list": [ "Temp-Water", "Pres", "%-DO", "Conc-DO", "Cond", "pH", "TurbN", "Depth","Volt-Battery"], + "parameter-list": [ "Temp-Water", "Depth"], "description": "Demonstration Profile for Couger Lake", "office-id": "SWT", "ref-ts-id": "DET.Elev-Forebay.Inst.0.0.Mixed-Rev" }, - "value-list" : [ + "timeseries-list" : [ { - "time-zone": "US/Pacific", - "times" : ["09/09/2019,13:16:01", "09/09/2019,13:17:20"], - "value": - { - "parameter": "Temp-Water", - "unit": "F", - "values": ["1", "2"] - } + "parameter": "Temp-Water", + "unit": "F", + "time-value-pairs": + [ + { + "time": "09/09/2019,13:16:01Z", + "value": "1.0" + }, + { + "time": "09/09/2019,13:17:20Z", + "value": "2.0" + } + ] }, { - "value": - { - "parameter": "Pres", - "unit": "mm-hg", - "values": ["1", "2"] - } - }, - { - "value": - { - "parameter": "Depth", - "unit": "ft", - "values": ["1", "2"] - } + "parameter": "Depth", + "unit": "ft", + "time-value-pairs": + [ + { + "time": "09/09/2019,13:16:01-07:00", + "value": "1.0" + }, + { + "time": "09/09/2019,13:17:20-07:00", + "value": "2.0" + } + ] } ] - } \ No newline at end of file diff --git a/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileparser.json b/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileparser.json new file mode 100644 index 000000000..7ca2c30e3 --- /dev/null +++ b/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileparser.json @@ -0,0 +1,23 @@ +{ + "office-id": "SWT", + "location-id": "TIMESERIESPROFILE_LOC", + "key-parameter": "Depth", + "record-delimiter": "\n", + "field-delimiter": ",", + "time-format": "MM/DD/YYYY,HH24:MI:SS", + "time-zone": "UTC", + "time-field": 1, + "time-in-two-fields": "F", + "parameter-info": [ + { + "parameter":"Depth", + "unit":"m", + "index":3 + }, + { + "parameter":"Temp-Water", + "unit":"F", + "index":5 + } + ] +} From 7b61ef3507f0d4c5cb838d609f1e308d22a1f72d Mon Sep 17 00:00:00 2001 From: Andreas Christmann Date: Tue, 18 Jun 2024 10:48:46 -0700 Subject: [PATCH 03/13] ts profile json --- .../cwms/cda/data/dto/timeseriesprofile/timeseriesprofile.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofile.json b/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofile.json index 5222856a6..4bbf3e071 100644 --- a/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofile.json +++ b/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofile.json @@ -4,5 +4,5 @@ "location-id": "Location", "office-id": "Office", "ref-ts-id": "TimeSeries", - "key-parameter": "Depth" + "key-parameter": "Depth", } \ No newline at end of file From ab581100d59cae4b25a9053ad9dd54701d83bf9d Mon Sep 17 00:00:00 2001 From: Andreas Christmann Date: Tue, 18 Jun 2024 10:50:55 -0700 Subject: [PATCH 04/13] ts profile json --- .../cwms/cda/data/dto/timeseriesprofile/timeseriesprofile.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofile.json b/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofile.json index 4bbf3e071..5222856a6 100644 --- a/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofile.json +++ b/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofile.json @@ -4,5 +4,5 @@ "location-id": "Location", "office-id": "Office", "ref-ts-id": "TimeSeries", - "key-parameter": "Depth", + "key-parameter": "Depth" } \ No newline at end of file From 15fdef179192ad449a13f83b4ca8e2328c168d96 Mon Sep 17 00:00:00 2001 From: Andreas Christmann Date: Wed, 19 Jun 2024 14:19:39 -0700 Subject: [PATCH 05/13] sample time series profile data --- .../timeSeriesProfileData.txt | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeSeriesProfileData.txt diff --git a/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeSeriesProfileData.txt b/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeSeriesProfileData.txt new file mode 100644 index 000000000..8f514133c --- /dev/null +++ b/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeSeriesProfileData.txt @@ -0,0 +1,27 @@ +'sep=, Date,Time,Site,Unit ID,User ID,�F-18H105402,mmHg-18H111574,DO %-18H110258,DO mg/L-18H110258,SPC-uS/cm-18H105402,pH-18H111544,NTU-18H108850,BGA-PCRFU-18H110486,BGA-PCug/L-18H110486,Chl RFU-18H110486,Chl ug/L-18H110486,DEP ft-18H105572,Batt V-18H111574,Lat-18H111574,Lon-18H111574, +09/09/2019,12:48:57,DET,,Holly Bellringer,67.108,719.6,98.3,9.03,43.9,8.54,0.19,0.21,-0.65,0.17,-0.01,3.152,5.35,44.71898,-122.24620, +09/09/2019,12:49:19,DET,,Holly Bellringer,67.563,719.6,97.2,8.88,43.4,8.43,0.12,0.21,-0.65,0.19,0.05,4.028,5.34,44.71898,-122.24620, +09/09/2019,12:52:54,DET,,Holly Bellringer,67.820,719.5,96.8,8.82,43.3,8.04,0.23,0.14,-0.71,0.20,0.10,6.264,5.32,44.71899,-122.24610, +09/09/2019,12:53:17,DET,,Holly Bellringer,67.767,719.6,96.6,8.81,43.3,8.02,0.12,0.15,-0.70,0.24,0.24,8.525,5.31,44.71900,-122.24610, +09/09/2019,12:54:42,DET,,Holly Bellringer,67.718,719.6,96.5,8.80,43.3,7.97,0.11,0.13,-0.72,0.25,0.29,10.789,5.31,44.71898,-122.24620, +09/09/2019,12:55:50,DET,,Holly Bellringer,67.700,719.6,96.4,8.79,43.3,7.95,0.08,0.17,-0.68,0.23,0.19,12.045,5.27,44.71898,-122.24620, +09/09/2019,12:56:27,DET,,Holly Bellringer,67.682,719.5,96.3,8.79,43.2,7.92,0.08,0.16,-0.70,0.24,0.24,14.188,5.28,44.71897,-122.24620, +09/09/2019,12:56:54,DET,,Holly Bellringer,67.669,719.5,96.2,8.78,43.2,7.92,0.17,0.10,-0.75,0.27,0.39,16.218,5.26,44.71897,-122.24620, +09/09/2019,12:57:48,DET,,Holly Bellringer,67.651,719.5,96.1,8.77,43.2,7.86,0.13,0.10,-0.75,0.22,0.16,18.303,5.26,44.71901,-122.24620, +09/09/2019,12:58:57,DET,,Holly Bellringer,67.613,719.6,95.8,8.75,43.2,7.86,0.05,0.15,-0.70,0.24,0.26,23.081,5.24,44.71901,-122.24620, +09/09/2019,12:59:31,DET,,Holly Bellringer,67.572,719.6,95.3,8.71,43.2,7.83,0.12,0.12,-0.74,0.30,0.48,28.262,5.26,44.71900,-122.24620, +09/09/2019,13:00:37,DET,,Holly Bellringer,67.557,719.6,95.1,8.69,43.2,7.82,0.07,0.11,-0.74,0.27,0.39,33.043,5.28,44.71904,-122.24610, +09/09/2019,13:01:08,DET,,Holly Bellringer,67.495,719.6,94.6,8.65,43.2,7.78,0.17,0.15,-0.71,0.26,0.35,38.527,5.27,44.71902,-122.24620, +09/09/2019,13:02:17,DET,,Holly Bellringer,67.003,719.7,91.4,8.40,43.4,7.74,0.14,0.26,-0.59,0.57,1.55,43.937,5.28,44.71902,-122.24620, +09/09/2019,13:02:51,DET,,Holly Bellringer,64.150,719.6,77.9,7.40,44.2,7.63,0.12,0.15,-0.70,0.33,0.62,48.191,5.27,44.71902,-122.24620, +09/09/2019,13:03:50,DET,,Holly Bellringer,62.782,719.6,71.1,6.86,44.2,7.49,0.13,0.26,-0.59,0.40,0.88,53.288,5.28,44.71902,-122.24620, +09/09/2019,13:04:50,DET,,Holly Bellringer,61.698,719.7,65.8,6.43,43.5,7.37,0.19,0.22,-0.63,0.37,0.76,58.457,5.28,44.71902,-122.24620, +09/09/2019,13:07:48,DET,,Holly Bellringer,54.818,719.8,61.8,6.56,39.4,7.12,0.67,0.18,-0.67,0.12,-0.23,88.792,5.29,44.71902,-122.24620, +09/09/2019,13:08:57,DET,,Holly Bellringer,52.003,719.8,68.4,7.53,37.9,7.07,0.08,0.28,-0.58,0.13,-0.19,103.598,5.28,44.71904,-122.24620, +09/09/2019,13:09:46,DET,,Holly Bellringer,49.363,719.8,73.9,8.42,37.4,7.05,0.17,0.23,-0.63,0.13,-0.19,118.692,5.30,44.71901,-122.24620, +09/09/2019,13:11:20,DET,,Holly Bellringer,47.156,719.8,76.6,8.98,37.2,7.03,0.28,0.28,-0.58,0.10,-0.29,133.659,5.32,44.71902,-122.24620, +09/09/2019,13:12:45,DET,,Holly Bellringer,45.468,719.8,75.9,9.11,37.0,7.00,0.43,0.30,-0.55,0.11,-0.26,148.541,5.31,44.71902,-122.24620, +09/09/2019,13:13:33,DET,,Holly Bellringer,44.743,719.8,75.4,9.13,37.0,6.99,0.52,0.35,-0.50,0.10,-0.30,163.665,5.31,44.71900,-122.24620, +09/09/2019,13:14:49,DET,,Holly Bellringer,44.135,719.8,75.5,9.22,36.9,6.98,0.67,0.30,-0.55,0.13,-0.20,178.560,5.31,44.71901,-122.24620, +09/09/2019,13:16:01,DET,,Holly Bellringer,43.701,719.8,75.7,9.30,36.9,6.97,0.88,0.31,-0.54,0.08,-0.38,193.010,5.32,44.71903,-122.24620, +09/09/2019,13:17:20,DET,,Holly Bellringer,43.390,719.8,75.6,9.33,36.9,6.96,1.00,0.32,-0.53,0.10,-0.31,208.607,5.31,44.71902,-122.24620,'; From 88d507964a129654756286f32a0aa42573cdcc49 Mon Sep 17 00:00:00 2001 From: Andreas Christmann Date: Wed, 19 Jun 2024 14:22:27 -0700 Subject: [PATCH 06/13] time series profile dto's --- .../dto/timeseriesprofile/ParameterInfo.java | 96 +++++++++ .../timeseriesprofile/TimeSeriesProfile.java | 165 +++++++++++++++ .../TimeSeriesProfileInstance.java | 29 +++ .../TimeSeriesProfileParser.java | 194 ++++++++++++++++++ 4 files changed, 484 insertions(+) create mode 100644 cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfo.java create mode 100644 cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfile.java create mode 100644 cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileInstance.java create mode 100644 cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParser.java diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfo.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfo.java new file mode 100644 index 000000000..02640b45d --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfo.java @@ -0,0 +1,96 @@ +package cwms.cda.data.dto.timeseriesprofile; + +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import cwms.cda.api.errors.FieldException; +import cwms.cda.data.dto.CwmsDTOBase; +import cwms.cda.formatters.Formats; +import cwms.cda.formatters.annotations.FormattableWith; +import cwms.cda.formatters.json.JsonV2; + +@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class) +@JsonDeserialize(builder = ParameterInfo.Builder.class) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) +public class ParameterInfo implements CwmsDTOBase +{ + private final String parameter; + private final String unit; + private final int index; + protected ParameterInfo(ParameterInfo.Builder builder) + { + parameter= builder.parameter; + unit = builder.unit; + index = builder.index; + } + public String getParameter() + { + return parameter; + } + public String getUnit() + { + return unit; + } + + public int getIndex(){ return index; } + + + @Override + public void validate() throws FieldException + { + + } + @Override + public int hashCode() { + int result = Objects.hashCode(getParameter()); + result = 31 * result + Objects.hashCode(getUnit()); + result = 31 * result + Objects.hashCode(getIndex()); + return result; + }@Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + ParameterInfo that = (ParameterInfo) o; + return Objects.equals(getParameter(), that.getParameter()) + && Objects.equals(getUnit(), that.getUnit()) + && Objects.equals(getIndex(), that.getIndex()); + } + @JsonPOJOBuilder + @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) + public static final class Builder + { + private String parameter; + private String unit; + private int index; + + + public ParameterInfo.Builder withParameter(String parameter) { + this.parameter = parameter; + return this; + } + public ParameterInfo.Builder withUnit(String unit) { + this.unit = unit; + return this; + } + public ParameterInfo.Builder withIndex(int index) + { + this.index = index; + return this; + } + + public ParameterInfo build() { + return new ParameterInfo(this); + } + + } +} \ No newline at end of file diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfile.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfile.java new file mode 100644 index 000000000..16805ff59 --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfile.java @@ -0,0 +1,165 @@ +package cwms.cda.data.dto.timeseriesprofile; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import cwms.cda.api.errors.FieldException; +import cwms.cda.data.dto.CwmsDTO; +import cwms.cda.formatters.Formats; +import cwms.cda.formatters.annotations.FormattableWith; +import cwms.cda.formatters.json.JsonV2; +import io.swagger.v3.oas.annotations.media.Schema; + +@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class) +@JsonDeserialize(builder = TimeSeriesProfile.Builder.class) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) +public final class TimeSeriesProfile extends CwmsDTO +{ + @Schema(description = "Location ID") + private final String locationId; + @Schema(description = "Description") + private final String description; + @Schema(description = "Parameter List") + private final List parameterList; + @Schema(description = "Key Parameter") + private final String keyParameter; + @Schema(description = "Reference TS") + private final String refTsId; + + private TimeSeriesProfile(Builder builder) + { + super(builder.officeId); + this.locationId = builder.locationId; + this.description = builder.description; + this.keyParameter = builder.keyParameter; + this.parameterList = builder.parameterList; + this.refTsId = builder.refTsId; + } + + public String getLocationId() + { + return locationId; + } + + public String getDescription() + { + return description; + } + + public String getKeyParameter() + { + return keyParameter; + } + + public List getParameterList() + { + return parameterList!=null ? new ArrayList<>(parameterList) : null; + } + + public String getRefTsId() + { + return refTsId; + } + + @Override + public void validate() throws FieldException + { + if (this.parameterList == null) { + throw new FieldException("Parameter list field can't be null"); + } + if (this.keyParameter == null) { + throw new FieldException("Key Parameter field can't be null"); + } + if (this.officeId == null) { + throw new FieldException("Office Id field can't be null"); + } + if (this.locationId == null) { + throw new FieldException("Location Id field can't be null"); + } + if (!parameterList.contains(keyParameter)) + { + throw new FieldException("Key Parameter must be part of Parameter list"); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + TimeSeriesProfile that = (TimeSeriesProfile) o; + return Objects.equals(getLocationId(), that.getLocationId()) + && Objects.equals(getOfficeId(), that.getOfficeId()) + && Objects.equals(getDescription(), that.getDescription()) + && Objects.equals(getKeyParameter(), that.getKeyParameter()) + && Objects.equals(getRefTsId(), that.getRefTsId()) + && Objects.equals(getParameterList(), that.getParameterList()) + ; + } + @Override + public int hashCode() { + int result = Objects.hashCode(getDescription()); + result = 31 * result + Objects.hashCode(getKeyParameter()); + result = 31 * result + Objects.hashCode(getLocationId()); + result = 31 * result + Objects.hashCode(getParameterList()); + result = 31 * result + Objects.hashCode(getOfficeId()); + result = 31 * result + Objects.hashCode(getRefTsId()); + return result; + } + @JsonPOJOBuilder + @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) + public static final class Builder { + private String officeId; + private List parameterList; + private String keyParameter; + private String description; + private String locationId; + private String refTsId; + + public TimeSeriesProfile.Builder withLocationId(String locationId) { + this.locationId = locationId; + return this; + } + + public TimeSeriesProfile.Builder withDescription(String description) { + this.description = description; + return this; + } + public TimeSeriesProfile.Builder withKeyParameter(String keyParameter) { + this.keyParameter = keyParameter; + return this; + } + + public TimeSeriesProfile.Builder withParameterList(List parameterList) + { + this.parameterList = parameterList!=null ? new ArrayList<>(parameterList) : null; + return this; + } + + public TimeSeriesProfile.Builder withOfficeId(String officeId) { + this.officeId = officeId; + return this; + } + + public TimeSeriesProfile.Builder withRefTsId(String refTsId) { + this.refTsId = refTsId; + return this; + } + + + public TimeSeriesProfile build() { + return new TimeSeriesProfile(this); + } + } +} diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileInstance.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileInstance.java new file mode 100644 index 000000000..67a26b1aa --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileInstance.java @@ -0,0 +1,29 @@ +package cwms.cda.data.dto.timeseriesprofile; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import cwms.cda.api.errors.FieldException; +import cwms.cda.data.dto.CwmsDTO; +import cwms.cda.formatters.Formats; +import cwms.cda.formatters.annotations.FormattableWith; +import cwms.cda.formatters.json.JsonV2; + +@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class) +@JsonDeserialize(builder = TimeSeriesProfile.Builder.class) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) +public final class TimeSeriesProfileInstance extends CwmsDTO +{ + protected TimeSeriesProfileInstance(String office) + { + super(office); + } + + @Override + public void validate() throws FieldException + { + + } +} diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParser.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParser.java new file mode 100644 index 000000000..19532bb72 --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParser.java @@ -0,0 +1,194 @@ +package cwms.cda.data.dto.timeseriesprofile; + +import java.math.BigInteger; +import java.util.List; +import java.util.Objects; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import cwms.cda.api.errors.FieldException; +import cwms.cda.data.dto.CwmsDTO; +import cwms.cda.formatters.Formats; +import cwms.cda.formatters.annotations.FormattableWith; +import cwms.cda.formatters.json.JsonV2; + +@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class) +@JsonDeserialize(builder = TimeSeriesProfileParser.Builder.class) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) +public class TimeSeriesProfileParser extends CwmsDTO +{ + private final String locationId; + private final String keyParameter; + private final char recordDelimiter; + private final char fieldDelimiter; + private final String timeFormat; + private final String timeZone; + private final int timeField; + private final List parameterInfo; + private final boolean timeInTwoFields; + protected TimeSeriesProfileParser(Builder builder) + { + super(builder.officeId); + locationId = builder.locationId; + keyParameter = builder.keyParameter; + recordDelimiter = builder.recordDelimiter; + fieldDelimiter = builder.fieldDelimiter; + timeFormat = builder.timeFormat; + timeZone = builder.timeZone; + timeField = builder.timeField; + parameterInfo = builder.parameterInfo; + timeInTwoFields = builder.timeInTwoFields; + } + + @Override + public void validate() throws FieldException + { + + } + + + public String getLocationId() + { + return locationId; + } + + public String getKeyParameter() + { + return keyParameter; + } + public String getRecordDelimiter(){ return String.valueOf(recordDelimiter); } + public String getFieldDelimiter(){ return String.valueOf(fieldDelimiter); } + public List getParameterInfo () + { + return parameterInfo; + } + + public String getTimeFormat() + { + return timeFormat; + } + + public String getTimeZone() + { + return timeZone; + } + + public BigInteger getTimeField() + { + return BigInteger.valueOf(timeField); + } + + public String getTimeInTwoFields() + { + return timeInTwoFields?"T":"F"; + } + + @Override + public int hashCode() { + int result = Objects.hashCode(getLocationId()); + result = 31 * result + Objects.hashCode(getFieldDelimiter()); + result = 31 * result + Objects.hashCode(getOfficeId()); + result = 31 * result + Objects.hashCode(getKeyParameter()); + result = 31 * result + Objects.hashCode(getTimeField()); + result = 31 * result + Objects.hashCode(getTimeFormat()); + result = 31 * result + Objects.hashCode(getParameterInfo()); + result = 31 * result + Objects.hashCode(getRecordDelimiter()); + result = 31 * result + Objects.hashCode(getTimeZone()); + result = 31 * result + Objects.hashCode(getTimeInTwoFields()); + return result; + } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + TimeSeriesProfileParser that = (TimeSeriesProfileParser) o; + return Objects.equals(getLocationId(), that.getLocationId()) + && Objects.equals(getFieldDelimiter(), that.getFieldDelimiter()) + && Objects.equals(getOfficeId(), that.getOfficeId()) + && Objects.equals(getKeyParameter(), that.getKeyParameter()) + && Objects.equals(getTimeField(), that.getTimeField()) + && Objects.equals(getTimeFormat(), that.getTimeFormat()) + && Objects.equals(getParameterInfo(), that.getParameterInfo()) + && Objects.equals(getRecordDelimiter(), that.getRecordDelimiter()) + && Objects.equals(getTimeZone(), that.getTimeZone()) + && Objects.equals(getTimeInTwoFields(), that.getTimeInTwoFields()); + } + + @JsonPOJOBuilder + @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) + public static final class Builder { + private String officeId; + private List parameterInfo; + private String keyParameter; + private char recordDelimiter; + private char fieldDelimiter; + private String timeFormat; + private String timeZone; + private int timeField; + private boolean timeInTwoFields; + private String locationId; + + public TimeSeriesProfileParser.Builder withLocationId(String locationId) { + this.locationId = locationId; + return this; + } + + public TimeSeriesProfileParser.Builder withKeyParameter(String keyParameter) { + this.keyParameter = keyParameter; + return this; + } + public TimeSeriesProfileParser.Builder withRecordDelimiter(char delimiter) { + this.recordDelimiter = delimiter; + return this; + } + public TimeSeriesProfileParser.Builder withFieldDelimiter(char delimiter) { + this.fieldDelimiter = delimiter; + return this; + } + public TimeSeriesProfileParser.Builder withTimeFormat(String timeFormat) + { + this.timeFormat = timeFormat; + return this; + } + public TimeSeriesProfileParser.Builder withTimeZone(String timeZone) + { + this.timeZone = timeZone; + return this; + } + public TimeSeriesProfileParser.Builder withTimeField(int field) + { + this.timeField = field; + return this; + } + public TimeSeriesProfileParser.Builder withTimeInTwoFields(boolean timeInTwoFields) + { + this.timeInTwoFields = timeInTwoFields; + return this; + } + public TimeSeriesProfileParser.Builder withParameterInfoList(List parameterInfoList) + { + this.parameterInfo =parameterInfoList; + return this; + } + + public TimeSeriesProfileParser.Builder withOfficeId(String officeId) { + this.officeId = officeId; + return this; + } + + + public TimeSeriesProfileParser build() { + return new TimeSeriesProfileParser(this); + } + } + +} From 994c9084bdb54138701f4e21ba4fa90f0b7c581b Mon Sep 17 00:00:00 2001 From: Andreas Christmann Date: Wed, 19 Jun 2024 15:11:13 -0700 Subject: [PATCH 07/13] time series profile dao's --- .../TimeSeriesProfileDao.java | 48 +++++++++++++++++++ .../TimeSeriesProfileInstanceDao.java | 21 ++++++++ 2 files changed, 69 insertions(+) create mode 100644 cwms-data-api/src/main/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileDao.java create mode 100644 cwms-data-api/src/main/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileInstanceDao.java diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileDao.java b/cwms-data-api/src/main/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileDao.java new file mode 100644 index 000000000..a44a6d565 --- /dev/null +++ b/cwms-data-api/src/main/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileDao.java @@ -0,0 +1,48 @@ +package cwms.cda.data.dao.timeseriesprofile; + +import java.util.List; + +import cwms.cda.data.dao.JooqDao; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfile; +import org.jooq.DSLContext; +import org.jooq.impl.DSL; + +import usace.cwms.db.jooq.codegen.packages.CWMS_TS_PROFILE_PACKAGE; + +public class TimeSeriesProfileDao extends JooqDao +{ + public TimeSeriesProfileDao(DSLContext dsl) + { + super(dsl); + } + public void storeTimeSeriesProfile(TimeSeriesProfile timeSeriesProfile, boolean failIfExists) { + + connection(dsl, conn -> { + List parameterList = timeSeriesProfile.getParameterList(); + String parameterString = parameterList.get(0); + for(int i=1; i Date: Wed, 19 Jun 2024 15:15:54 -0700 Subject: [PATCH 08/13] time series profile dto's unit test --- .../timeseriesprofile/ParameterInfoTest.java | 5 ++ .../TimeSeriesProfileInstanceTest.java | 5 ++ .../TimeSeriesProfileParserTest.java | 61 +++++++++++++++ .../TimeSeriesProfileTest.java | 74 +++++++++++++++++++ 4 files changed, 145 insertions(+) create mode 100644 cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfoTest.java create mode 100644 cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileInstanceTest.java create mode 100644 cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParserTest.java create mode 100644 cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileTest.java diff --git a/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfoTest.java b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfoTest.java new file mode 100644 index 000000000..7de1adaca --- /dev/null +++ b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/ParameterInfoTest.java @@ -0,0 +1,5 @@ +package cwms.cda.data.dto.timeseriesprofile; + +public class ParameterInfoTest +{ +} diff --git a/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileInstanceTest.java b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileInstanceTest.java new file mode 100644 index 000000000..bb05555cd --- /dev/null +++ b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileInstanceTest.java @@ -0,0 +1,5 @@ +package cwms.cda.data.dto.timeseriesprofile; + +public class TimeSeriesProfileInstanceTest +{ +} diff --git a/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParserTest.java b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParserTest.java new file mode 100644 index 000000000..a59003f7f --- /dev/null +++ b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParserTest.java @@ -0,0 +1,61 @@ +package cwms.cda.data.dto.timeseriesprofile; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import cwms.cda.formatters.ContentType; +import cwms.cda.formatters.Formats; +import cwms.cda.formatters.json.JsonV2; +import fixtures.CwmsDataApiSetupCallback; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TimeSeriesProfileParserTest +{ + @Test + void testTimeSeriesProfileSerializationRoundTrip() throws JsonProcessingException + { + TimeSeriesProfileParser timeSeriesProfileParser = buildTestTimeSeriesProfileParser(); + ContentType contentType = Formats.parseHeader(Formats.JSONV2); + + ObjectMapper om = JsonV2.buildObjectMapper(); + String serializedLocation = om.writeValueAsString(timeSeriesProfileParser); + + String serialized = Formats.format(contentType, timeSeriesProfileParser); + TimeSeriesProfileParser deserialized = Formats.parseContent(Formats.parseHeader(Formats.JSONV2), serialized, TimeSeriesProfileParser.class); + assertEquals(timeSeriesProfileParser, deserialized, "Roundtrip serialization failed"); + assertEquals( timeSeriesProfileParser.hashCode(), deserialized.hashCode(), + "Roundtrip serialization failed"); + } + private static TimeSeriesProfileParser buildTestTimeSeriesProfileParser() { + List parameterInfo= new ArrayList<>(); + parameterInfo.add (new ParameterInfo.Builder() + .withParameter("Depth") + .withIndex(3) + .withUnit("m") + .build()); + parameterInfo.add (new ParameterInfo.Builder() + .withParameter("Temp-Water") + .withIndex(5) + .withUnit("F") + .build()); + return + + new TimeSeriesProfileParser.Builder() + .withOfficeId("SWT") + .withLocationId("TIMESERIESPROFILE_LOC") + .withKeyParameter("Depth") + .withRecordDelimiter((char) 10) + .withFieldDelimiter(',') + .withTimeFormat("MM/DD/YYYY,HH24:MI:SS") + .withTimeZone("UTC") + .withTimeField(1) + .withTimeInTwoFields(false) + .withParameterInfoList(parameterInfo) + .build(); + } + +} diff --git a/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileTest.java b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileTest.java new file mode 100644 index 000000000..c5520bf73 --- /dev/null +++ b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileTest.java @@ -0,0 +1,74 @@ +package cwms.cda.data.dto.timeseriesprofile; + +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +import cwms.cda.formatters.ContentType; +import cwms.cda.formatters.Formats; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +final class TimeSeriesProfileTest +{ + @Test + void testTimeSeriesProfileSerializationRoundTrip() { + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile(); + ContentType contentType = Formats.parseHeader(Formats.JSONV2); + String serialized = Formats.format(contentType, timeSeriesProfile); + TimeSeriesProfile deserialized = Formats.parseContent(Formats.parseHeader(Formats.JSONV2), serialized, TimeSeriesProfile.class); + assertEquals(timeSeriesProfile, deserialized, "Roundtrip serialization failed"); + assertEquals(timeSeriesProfile.hashCode(), deserialized.hashCode(), "Roundtrip serialization failed"); + } + + @Test + void testTimeSeriesProfileSerializationRoundTripFromFile() throws Exception { + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile(); + InputStream resource = this.getClass().getResourceAsStream("/cwms/cda/data/dto/timeseriesprofile/timeseriesprofile.json"); + assertNotNull(resource); + String serialized = IOUtils.toString(resource, StandardCharsets.UTF_8); + TimeSeriesProfile deserialized = Formats.parseContent(Formats.parseHeader(Formats.JSONV2), serialized, TimeSeriesProfile.class); + assertEquals(timeSeriesProfile, deserialized, "Roundtrip serialization failed"); + } + +// @Test +// void testValidate() { +// Location location = buildTestLocation(); +// String projectId = "project"; +// assertAll(() -> { +// Embankment embankment = new Embankment.Builder().build(); +// assertThrows(FieldException.class, embankment::validate, +// "Expected validate() to throw FieldException because Location field can't be null, but it didn't"); +// }, () -> { +// Embankment embankment = new Embankment.Builder().withLocation(location).build(); +// assertThrows(FieldException.class, embankment::validate, +// "Expected validate() to throw FieldException because Project Id field can't be null, but it didn't"); +// }, () -> { +// Embankment embankment = new Embankment.Builder().withLocation(location).withProjectId(projectId).build(); +// assertThrows(FieldException.class, embankment::validate, +// "Expected validate() to throw FieldException because Project Office Id field can't be null, but it didn't"); +// }, () -> { +// Embankment embankment = new Embankment.Builder().withLocation(location).withProjectId(projectId).withProjectOfficeId("SPK").build(); +// assertThrows(FieldException.class, embankment::validate, +// "Expected validate() to throw FieldException because Structure type field can't be null, but it didn't"); +// } +// ); +// } + + private TimeSeriesProfile buildTestTimeSeriesProfile() { + return new TimeSeriesProfile.Builder() + .withOfficeId("Office") + .withKeyParameter("Depth") + .withRefTsId("TimeSeries") + .withLocationId("Location") + .withDescription("Description") + .withParameterList(Arrays.asList(new String[]{"Temperature", "Depth"})) + .build(); + } + +} From 8fbcb4e7b92fdf36207711a242880e0ee78f7a75 Mon Sep 17 00:00:00 2001 From: Andreas Christmann Date: Wed, 19 Jun 2024 15:17:02 -0700 Subject: [PATCH 09/13] time series profile dao integration test --- .../TimeSeriesProfileParserDaoIT.java | 183 ++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 cwms-data-api/src/test/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileParserDaoIT.java diff --git a/cwms-data-api/src/test/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileParserDaoIT.java b/cwms-data-api/src/test/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileParserDaoIT.java new file mode 100644 index 000000000..a499ae723 --- /dev/null +++ b/cwms-data-api/src/test/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileParserDaoIT.java @@ -0,0 +1,183 @@ +package cwms.cda.data.dao.timeseriesprofile; + +import java.io.IOException; +import java.sql.SQLException; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import cwms.cda.api.DataApiTestIT; +import cwms.cda.api.enums.Nation; +import cwms.cda.data.dao.LocationsDaoImpl; +import cwms.cda.data.dto.Location; +import cwms.cda.data.dto.timeseriesprofile.ParameterInfo; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfile; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfileParser; +import fixtures.CwmsDataApiSetupCallback; +import mil.army.usace.hec.test.database.CwmsDatabaseContainer; +import org.jooq.DSLContext; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import static cwms.cda.data.dao.DaoTest.getDslContext; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertThrowsExactly; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Tag("integration") +final class TimeSeriesProfileParserDaoIT extends DataApiTestIT +{ + private static final Location TIMESERIESPORFILE_LOC = buildTestLocation(); + + @BeforeAll + public static void setup() throws Exception + { + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + LocationsDaoImpl locationsDao = new LocationsDaoImpl(context); + try + { + locationsDao.storeLocation(TIMESERIESPORFILE_LOC); + } + catch(IOException e) + { + throw new RuntimeException(e); + } + }); + } + + @AfterAll + public static void tearDown() throws Exception { + + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + LocationsDaoImpl locationsDao = new LocationsDaoImpl(context); + locationsDao.deleteLocation(TIMESERIESPORFILE_LOC.getName(), databaseLink.getOfficeId()); + }); + } + + @Test + void testStoreAndRetrieve() throws Exception { + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + + TimeSeriesProfileDao timeSeriesProfileDao = new TimeSeriesProfileDao(context); + + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile(); + timeSeriesProfileDao.storeTimeSeriesProfile(timeSeriesProfile, false); + + TimeSeriesProfileParserDao timeSeriesProfileParserDao = new TimeSeriesProfileParserDao(context); + TimeSeriesProfileParser timeSeriesProfileParser = buildTestTimeSeriesProfileParser(); + timeSeriesProfileParserDao.storeTimeSeriesProfileParser(timeSeriesProfileParser, false); + + TimeSeriesProfileParser retrieved = timeSeriesProfileParserDao.retrieveTimeSeriesProfileParser(timeSeriesProfileParser.getLocationId(), + timeSeriesProfileParser.getKeyParameter(), timeSeriesProfileParser.getOfficeId()); + assertEquals(timeSeriesProfileParser, retrieved); + + timeSeriesProfileParserDao.deleteTimeSeriesProfileParser(timeSeriesProfileParser.getLocationId(), + timeSeriesProfileParser.getKeyParameter(), timeSeriesProfileParser.getOfficeId()); + }); + } + + @Test + void testStoreAndDelete() throws SQLException + { + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + + TimeSeriesProfileDao timeSeriesProfileDao = new TimeSeriesProfileDao(context); + + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile(); + timeSeriesProfileDao.storeTimeSeriesProfile(timeSeriesProfile, false); + + TimeSeriesProfileParserDao timeSeriesProfileParserDao = new TimeSeriesProfileParserDao(context); + TimeSeriesProfileParser timeSeriesProfileParser = buildTestTimeSeriesProfileParser(); + timeSeriesProfileParserDao.storeTimeSeriesProfileParser(timeSeriesProfileParser, false); + + timeSeriesProfileParserDao.deleteTimeSeriesProfileParser(timeSeriesProfileParser.getLocationId(), + timeSeriesProfileParser.getKeyParameter(), timeSeriesProfileParser.getOfficeId()); + + assertThrows(Exception.class, ()->timeSeriesProfileParserDao.retrieveTimeSeriesProfileParser( + timeSeriesProfileParser.getLocationId(), + timeSeriesProfileParser.getKeyParameter(), timeSeriesProfileParser.getOfficeId())); + + }); + } + + @Test + void testStoreAndRetrieveMultiple() + { + // TODO + } + @Test + void testStoreAndCopy() + { + // TODO + } + private static TimeSeriesProfile buildTestTimeSeriesProfile() + { + String officeId = CwmsDataApiSetupCallback.getDatabaseLink().getOfficeId(); + return new TimeSeriesProfile.Builder() + .withOfficeId(officeId) + .withLocationId("TIMESERIESPROFILE_LOC") + .withKeyParameter("Depth") + .withParameterList(Arrays.asList(new String[]{"Pres", "Depth"})) + .build(); + + } + private static TimeSeriesProfileParser buildTestTimeSeriesProfileParser() { + List parameterInfoList = new ArrayList<>(); + parameterInfoList.add( new ParameterInfo.Builder() + .withParameter("Depth") + .withIndex(3) + .withUnit("m") + .build()); + parameterInfoList.add( new ParameterInfo.Builder() + .withParameter("Temp-Water") + .withIndex(4) + .withUnit("F") + .build()); + + String officeId = CwmsDataApiSetupCallback.getDatabaseLink().getOfficeId(); + return + + new TimeSeriesProfileParser.Builder() + .withOfficeId(officeId) + .withLocationId("TIMESERIESPROFILE_LOC") + .withKeyParameter("Depth") + .withRecordDelimiter((char) 10) + .withFieldDelimiter(',') + .withTimeFormat("MM/DD/YYYY,HH24:MI:SS") + .withTimeZone("UTC") + .withTimeField(1) + .withTimeInTwoFields(false) + .withParameterInfoList(parameterInfoList) + .build(); + } + + private static Location buildTestLocation() { + String officeId = CwmsDataApiSetupCallback.getDatabaseLink().getOfficeId(); + return new Location.Builder("TIMESERIESPROFILE_LOC", "SITE", ZoneId.of("UTC"), + 38.5613824, -121.7298432, "NVGD29", officeId) + .withElevation(10.0) + .withLocationType("SITE") + .withCountyName("Sacramento") + .withNation(Nation.US) + .withActive(true) + .withStateInitial("CA") + .withBoundingOfficeId(officeId) + .withPublishedLatitude(38.5613824) + .withPublishedLongitude(-121.7298432) + .withLongName("UNITED STATES") + .withDescription("for testing") + .build(); + } +} From 814dd5469e0cb72a2922fa1e82ce3959e75548fd Mon Sep 17 00:00:00 2001 From: Andreas Christmann Date: Thu, 20 Jun 2024 12:32:33 -0700 Subject: [PATCH 10/13] time series profile unit test --- .../TimeSeriesProfileTest.java | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileTest.java b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileTest.java index c5520bf73..91568871b 100644 --- a/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileTest.java +++ b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileTest.java @@ -36,30 +36,6 @@ void testTimeSeriesProfileSerializationRoundTripFromFile() throws Exception { assertEquals(timeSeriesProfile, deserialized, "Roundtrip serialization failed"); } -// @Test -// void testValidate() { -// Location location = buildTestLocation(); -// String projectId = "project"; -// assertAll(() -> { -// Embankment embankment = new Embankment.Builder().build(); -// assertThrows(FieldException.class, embankment::validate, -// "Expected validate() to throw FieldException because Location field can't be null, but it didn't"); -// }, () -> { -// Embankment embankment = new Embankment.Builder().withLocation(location).build(); -// assertThrows(FieldException.class, embankment::validate, -// "Expected validate() to throw FieldException because Project Id field can't be null, but it didn't"); -// }, () -> { -// Embankment embankment = new Embankment.Builder().withLocation(location).withProjectId(projectId).build(); -// assertThrows(FieldException.class, embankment::validate, -// "Expected validate() to throw FieldException because Project Office Id field can't be null, but it didn't"); -// }, () -> { -// Embankment embankment = new Embankment.Builder().withLocation(location).withProjectId(projectId).withProjectOfficeId("SPK").build(); -// assertThrows(FieldException.class, embankment::validate, -// "Expected validate() to throw FieldException because Structure type field can't be null, but it didn't"); -// } -// ); -// } - private TimeSeriesProfile buildTestTimeSeriesProfile() { return new TimeSeriesProfile.Builder() .withOfficeId("Office") From 5c8ed92d20adb1bcb955e23d3cb85f4eda9af280 Mon Sep 17 00:00:00 2001 From: Andreas Christmann Date: Fri, 21 Jun 2024 12:55:35 -0700 Subject: [PATCH 11/13] added db cleanup --- .../TimeSeriesProfileDaoIT.java | 182 ++++++++++++++++++ 1 file changed, 182 insertions(+) create mode 100644 cwms-data-api/src/test/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileDaoIT.java diff --git a/cwms-data-api/src/test/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileDaoIT.java b/cwms-data-api/src/test/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileDaoIT.java new file mode 100644 index 000000000..e76b22627 --- /dev/null +++ b/cwms-data-api/src/test/java/cwms/cda/data/dao/timeseriesprofile/TimeSeriesProfileDaoIT.java @@ -0,0 +1,182 @@ +package cwms.cda.data.dao.timeseriesprofile; + +import java.io.IOException; +import java.sql.SQLException; +import java.time.ZoneId; +import java.util.Arrays; +import java.util.List; + +import cwms.cda.api.DataApiTestIT; +import cwms.cda.api.enums.Nation; +import cwms.cda.data.dao.LocationsDaoImpl; +import cwms.cda.data.dto.Location; +import cwms.cda.data.dto.timeseriesprofile.TimeSeriesProfile; +import fixtures.CwmsDataApiSetupCallback; +import mil.army.usace.hec.test.database.CwmsDatabaseContainer; +import org.jooq.DSLContext; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import static cwms.cda.data.dao.DaoTest.getDslContext; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@Tag("integration") +public class TimeSeriesProfileDaoIT extends DataApiTestIT +{ + private static final Location LOCATION_AAA = buildTestLocation("AAA"); + private static final Location TIMESERIESPROFILE_LOC = buildTestLocation("TIMESERIESPROFILE_LOC"); + @BeforeAll + public static void setup() throws Exception + { + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + LocationsDaoImpl locationsDao = new LocationsDaoImpl(context); + try + { + locationsDao.storeLocation(LOCATION_AAA); + locationsDao.storeLocation(TIMESERIESPROFILE_LOC); + } + catch(IOException e) + { + throw new RuntimeException(e); + } + }); + } + + @AfterAll + public static void tearDown() throws Exception { + + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + LocationsDaoImpl locationsDao = new LocationsDaoImpl(context); + locationsDao.deleteLocation(LOCATION_AAA.getName(), LOCATION_AAA.getOfficeId()); + locationsDao.deleteLocation(TIMESERIESPROFILE_LOC.getName(), TIMESERIESPROFILE_LOC.getOfficeId()); + }); + } + + @Test + void testCopyTimeSeriesProfile() throws SQLException + { + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + + TimeSeriesProfileDao timeSeriesProfileDao = new TimeSeriesProfileDao(context); + + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile("Depth"); + + timeSeriesProfileDao.storeTimeSeriesProfile(timeSeriesProfile, false); + timeSeriesProfileDao.copyTimeSeriesProfile(timeSeriesProfile.getLocationId(), timeSeriesProfile.getKeyParameter(), + "AAA","",timeSeriesProfile.getOfficeId()); + TimeSeriesProfile timeSeriesProfileCopied = timeSeriesProfileDao.retrieveTimeSeriesProfile("AAA", + timeSeriesProfile.getKeyParameter(), timeSeriesProfile.getOfficeId()); + assertEquals("AAA", timeSeriesProfileCopied.getLocationId()); + assertEquals(timeSeriesProfile.getKeyParameter(), timeSeriesProfileCopied.getKeyParameter()); + assertEquals(timeSeriesProfile.getParameterList(),timeSeriesProfileCopied.getParameterList()); + + timeSeriesProfileDao.deleteTimeSeriesProfile(timeSeriesProfile.getLocationId(),timeSeriesProfile.getKeyParameter(),timeSeriesProfile.getOfficeId()); + timeSeriesProfileDao.deleteTimeSeriesProfile(timeSeriesProfileCopied.getLocationId(),timeSeriesProfileCopied.getKeyParameter(),timeSeriesProfileCopied.getOfficeId()); + }); + } + @Test + void testRetrieveTimeSeriesProfile() throws Exception { + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + + TimeSeriesProfileDao timeSeriesProfileDao = new TimeSeriesProfileDao(context); + + TimeSeriesProfile timeSeriesProfileIn = (buildTestTimeSeriesProfile("Depth")); + timeSeriesProfileDao.storeTimeSeriesProfile(timeSeriesProfileIn, false); + + TimeSeriesProfile timeSeriesProfileOut = timeSeriesProfileDao.retrieveTimeSeriesProfile(timeSeriesProfileIn.getLocationId(), + timeSeriesProfileIn.getKeyParameter(), timeSeriesProfileIn.getOfficeId()); + + assertEquals(timeSeriesProfileOut, timeSeriesProfileIn); + + timeSeriesProfileDao.deleteTimeSeriesProfile(timeSeriesProfileIn.getLocationId(), + timeSeriesProfileIn.getKeyParameter(), timeSeriesProfileIn.getOfficeId()); + }); + } + + @Test + void testRetrieveCatalog() throws Exception { + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + + TimeSeriesProfileDao timeSeriesProfileDao = new TimeSeriesProfileDao(context); + timeSeriesProfileDao.storeTimeSeriesProfile(buildTestTimeSeriesProfile("Depth"), false); + timeSeriesProfileDao.storeTimeSeriesProfile(buildTestTimeSeriesProfile("Pres"), false); + + + List timeSeriesProfileListBefore = + timeSeriesProfileDao.retrieveTimeSeriesProfiles("*", "*", "*"); + + for(TimeSeriesProfile timeSeriesProfile: timeSeriesProfileListBefore) + { + timeSeriesProfileDao.deleteTimeSeriesProfile(timeSeriesProfile.getLocationId(), timeSeriesProfile.getKeyParameter(), + timeSeriesProfile.getOfficeId()); + } + List timeSeriesProfileListAfter = timeSeriesProfileDao.retrieveTimeSeriesProfiles("*", "*", "*"); + + assertEquals(0,timeSeriesProfileListAfter.size()); + assertEquals(2,timeSeriesProfileListBefore.size()); + }); + } + @Test + void testDeleteTimeSeriesProfile() throws Exception { + CwmsDatabaseContainer databaseLink = CwmsDataApiSetupCallback.getDatabaseLink(); + databaseLink.connection(c -> { + DSLContext context = getDslContext(c, databaseLink.getOfficeId()); + + TimeSeriesProfileDao timeSeriesProfileDao = new TimeSeriesProfileDao(context); + TimeSeriesProfile timeSeriesProfile = buildTestTimeSeriesProfile("Depth"); + timeSeriesProfileDao.storeTimeSeriesProfile(buildTestTimeSeriesProfile("Depth"), false); + + List timeSeriesProfileListBefore = + timeSeriesProfileDao.retrieveTimeSeriesProfiles("*", "*", "*"); + + timeSeriesProfileDao.deleteTimeSeriesProfile(timeSeriesProfile.getLocationId(), timeSeriesProfile.getKeyParameter(), + timeSeriesProfile.getOfficeId()); + + List timeSeriesProfileListAfter = + timeSeriesProfileDao.retrieveTimeSeriesProfiles("*", "*", "*"); + + + assertEquals(timeSeriesProfileListBefore.size()-1,timeSeriesProfileListAfter.size()); + }); + } + private static Location buildTestLocation(String location) { + String officeId = CwmsDataApiSetupCallback.getDatabaseLink().getOfficeId(); + return new Location.Builder(location, "SITE", ZoneId.of("UTC"), + 38.5613824, -121.7298432, "NVGD29", officeId) + .withElevation(10.0) + .withLocationType("SITE") + .withCountyName("Sacramento") + .withNation(Nation.US) + .withActive(true) + .withStateInitial("CA") + .withBoundingOfficeId(officeId) + .withPublishedLatitude(38.5613824) + .withPublishedLongitude(-121.7298432) + .withLongName("UNITED STATES") + .withDescription("for testing") + .build(); + } + private static TimeSeriesProfile buildTestTimeSeriesProfile(String keyParameter) + { + String officeId = CwmsDataApiSetupCallback.getDatabaseLink().getOfficeId(); + return new TimeSeriesProfile.Builder() + .withOfficeId(officeId) + .withLocationId("TIMESERIESPROFILE_LOC") + .withKeyParameter(keyParameter) + .withParameterList(Arrays.asList("Pres", "Depth")) + .build(); + + } +} From a1aead4ff74d8c697e4939d7556bd426d8de5cd8 Mon Sep 17 00:00:00 2001 From: Andreas Christmann Date: Tue, 25 Jun 2024 14:46:33 -0700 Subject: [PATCH 12/13] moved equals to test classes and removed hashcode --- .../timeseriesprofile/TimeSeriesProfile.java | 31 +--------- .../TimeSeriesProfileParser.java | 61 ++++--------------- .../TimeSeriesProfileParserTest.java | 45 +++++++++----- .../TimeSeriesProfileTest.java | 17 +++--- .../timeseriesprofileparser.json | 6 +- 5 files changed, 59 insertions(+), 101 deletions(-) diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfile.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfile.java index 16805ff59..30f89f170 100644 --- a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfile.java +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfile.java @@ -2,7 +2,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.Objects; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.PropertyNamingStrategies; @@ -23,6 +22,7 @@ public final class TimeSeriesProfile extends CwmsDTO { @Schema(description = "Location ID") + // TODO replace with CWMSID private final String locationId; @Schema(description = "Description") private final String description; @@ -31,6 +31,7 @@ public final class TimeSeriesProfile extends CwmsDTO @Schema(description = "Key Parameter") private final String keyParameter; @Schema(description = "Reference TS") + // TODO replace with CWMSID private final String refTsId; private TimeSeriesProfile(Builder builder) @@ -89,34 +90,6 @@ public void validate() throws FieldException } } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - TimeSeriesProfile that = (TimeSeriesProfile) o; - return Objects.equals(getLocationId(), that.getLocationId()) - && Objects.equals(getOfficeId(), that.getOfficeId()) - && Objects.equals(getDescription(), that.getDescription()) - && Objects.equals(getKeyParameter(), that.getKeyParameter()) - && Objects.equals(getRefTsId(), that.getRefTsId()) - && Objects.equals(getParameterList(), that.getParameterList()) - ; - } - @Override - public int hashCode() { - int result = Objects.hashCode(getDescription()); - result = 31 * result + Objects.hashCode(getKeyParameter()); - result = 31 * result + Objects.hashCode(getLocationId()); - result = 31 * result + Objects.hashCode(getParameterList()); - result = 31 * result + Objects.hashCode(getOfficeId()); - result = 31 * result + Objects.hashCode(getRefTsId()); - return result; - } @JsonPOJOBuilder @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) public static final class Builder { diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParser.java b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParser.java index 19532bb72..b9774a380 100644 --- a/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParser.java +++ b/cwms-data-api/src/main/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParser.java @@ -2,8 +2,6 @@ import java.math.BigInteger; import java.util.List; -import java.util.Objects; - import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @@ -28,7 +26,7 @@ public class TimeSeriesProfileParser extends CwmsDTO private final String timeFormat; private final String timeZone; private final int timeField; - private final List parameterInfo; + private final List parameterInfoList; private final boolean timeInTwoFields; protected TimeSeriesProfileParser(Builder builder) { @@ -40,14 +38,16 @@ protected TimeSeriesProfileParser(Builder builder) timeFormat = builder.timeFormat; timeZone = builder.timeZone; timeField = builder.timeField; - parameterInfo = builder.parameterInfo; + parameterInfoList = builder.parameterInfoList; timeInTwoFields = builder.timeInTwoFields; } @Override public void validate() throws FieldException { - + if (this.keyParameter == null) { + throw new FieldException("Key Parameter field can't be null"); + } } @@ -60,11 +60,11 @@ public String getKeyParameter() { return keyParameter; } - public String getRecordDelimiter(){ return String.valueOf(recordDelimiter); } - public String getFieldDelimiter(){ return String.valueOf(fieldDelimiter); } - public List getParameterInfo () + public char getRecordDelimiter(){ return recordDelimiter; } + public char getFieldDelimiter(){ return fieldDelimiter; } + public List getParameterInfoList () { - return parameterInfo; + return parameterInfoList; } public String getTimeFormat() @@ -82,52 +82,17 @@ public BigInteger getTimeField() return BigInteger.valueOf(timeField); } - public String getTimeInTwoFields() + public boolean getTimeInTwoFields() { - return timeInTwoFields?"T":"F"; - } - - @Override - public int hashCode() { - int result = Objects.hashCode(getLocationId()); - result = 31 * result + Objects.hashCode(getFieldDelimiter()); - result = 31 * result + Objects.hashCode(getOfficeId()); - result = 31 * result + Objects.hashCode(getKeyParameter()); - result = 31 * result + Objects.hashCode(getTimeField()); - result = 31 * result + Objects.hashCode(getTimeFormat()); - result = 31 * result + Objects.hashCode(getParameterInfo()); - result = 31 * result + Objects.hashCode(getRecordDelimiter()); - result = 31 * result + Objects.hashCode(getTimeZone()); - result = 31 * result + Objects.hashCode(getTimeInTwoFields()); - return result; + return timeInTwoFields; } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - TimeSeriesProfileParser that = (TimeSeriesProfileParser) o; - return Objects.equals(getLocationId(), that.getLocationId()) - && Objects.equals(getFieldDelimiter(), that.getFieldDelimiter()) - && Objects.equals(getOfficeId(), that.getOfficeId()) - && Objects.equals(getKeyParameter(), that.getKeyParameter()) - && Objects.equals(getTimeField(), that.getTimeField()) - && Objects.equals(getTimeFormat(), that.getTimeFormat()) - && Objects.equals(getParameterInfo(), that.getParameterInfo()) - && Objects.equals(getRecordDelimiter(), that.getRecordDelimiter()) - && Objects.equals(getTimeZone(), that.getTimeZone()) - && Objects.equals(getTimeInTwoFields(), that.getTimeInTwoFields()); - } @JsonPOJOBuilder @JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class) public static final class Builder { private String officeId; - private List parameterInfo; + private List parameterInfoList; private String keyParameter; private char recordDelimiter; private char fieldDelimiter; @@ -176,7 +141,7 @@ public TimeSeriesProfileParser.Builder withTimeInTwoFields(boolean timeInTwoFiel } public TimeSeriesProfileParser.Builder withParameterInfoList(List parameterInfoList) { - this.parameterInfo =parameterInfoList; + this.parameterInfoList =parameterInfoList; return this; } diff --git a/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParserTest.java b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParserTest.java index a59003f7f..ab1c514c4 100644 --- a/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParserTest.java +++ b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileParserTest.java @@ -1,34 +1,39 @@ package cwms.cda.data.dto.timeseriesprofile; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import cwms.cda.formatters.ContentType; import cwms.cda.formatters.Formats; -import cwms.cda.formatters.json.JsonV2; -import fixtures.CwmsDataApiSetupCallback; +import org.apache.commons.io.IOUtils; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; -public class TimeSeriesProfileParserTest +final class TimeSeriesProfileParserTest { @Test - void testTimeSeriesProfileSerializationRoundTrip() throws JsonProcessingException + void testTimeSeriesProfileSerializationRoundTrip() { TimeSeriesProfileParser timeSeriesProfileParser = buildTestTimeSeriesProfileParser(); ContentType contentType = Formats.parseHeader(Formats.JSONV2); - ObjectMapper om = JsonV2.buildObjectMapper(); - String serializedLocation = om.writeValueAsString(timeSeriesProfileParser); - String serialized = Formats.format(contentType, timeSeriesProfileParser); TimeSeriesProfileParser deserialized = Formats.parseContent(Formats.parseHeader(Formats.JSONV2), serialized, TimeSeriesProfileParser.class); - assertEquals(timeSeriesProfileParser, deserialized, "Roundtrip serialization failed"); - assertEquals( timeSeriesProfileParser.hashCode(), deserialized.hashCode(), - "Roundtrip serialization failed"); + testAssertEquals(timeSeriesProfileParser, deserialized, "Roundtrip serialization failed"); + } + + @Test + void testTimeSeriesProfileSerializationRoundTripFromFile() throws Exception { + TimeSeriesProfileParser timeSeriesProfileParser = buildTestTimeSeriesProfileParser(); + InputStream resource = this.getClass().getResourceAsStream("/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileparser.json"); + assertNotNull(resource); + String serialized = IOUtils.toString(resource, StandardCharsets.UTF_8); + TimeSeriesProfileParser deserialized = Formats.parseContent(Formats.parseHeader(Formats.JSONV2), serialized, TimeSeriesProfileParser.class); + testAssertEquals(timeSeriesProfileParser, deserialized, "Roundtrip serialization from file failed"); } private static TimeSeriesProfileParser buildTestTimeSeriesProfileParser() { List parameterInfo= new ArrayList<>(); @@ -46,7 +51,7 @@ private static TimeSeriesProfileParser buildTestTimeSeriesProfileParser() { new TimeSeriesProfileParser.Builder() .withOfficeId("SWT") - .withLocationId("TIMESERIESPROFILE_LOC") + .withLocationId("location") .withKeyParameter("Depth") .withRecordDelimiter((char) 10) .withFieldDelimiter(',') @@ -57,5 +62,17 @@ private static TimeSeriesProfileParser buildTestTimeSeriesProfileParser() { .withParameterInfoList(parameterInfo) .build(); } - + private void testAssertEquals(TimeSeriesProfileParser expected, TimeSeriesProfileParser actual, String message) + { + assertEquals(expected.getLocationId(), actual.getLocationId(), message); + assertEquals(expected.getFieldDelimiter(), actual.getFieldDelimiter(), message); + assertEquals(expected.getOfficeId(), actual.getOfficeId(), message); + assertEquals(expected.getKeyParameter(), actual.getKeyParameter(), message); + assertEquals(expected.getTimeField(), actual.getTimeField(), message); + assertEquals(expected.getTimeFormat(), actual.getTimeFormat(), message); + // assertEquals(expected.getParameterInfo(), actual.getParameterInfo(),message); + assertEquals(expected.getRecordDelimiter(), actual.getRecordDelimiter(), message); + assertEquals(expected.getTimeZone(), actual.getTimeZone()); + assertEquals(expected.getTimeInTwoFields(), actual.getTimeInTwoFields()); + } } diff --git a/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileTest.java b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileTest.java index 91568871b..a8825e05e 100644 --- a/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileTest.java +++ b/cwms-data-api/src/test/java/cwms/cda/data/dto/timeseriesprofile/TimeSeriesProfileTest.java @@ -9,10 +9,8 @@ import org.apache.commons.io.IOUtils; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; final class TimeSeriesProfileTest { @@ -22,8 +20,7 @@ void testTimeSeriesProfileSerializationRoundTrip() { ContentType contentType = Formats.parseHeader(Formats.JSONV2); String serialized = Formats.format(contentType, timeSeriesProfile); TimeSeriesProfile deserialized = Formats.parseContent(Formats.parseHeader(Formats.JSONV2), serialized, TimeSeriesProfile.class); - assertEquals(timeSeriesProfile, deserialized, "Roundtrip serialization failed"); - assertEquals(timeSeriesProfile.hashCode(), deserialized.hashCode(), "Roundtrip serialization failed"); + testAssertEquals(timeSeriesProfile, deserialized, "Roundtrip serialization failed"); } @Test @@ -33,7 +30,7 @@ void testTimeSeriesProfileSerializationRoundTripFromFile() throws Exception { assertNotNull(resource); String serialized = IOUtils.toString(resource, StandardCharsets.UTF_8); TimeSeriesProfile deserialized = Formats.parseContent(Formats.parseHeader(Formats.JSONV2), serialized, TimeSeriesProfile.class); - assertEquals(timeSeriesProfile, deserialized, "Roundtrip serialization failed"); + testAssertEquals(timeSeriesProfile, deserialized, "Roundtrip serialization from file failed"); } private TimeSeriesProfile buildTestTimeSeriesProfile() { @@ -43,8 +40,14 @@ private TimeSeriesProfile buildTestTimeSeriesProfile() { .withRefTsId("TimeSeries") .withLocationId("Location") .withDescription("Description") - .withParameterList(Arrays.asList(new String[]{"Temperature", "Depth"})) + .withParameterList(Arrays.asList("Temperature", "Depth")) .build(); } - + private void testAssertEquals(TimeSeriesProfile expected, TimeSeriesProfile actual, String message) { + assertEquals(expected.getLocationId(), actual.getLocationId(), message); + assertEquals(expected.getDescription(), actual.getDescription(), message); + assertEquals(expected.getParameterList(), actual.getParameterList(), message); + assertEquals(expected.getKeyParameter(), actual.getKeyParameter(), message); + assertEquals(expected.getRefTsId(), actual.getRefTsId(), message); + } } diff --git a/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileparser.json b/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileparser.json index 7ca2c30e3..4a907c4bb 100644 --- a/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileparser.json +++ b/cwms-data-api/src/test/resources/cwms/cda/data/dto/timeseriesprofile/timeseriesprofileparser.json @@ -1,14 +1,14 @@ { "office-id": "SWT", - "location-id": "TIMESERIESPROFILE_LOC", + "location-id": "location", "key-parameter": "Depth", "record-delimiter": "\n", "field-delimiter": ",", "time-format": "MM/DD/YYYY,HH24:MI:SS", "time-zone": "UTC", "time-field": 1, - "time-in-two-fields": "F", - "parameter-info": [ + "time-in-two-fields": false, + "parameter-info-list": [ { "parameter":"Depth", "unit":"m", From 24de6336fac94c2e505862b5c3e659d81b63526e Mon Sep 17 00:00:00 2001 From: Andreas Date: Wed, 3 Dec 2025 12:33:01 -0800 Subject: [PATCH 13/13] added check for timeseries-ids size. Updating with 3 timeseries should give us 3 timeseries --- .../src/test/java/cwms/cda/api/ForecastSpecControllerTestIT.java | 1 + 1 file changed, 1 insertion(+) diff --git a/cwms-data-api/src/test/java/cwms/cda/api/ForecastSpecControllerTestIT.java b/cwms-data-api/src/test/java/cwms/cda/api/ForecastSpecControllerTestIT.java index 1996ee94f..6089d48ae 100644 --- a/cwms-data-api/src/test/java/cwms/cda/api/ForecastSpecControllerTestIT.java +++ b/cwms-data-api/src/test/java/cwms/cda/api/ForecastSpecControllerTestIT.java @@ -363,6 +363,7 @@ void test_create_get_update_get() throws IOException { .assertThat() .statusCode(is(HttpServletResponse.SC_OK)) .body("source-entity-id", equalTo("USGS")) + .body("time-series-ids.size()", equalTo(3)) ; }