Skip to content

Commit f232f39

Browse files
committed
CWMS-2197 Adds include alias flag for timeseries catalog
1 parent 4f5a6f1 commit f232f39

9 files changed

Lines changed: 436 additions & 77 deletions

File tree

cwms-data-api/src/main/java/cwms/cda/api/CatalogController.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static com.codahale.metrics.MetricRegistry.name;
44
import static cwms.cda.api.Controllers.ACCEPT;
5+
import static cwms.cda.api.Controllers.INCLUDE_ALIASES;
56
import static cwms.cda.api.Controllers.BOUNDING_OFFICE_LIKE;
67
import static cwms.cda.api.Controllers.CURSOR;
78
import static cwms.cda.api.Controllers.EXCLUDE_EMPTY;
@@ -168,6 +169,10 @@ public void getAll(Context ctx) {
168169
description = "Posix <a href=\"regexp.html\">regular expression</a> matching "
169170
+ "against the location type."
170171
),
172+
@OpenApiParam(name = INCLUDE_ALIASES, type = Boolean.class,
173+
description = "Whether to add aliases to the catalog entries. "
174+
+ "Default is false. If true, the aliases will be added to the "
175+
+ "catalog entries in the response."),
171176
},
172177
pathParams = {
173178
@OpenApiParam(name = "dataset",
@@ -230,7 +235,8 @@ public void getOne(@NotNull Context ctx, @NotNull String dataSet) {
230235

231236
String locationType = queryParamAsClass(ctx, new String[]{LOCATION_TYPE_LIKE},
232237
String.class, null, metrics, name(CatalogController.class.getName(), GET_ONE));
233-
238+
boolean includeAliases = ctx.queryParamAsClass(INCLUDE_ALIASES, Boolean.class)
239+
.getOrDefault(false);
234240
String acceptHeader = ctx.header(ACCEPT);
235241
ContentType contentType = Formats.parseHeader(acceptHeader, Catalog.class);
236242
Catalog cat = null;
@@ -254,6 +260,7 @@ public void getOne(@NotNull Context ctx, @NotNull String dataSet) {
254260
.withExcludeEmpty(excludeExtents)
255261
.withLocationKind(locationKind)
256262
.withLocationType(locationType)
263+
.withIncludeAliases(includeAliases)
257264
.build();
258265

259266
cat = tsDao.getTimeSeriesCatalog(cursor, pageSize, parameters);

cwms-data-api/src/main/java/cwms/cda/api/Controllers.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ public final class Controllers {
146146
public static final String ISSUE_DATE = "issue-date";
147147
public static final String LOCATION_KIND_LIKE = "location-kind-like";
148148
public static final String LOCATION_TYPE_LIKE = "location-type-like";
149+
public static final String INCLUDE_ALIASES = "include-aliases";
149150
public static final String MIN_NUMBER = "min-number";
150151
public static final String MAX_NUMBER = "max-number";
151152
public static final String MIN_HEIGHT = "min-height";

cwms-data-api/src/main/java/cwms/cda/data/dao/CatalogRequestParameters.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public class CatalogRequestParameters {
2020
private final boolean excludeEmpty;
2121
private final String locationKind;
2222
private final String locationType;
23+
private final boolean includeAliases;
2324

2425
private CatalogRequestParameters(Builder builder) {
2526
this.office = builder.office;
@@ -34,6 +35,7 @@ private CatalogRequestParameters(Builder builder) {
3435
this.excludeEmpty = builder.excludeEmpty;
3536
this.locationKind = builder.locationKind;
3637
this.locationType = builder.locationType;
38+
this.includeAliases = builder.includeAliases;
3739
}
3840

3941
public String getBoundingOfficeLike() {
@@ -84,6 +86,10 @@ public String getLocationType() {
8486
return locationType;
8587
}
8688

89+
public boolean includeAliases() {
90+
return includeAliases;
91+
}
92+
8793

8894
public static class Builder {
8995
String office;
@@ -98,6 +104,7 @@ public static class Builder {
98104
private boolean excludeEmpty = true;
99105
String locationKind;
100106
String locationType;
107+
private boolean includeAliases = false;
101108

102109
public Builder() {
103110

@@ -163,6 +170,11 @@ public Builder withLocationType(String locationType) {
163170
return this;
164171
}
165172

173+
public Builder withIncludeAliases(boolean includeAliases) {
174+
this.includeAliases = includeAliases;
175+
return this;
176+
}
177+
166178
public static Builder from(CatalogRequestParameters params) {
167179
// This NEEDS to include every field in the CatalogRequestParameters
168180
return new Builder()

cwms-data-api/src/main/java/cwms/cda/data/dao/TimeSeriesDaoImpl.java

Lines changed: 219 additions & 65 deletions
Large diffs are not rendered by default.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package cwms.cda.data.dto.catalog;
2+
3+
import com.fasterxml.jackson.annotation.JsonInclude;
4+
import com.fasterxml.jackson.annotation.JsonRootName;
5+
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
6+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
7+
import com.fasterxml.jackson.databind.annotation.JsonNaming;
8+
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
9+
import cwms.cda.formatters.Formats;
10+
import cwms.cda.formatters.annotations.FormattableWith;
11+
import cwms.cda.formatters.json.JsonV2;
12+
import java.util.Objects;
13+
14+
@JsonRootName("alias")
15+
@FormattableWith(contentType = Formats.JSONV2, formatter = JsonV2.class, aliases = {Formats.DEFAULT, Formats.JSON})
16+
@JsonDeserialize(builder = TimeSeriesAlias.Builder.class)
17+
@JsonInclude(JsonInclude.Include.NON_NULL)
18+
@JsonNaming(PropertyNamingStrategies.KebabCaseStrategy.class)
19+
public final class TimeSeriesAlias {
20+
21+
@JacksonXmlProperty(isAttribute = true)
22+
private final String name;
23+
private final String value;
24+
25+
private TimeSeriesAlias(Builder builder) {
26+
this.name = builder.name;
27+
this.value = builder.value;
28+
}
29+
30+
public String getName() {
31+
return name;
32+
}
33+
34+
public String getValue() {
35+
return value;
36+
}
37+
38+
@Override
39+
public boolean equals(Object o) {
40+
if (this == o) {
41+
return true;
42+
}
43+
if (o == null || getClass() != o.getClass()) {
44+
return false;
45+
}
46+
TimeSeriesAlias that = (TimeSeriesAlias) o;
47+
return Objects.equals(name, that.name) && Objects.equals(value, that.value);
48+
}
49+
50+
@Override
51+
public int hashCode() {
52+
return Objects.hash(name, value);
53+
}
54+
55+
public static final class Builder {
56+
private String name;
57+
private String value;
58+
59+
public Builder() {
60+
}
61+
62+
public Builder withName(String name) {
63+
this.name = name;
64+
return this;
65+
}
66+
67+
public Builder withValue(String value) {
68+
this.value = value;
69+
return this;
70+
}
71+
72+
public TimeSeriesAlias build() {
73+
return new TimeSeriesAlias(this);
74+
}
75+
}
76+
}

cwms-data-api/src/main/java/cwms/cda/data/dto/catalog/TimeseriesCatalogEntry.java

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.math.BigDecimal;
44
import java.time.ZonedDateTime;
55
import java.util.ArrayList;
6+
import java.util.Collection;
67
import java.util.List;
78

89
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
@@ -29,6 +30,9 @@ public class TimeseriesCatalogEntry extends CatalogEntry {
2930
@JacksonXmlProperty(localName = "extents")
3031
private List<TimeSeriesExtents> extents;
3132

33+
@JacksonXmlElementWrapper(localName = "aliases")
34+
@JacksonXmlProperty(localName = "alias")
35+
private Collection<TimeSeriesAlias> aliases;
3236

3337
public String getName() {
3438
return this.name;
@@ -52,18 +56,23 @@ public List<TimeSeriesExtents> getExtents() {
5256
return extents;
5357
}
5458

59+
public Collection<TimeSeriesAlias> getAliases() {
60+
return aliases;
61+
}
62+
5563
private TimeseriesCatalogEntry() {
5664
super(null);
5765
}
5866

59-
private TimeseriesCatalogEntry(String office, String name, String units, String interval, Long intervalOffset, String timeZone, List<TimeSeriesExtents> extents) {
60-
super(office);
61-
this.name = name;
62-
this.units = units;
63-
this.interval = interval;
64-
this.intervalOffset = intervalOffset;
65-
this.timeZone = timeZone;
66-
this.extents = extents;
67+
private TimeseriesCatalogEntry(Builder builder) {
68+
super(builder.office);
69+
this.name = builder.tsName;
70+
this.units = builder. units;
71+
this.interval = builder.interval;
72+
this.intervalOffset = builder.intervalOffset;
73+
this.timeZone = builder.timeZone;
74+
this.extents = builder.extents;
75+
this.aliases = builder.aliases;
6776
}
6877

6978
public String getUnits() {
@@ -90,6 +99,7 @@ public static class Builder {
9099
private ZonedDateTime earliestTime;
91100
private ZonedDateTime latestTime;
92101
private List<TimeSeriesExtents> extents = null;
102+
private Collection<TimeSeriesAlias> aliases = null;
93103

94104
public Builder officeId(final String office) {
95105
this.office = office;
@@ -143,8 +153,17 @@ public Builder withExtents(final List<TimeSeriesExtents> newExtents) {
143153
return this;
144154
}
145155

156+
public Builder withAliases(final Collection<TimeSeriesAlias> aliases) {
157+
if (aliases == null) {
158+
this.aliases = null;
159+
} else {
160+
this.aliases = new ArrayList<>(aliases);
161+
}
162+
return this;
163+
}
164+
146165
public TimeseriesCatalogEntry build() {
147-
return new TimeseriesCatalogEntry(office, tsName, units, interval, intervalOffset, timeZone, extents);
166+
return new TimeseriesCatalogEntry(this);
148167
}
149168
}
150169
}

cwms-data-api/src/test/java/cwms/cda/api/CatalogControllerTestIT.java

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
package cwms.cda.api;
22

3+
import com.fasterxml.jackson.core.JsonProcessingException;
4+
import com.fasterxml.jackson.core.type.TypeReference;
5+
import com.fasterxml.jackson.databind.JsonNode;
6+
import com.fasterxml.jackson.databind.ObjectMapper;
37
import static cwms.cda.api.Controllers.BOUNDING_OFFICE_LIKE;
48
import static cwms.cda.api.Controllers.EXCLUDE_EMPTY;
9+
import static cwms.cda.api.Controllers.INCLUDE_ALIASES;
510
import static cwms.cda.api.Controllers.LIKE;
611
import static cwms.cda.api.Controllers.LOCATION_CATEGORY_LIKE;
712
import static cwms.cda.api.Controllers.LOCATION_GROUP_LIKE;
813
import static cwms.cda.api.Controllers.LOCATION_KIND_LIKE;
914
import static cwms.cda.api.Controllers.TIMESERIES_CATEGORY_LIKE;
1015
import static cwms.cda.api.Controllers.TIMESERIES_GROUP_LIKE;
16+
import cwms.cda.data.dto.catalog.TimeSeriesAlias;
17+
import cwms.cda.data.dto.catalog.TimeseriesCatalogEntry;
18+
import cwms.cda.formatters.json.JsonV2;
19+
import java.util.List;
20+
import java.util.Objects;
21+
import java.util.stream.Collectors;
1122
import static org.junit.jupiter.api.Assertions.*;
1223

1324
import cwms.cda.data.dao.DeleteRule;
@@ -125,6 +136,73 @@ void test_no_aliased_results_returned() {
125136
.body("entries.size()",is(4));
126137
}
127138

139+
@Test
140+
void test_no_aliases_returned() {
141+
Integer numAliases = given().accept(Formats.JSONV2)
142+
.log().ifValidationFails(LogDetail.ALL, true)
143+
.queryParam(Controllers.OFFICE, OFFICE)
144+
.queryParam(EXCLUDE_EMPTY, false)
145+
.when()
146+
.get("/catalog/TIMESERIES")
147+
.then()
148+
.log().ifValidationFails(LogDetail.ALL, true)
149+
.assertThat()
150+
.statusCode(is(200))
151+
.extract()
152+
.jsonPath()
153+
.getObject("entries.aliases.aliases.size()", Integer.class);
154+
assertEquals(0, (int) numAliases, "Expected no aliases, but found some.");
155+
}
156+
157+
@Test
158+
void test_aliases_returned() {
159+
Integer numAliases = given().accept(Formats.JSONV2)
160+
.log().ifValidationFails(LogDetail.ALL, true)
161+
.queryParam(Controllers.OFFICE, OFFICE)
162+
.queryParam(EXCLUDE_EMPTY,false)
163+
.queryParam(INCLUDE_ALIASES,true)
164+
.when()
165+
.get("/catalog/TIMESERIES")
166+
.then()
167+
.log().ifValidationFails(LogDetail.ALL, true)
168+
.assertThat()
169+
.statusCode(is(200))
170+
.extract()
171+
.jsonPath()
172+
.getObject("entries.aliases.aliases.size()", Integer.class);
173+
assertTrue(numAliases > 0, "Expected aliases, but found none.");
174+
}
175+
176+
@Test
177+
void test_alias_is_correct() throws JsonProcessingException {
178+
Response response = given().accept(Formats.JSONV2)
179+
.log().ifValidationFails(LogDetail.ALL, true)
180+
.queryParam(Controllers.OFFICE, OFFICE)
181+
.queryParam(EXCLUDE_EMPTY, false)
182+
.queryParam(INCLUDE_ALIASES, true)
183+
.when()
184+
.get("/catalog/TIMESERIES");
185+
String json = response.body().asPrettyString();
186+
ObjectMapper om = JsonV2.buildObjectMapper();
187+
JsonNode root = om.readTree(json);
188+
JsonNode entriesNode = root.get("entries");
189+
String entriesJson = om.writeValueAsString(entriesNode);
190+
List<TimeseriesCatalogEntry> entries = om.readValue(entriesJson, new TypeReference<List<TimeseriesCatalogEntry>>() {});
191+
assertNotNull(entries);
192+
TimeseriesCatalogEntry alias = entries
193+
.stream()
194+
.filter(Objects::nonNull)
195+
.collect(Collectors.toSet()).stream()
196+
.filter(e -> e.getName().equals("Pine Flat-Outflow.Stage.Inst.15Minutes.0.one"))
197+
.findFirst()
198+
.orElse(null);
199+
assertNotNull(alias);
200+
assertTrue(alias.getAliases().contains(new TimeSeriesAlias.Builder()
201+
.withName("Test Category-LessThan3")
202+
.withValue("test alias 1")
203+
.build()));
204+
}
205+
128206

129207
@Test
130208
void test_queries_are_case_insensitive() {

cwms-data-api/src/test/java/cwms/cda/data/dto/catalog/TimeseriesCatalogEntryTest.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import io.restassured.path.json.JsonPath;
77
import io.restassured.path.xml.XmlPath;
8+
import java.util.Arrays;
89
import org.junit.jupiter.api.Test;
910

1011
import cwms.cda.data.dto.Catalog;
@@ -42,6 +43,10 @@ void test_xml_serialization_earliest(){
4243
Object tmp = path.get("catalog.entries.entry.extents");
4344
assertThat(path.getString("catalog.entries.entry.extents.extents.earliest-time"), equalTo("2017-07-27T05:00:00Z"));
4445
assertThat(path.getString("catalog.entries.entry.extents.extents.latest-time"), equalTo("2017-11-24T22:30:00Z"));
46+
assertThat(path.getString("catalog.entries.entry.aliases.alias[0].@name"), equalTo("alias1"));
47+
assertThat(path.getString("catalog.entries.entry.aliases.alias[0].value"), equalTo("value1"));
48+
assertThat(path.getString("catalog.entries.entry.aliases.alias[1].@name"), equalTo("alias2"));
49+
assertThat(path.getString("catalog.entries.entry.aliases.alias[1].value"), equalTo("value2"));
4550

4651
}
4752

@@ -66,6 +71,10 @@ void test_json_serialization_earliest(){
6671
assertThat(path.getString("entries[0].time-zone"), equalTo("US/Central"));
6772
assertThat(path.getString("entries[0].extents[0].earliest-time"), equalTo("2017-07-27T05:00:00Z"));
6873
assertThat(path.getString("entries[0].extents[0].latest-time"), equalTo("2017-11-24T22:30:00Z"));
74+
assertThat(path.getString("entries[0].aliases[0].name"), equalTo("alias1"));
75+
assertThat(path.getString("entries[0].aliases[0].value"), equalTo("value1"));
76+
assertThat(path.getString("entries[0].aliases[1].name"), equalTo("alias2"));
77+
assertThat(path.getString("entries[0].aliases[1].value"), equalTo("value2"));
6978

7079
}
7180

@@ -113,7 +122,10 @@ private TimeseriesCatalogEntry buildEntry()
113122
.withEarliestTime(ZonedDateTime.parse("2017-07-27T05:00:00Z"))
114123
.withLatestTime(ZonedDateTime.parse("2017-11-24T22:30:00Z"))
115124
.withLastUpdate(ZonedDateTime.parse("2017-11-24T22:30:00Z"))
116-
.build());
125+
.build())
126+
.withAliases(Arrays.asList(
127+
new TimeSeriesAlias.Builder().withName("alias1").withValue("value1").build(),
128+
new TimeSeriesAlias.Builder().withName("alias2").withValue("value2").build()));
117129
return builder
118130
.build();
119131

cwms-data-api/src/test/resources/cwms/cda/data/sql/ts_catalog_setup.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ begin
135135
p_ts_group_id=>'LessThan3',
136136
p_ts_id=>'Pine Flat-Outflow.Stage.Inst.15Minutes.0.one',
137137
p_ts_attribute=>0,
138-
p_ts_alias_id=>null,
138+
p_ts_alias_id=>'test alias 1',
139139
p_ref_ts_id=>NULL,
140140
p_db_office_id=>l_office);
141141

0 commit comments

Comments
 (0)