diff --git a/cwms-data-api/src/main/java/cwms/cda/api/CatalogController.java b/cwms-data-api/src/main/java/cwms/cda/api/CatalogController.java index 919e7e3e42..af9cc60939 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/CatalogController.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/CatalogController.java @@ -271,6 +271,7 @@ public void getOne(@NotNull Context ctx, @NotNull String dataSet) { .withLocationType(locationType) .withFilterBaseLocations(filterBaseLocations) .withNegateLocationKindLike(negateLocationKind) + .withIncludeAliases(includeAliases) .build(); LocationsDao dao = new LocationsDaoImpl(dsl); diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dao/LocationsDaoImpl.java b/cwms-data-api/src/main/java/cwms/cda/data/dao/LocationsDaoImpl.java index 02c074a23c..eff2a07b24 100644 --- a/cwms-data-api/src/main/java/cwms/cda/data/dao/LocationsDaoImpl.java +++ b/cwms-data-api/src/main/java/cwms/cda/data/dao/LocationsDaoImpl.java @@ -59,6 +59,7 @@ import java.time.ZoneId; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -77,10 +78,11 @@ import org.jooq.Configuration; import org.jooq.DSLContext; import org.jooq.Field; +import org.jooq.OrderField; import org.jooq.Record; import org.jooq.Record1; import org.jooq.SelectConditionStep; -import org.jooq.SelectSeekStep3; +import org.jooq.SelectSeekStepN; import org.jooq.Table; import org.jooq.conf.ParamType; import org.jooq.exception.DataAccessException; @@ -426,8 +428,14 @@ public Catalog getLocationCatalog(String page, int pageSize, CatalogRequestParam } private Catalog getLocationCatalog(Catalog.CatalogPage catPage, int pageSize, CatalogRequestParameters params) { + FieldMapping fieldMapping = null; + if (params.includeAliases()) { + fieldMapping = new AvLoc2FieldMapping(); + } else { - final AV_LOC2 avLoc2 = AV_LOC2.AV_LOC2; // ref the view just shorten the jooq + fieldMapping = new AvLocFieldMapping(); + } + Table table = fieldMapping.getTable(); //Now querying against AV_LOC2 as it gives us back the same information as querying against //location group views. This makes the code clearer and improves performance. //If there is a performance improvement by switching back to location groups and querying against @@ -448,7 +456,7 @@ private Catalog getLocationCatalog(Catalog.CatalogPage catPage, int pageSize, Ca cursorOffice = null; SelectConditionStep> count = dsl.select(count(asterisk())) - .from(avLoc2) + .from(table) .where(condition); logger.log(Level.FINER, () -> count.getSQL(ParamType.INLINED)); total = count.fetchOne().value1(); @@ -460,15 +468,20 @@ private Catalog getLocationCatalog(Catalog.CatalogPage catPage, int pageSize, Ca pageSize = catPage.getPageSize(); } - condition = addCursorConditions(condition, cursorOffice, cursorLocation); + condition = addCursorConditions(condition, cursorOffice, cursorLocation, fieldMapping); + + Field dataId = fieldMapping.getLocationId().as("real_id"); + Field dataCode = fieldMapping.getLocationCode().as("real_code"); + + if (fieldMapping.includesAliases()) { + condition = condition.and(fieldMapping.getAliasedItem().isNull()); + } - Field dataId = avLoc2.LOCATION_ID.as("real_id"); - Field dataCode = avLoc2.LOCATION_CODE.as("real_code"); // data/limiter/query Table data = dsl.select(dataId,dataCode) - .from(avLoc2) - .where(condition.and(avLoc2.ALIASED_ITEM.isNull())) - .orderBy(avLoc2.DB_OFFICE_ID.asc(),avLoc2.LOCATION_ID.asc()) + .from(table) + .where(condition) + .orderBy(fieldMapping.getDbOfficeId().asc(), fieldMapping.getLocationId().asc()) .asTable("data"); CommonTableExpression limiter = name("limiter") .fields("real_id","location_code") @@ -478,88 +491,116 @@ private Catalog getLocationCatalog(Catalog.CatalogPage catPage, int pageSize, Ca .where(field("rownum").lessOrEqual(pageSize)) ); Field limitId = limiter.field("real_id",String.class); - Field limitCode = limiter.field("location_code",Long.class); - SelectSeekStep3 query = dsl.with(limiter).select( + OrderField[] orderFields = new OrderField[2 + (fieldMapping.includesAliases() ? 1 : 0)]; + orderFields[0] = fieldMapping.getDbOfficeId().asc(); + orderFields[1] = limitId.asc(); + if (fieldMapping.includesAliases()) { + orderFields[2] = fieldMapping.getAliasedItem().asc(); + } + + Field limitCode = limiter.field("location_code",Long.class); + SelectSeekStepN query = dsl.with(limiter).select( limitId, - avLoc2.LOCATION_ID.as("alias_id"), - avLoc2.asterisk()) + fieldMapping.getLocationId().as("alias_id"), + table.asterisk()) .from(limiter) - .leftOuterJoin(avLoc2).on(avLoc2.LOCATION_CODE.eq(limitCode)) - .orderBy(avLoc2.DB_OFFICE_ID.asc(),limitId.asc(),avLoc2.ALIASED_ITEM.asc()); + .leftOuterJoin(table).on(fieldMapping.getLocationCode().eq(limitCode)) + .orderBy(orderFields); logger.log(Level.FINER, () -> query.getSQL(ParamType.INLINED)); - try (Stream recordStream = query + try (Stream recordStream = (Stream) query .fetchSize(DEFAULT_FETCH_SIZE) .fetchStream()) { - List entries = recordStream - .map(r -> r.into(AV_LOC2.AV_LOC2)) - .collect(groupingBy(usace.cwms.db.jooq.codegen.tables.records.AV_LOC2::getLOCATION_CODE)) - .values() - .stream() - .map(l -> { - usace.cwms.db.jooq.codegen.tables.records.AV_LOC2 row = l.stream() - .filter(r -> r.getALIASED_ITEM() == null) - .findFirst() - .orElseThrow(() -> new DataAccessException("Could not find location for list of aliases: " + l)); - Set aliases = l.stream().filter(r -> r.getALIASED_ITEM() != null) - .map(this::buildLocationAlias).collect(toSet()); - return buildCatalogEntry(row, aliases); - }) - .collect(toList()); - + final FieldMapping mapping = fieldMapping; + List entries = recordStream + .map(r -> r.into(table)) + .collect(groupingBy(row -> row.get(mapping.getLocationCode()))) + .values() + .stream() + .map(l -> { + Record row = l.stream() + .filter(r -> { + if (mapping.includesAliases()) { + return r.get(mapping.getAliasedItem()) == null; + } else { + return true; + } + }) + .findFirst() + .orElseThrow( + () -> new DataAccessException("Could not find location for list of aliases: " + l)); + Set aliases = new HashSet<>(); + if (params.includeAliases()) { + aliases = l.stream().filter(r -> r.get(mapping.getAliasedItem()) != null) + .map(r -> buildLocationAlias(r, mapping)).collect(toSet()); + } + return buildCatalogEntry(row, aliases, mapping); + }) + .collect(toList()); return new Catalog(cursorLocation, total, pageSize, entries, params); } } private static Condition buildWhereCondition(CatalogRequestParameters params) { String idLike = params.getIdLike(); + FieldMapping fieldMapping = null; + if (params.includeAliases()) { + fieldMapping = new AvLoc2FieldMapping(); + } else { + fieldMapping = new AvLocFieldMapping(); + } - Condition condition = caseInsensitiveLikeRegex(AV_LOC2.AV_LOC2.LOCATION_ID, idLike) - .and(AV_LOC2.AV_LOC2.LOCATION_CODE.notEqual(DELETED_TS_MARKER)) - .and(AV_LOC2.AV_LOC2.UNIT_SYSTEM.equalIgnoreCase(params.getUnitSystem())); + Condition condition = caseInsensitiveLikeRegex(fieldMapping.getLocationId(), idLike) + .and(fieldMapping.getLocationCode().notEqual(DELETED_TS_MARKER)) + .and(fieldMapping.getUnitSystem().equalIgnoreCase(params.getUnitSystem())); String groupLike = params.getLocGroupLike(); String categoryLike = params.getLocCatLike(); - if (categoryLike == null && groupLike == null) { - condition = condition.and(AV_LOC2.AV_LOC2.ALIASED_ITEM.isNull()); + if (categoryLike == null && groupLike == null && params.includeAliases()) { + condition = condition.and(fieldMapping.getAliasedItem().isNull()); + } + + if (params.includeAliases()) { + condition = + condition.and(caseInsensitiveLikeRegexNullTrue(fieldMapping.getAliasCategory(), categoryLike)); + condition = condition.and(caseInsensitiveLikeRegexNullTrue(fieldMapping.getAliasGroup(), groupLike)); } - condition = condition.and(caseInsensitiveLikeRegexNullTrue(AV_LOC2.AV_LOC2.LOC_ALIAS_CATEGORY, categoryLike)); - condition = condition.and(caseInsensitiveLikeRegexNullTrue(AV_LOC2.AV_LOC2.LOC_ALIAS_GROUP, groupLike)); String office = params.getOffice(); if (office != null) { - condition = condition.and(DSL.upper(AV_LOC2.AV_LOC2.DB_OFFICE_ID).eq(office.toUpperCase())); + condition = condition.and(DSL.upper(fieldMapping.getDbOfficeId()).eq(office.toUpperCase())); } - condition = condition.and(caseInsensitiveLikeRegexNullTrue(AV_LOC2.AV_LOC2.BOUNDING_OFFICE_ID, + condition = condition.and(caseInsensitiveLikeRegexNullTrue(fieldMapping.getBoundingOfficeId(), params.getBoundingOfficeLike())); String regexLocationKind = params.getLocationKind(); if (params.isNegateLocationKindLike() && !regexLocationKind.toUpperCase().startsWith("NOT:")) { regexLocationKind = String.format("NOT:%s", regexLocationKind); } - condition = condition.and(caseInsensitiveLikeRegexNullTrue(AV_LOC2.AV_LOC2.LOCATION_KIND_ID, + condition = condition.and(caseInsensitiveLikeRegexNullTrue(fieldMapping.getLocationKind(), regexLocationKind)); - condition = condition.and(caseInsensitiveLikeRegexNullTrue(AV_LOC2.AV_LOC2.LOCATION_TYPE, + condition = condition.and(caseInsensitiveLikeRegexNullTrue(fieldMapping.getLocationType(), params.getLocationType())); - if (params.filterBaseLocations()) { - condition = condition.and(AV_LOC2.AV_LOC2.SUB_LOCATION_ID.isNotNull()); + if (params.filterBaseLocations() && params.includeAliases()) { + condition = condition.and(fieldMapping.getSubLocationId().isNotNull()); } return condition; } - private static Condition addCursorConditions(Condition condition, String cursorOffice, String cursorLocation) { + private static Condition addCursorConditions(Condition condition, String cursorOffice, String cursorLocation, + FieldMapping mapping) { if (cursorOffice != null) { - Condition officeEqualCur = DSL.upper(AV_LOC2.AV_LOC2.DB_OFFICE_ID).eq(cursorOffice.toUpperCase()); - Condition curOfficeLocationIdGreater = DSL.upper(AV_LOC2.AV_LOC2.LOCATION_ID).gt(cursorLocation); - Condition officeGreaterThanCur = DSL.upper(AV_LOC2.AV_LOC2.DB_OFFICE_ID).gt(cursorOffice.toUpperCase()); + Condition officeEqualCur = DSL.upper(mapping.getDbOfficeId()).eq(cursorOffice.toUpperCase()); + Condition curOfficeLocationIdGreater = DSL.upper(mapping.getLocationId()).gt(cursorLocation); + Condition officeGreaterThanCur = DSL.upper(mapping.getDbOfficeId()).gt(cursorOffice.toUpperCase()); condition = condition.and(officeEqualCur).and(curOfficeLocationIdGreater).or(officeGreaterThanCur); } else { - condition = condition.and(DSL.upper(AV_LOC2.AV_LOC2.LOCATION_ID).gt(cursorLocation)); + condition = condition.and(DSL.upper(mapping.getLocationId()).gt(cursorLocation)); } return condition; } @@ -573,41 +614,41 @@ static String warnIfMismatch(String paramName, String pageParam, String queryPar return pageParam; } - private LocationAlias buildLocationAlias(usace.cwms.db.jooq.codegen.tables.records.AV_LOC2 row) { - return new LocationAlias(row.getLOC_ALIAS_CATEGORY() + "-" + row.getLOC_ALIAS_GROUP(), - row.getLOCATION_ID()); + private LocationAlias buildLocationAlias(Record row, FieldMapping mapping) { + return new LocationAlias(row.get(mapping.getAliasCategory()) + "-" + row.get(mapping.getAliasGroup()), + row.get(mapping.getLocationId())); } @NotNull - private static LocationCatalogEntry buildCatalogEntry(usace.cwms.db.jooq.codegen.tables.records.AV_LOC2 loc, - Set aliases) { + private static LocationCatalogEntry buildCatalogEntry(Record loc, + Set aliases, FieldMapping mapping) { return new LocationCatalogEntry.Builder() - .officeId(loc.getDB_OFFICE_ID()) - .name(loc.getLOCATION_ID()) - .nearestCity(loc.getNEAREST_CITY()) - .publicName(loc.getPUBLIC_NAME()) - .longName(loc.getLONG_NAME()) - .description(loc.getDESCRIPTION()) - .kind(loc.getLOCATION_KIND_ID()) - .type(loc.getLOCATION_TYPE()) - .timeZone(loc.getTIME_ZONE_NAME()) - .latitude(loc.getLATITUDE() != null ? loc.getLATITUDE().doubleValue() : null) - .longitude(loc.getLONGITUDE() != null ? loc.getLONGITUDE().doubleValue() : null) - .publishedLatitude(loc.getPUBLISHED_LATITUDE() != null - ? loc.getPUBLISHED_LATITUDE().doubleValue() : null) - .publishedLongitude(loc.getPUBLISHED_LONGITUDE() != null - ? loc.getPUBLISHED_LONGITUDE().doubleValue() : null) - .horizontalDatum(loc.getHORIZONTAL_DATUM()) - .elevation(loc.getELEVATION()) - .unit(loc.getUNIT_ID()) - .verticalDatum(loc.getVERTICAL_DATUM()) - .nation(loc.getNATION_ID()) - .state(loc.getSTATE_INITIAL()) - .county(loc.getCOUNTY_NAME()) - .boundingOffice(loc.getBOUNDING_OFFICE_ID()) - .mapLabel(loc.getMAP_LABEL()) - .active(loc.getACTIVE_FLAG().equalsIgnoreCase("T")) + .officeId(loc.get(mapping.getDbOfficeId())) + .name(loc.get(mapping.getLocationId())) + .nearestCity(loc.get(mapping.getNearestCity())) + .publicName(loc.get(mapping.getPublicName())) + .longName(loc.get(mapping.getLongName())) + .description(loc.get(mapping.getDescription())) + .kind(loc.get(mapping.getLocationKind())) + .type(loc.get(mapping.getLocationType())) + .timeZone(loc.get(mapping.getTimeZoneName())) + .latitude(loc.get(mapping.getLatitude()) != null ? loc.get(mapping.getLatitude()).doubleValue() : null) + .longitude(loc.get(mapping.getLongitude()) != null ? loc.get(mapping.getLongitude()).doubleValue() : null) + .publishedLatitude(loc.get(mapping.getPublishedLatitude()) != null + ? loc.get(mapping.getPublishedLatitude()).doubleValue() : null) + .publishedLongitude(loc.get(mapping.getPublishedLongitude()) != null + ? loc.get(mapping.getPublishedLongitude()).doubleValue() : null) + .horizontalDatum(loc.get(mapping.getHorizontalDatum())) + .elevation(loc.get(mapping.getElevation())) + .unit(loc.get(mapping.getUnit())) + .verticalDatum(loc.get(mapping.getVerticalDatum())) + .nation(loc.get(mapping.getNation())) + .state(loc.get(mapping.getStateInitial())) + .county(loc.get(mapping.getCountyName())) + .boundingOffice(loc.get(mapping.getBoundingOfficeId())) + .mapLabel(loc.get(mapping.getMapLabel())) + .active(loc.get(mapping.getActiveFlag()).equalsIgnoreCase("T")) .aliases(aliases) .build(); } @@ -643,4 +684,382 @@ private static LOCATION_OBJ_T getLocationObj(Location location) { } return retval; } + + private interface FieldMapping { + Field getLocationCode(); + + Field getLocationId(); + + Field getAliasedItem(); + + Field getDbOfficeId(); + + Field getUnitSystem(); + + Field getLocationType(); + + Field getLocationKind(); + + Field getBoundingOfficeId(); + + Field getAliasGroup(); + + Field getAliasCategory(); + + Field getSubLocationId(); + + Field getNearestCity(); + + Field getPublicName(); + + Field getLongName(); + + Field getDescription(); + + Field getTimeZoneName(); + + Field getLatitude(); + + Field getLongitude(); + + Field getPublishedLatitude(); + + Field getPublishedLongitude(); + + Field getHorizontalDatum(); + + Field getElevation(); + + Field getUnit(); + + Field getVerticalDatum(); + + Field getStateInitial(); + + Field getCountyName(); + + Field getActiveFlag(); + + Field getMapLabel(); + + Field getNation(); + + boolean includesAliases(); + + Table getTable(); + } + + private static class AvLoc2FieldMapping implements FieldMapping { + @Override + public Field getLocationCode() { + return AV_LOC2.AV_LOC2.LOCATION_CODE; + } + + @Override + public Field getLocationId() { + return AV_LOC2.AV_LOC2.LOCATION_ID; + } + + @Override + public Field getAliasedItem() { + return AV_LOC2.AV_LOC2.ALIASED_ITEM; + } + + @Override + public Field getDbOfficeId() { + return AV_LOC2.AV_LOC2.DB_OFFICE_ID; + } + + @Override + public Field getUnitSystem() { + return AV_LOC2.AV_LOC2.UNIT_SYSTEM; + } + + @Override + public Field getLocationType() { + return AV_LOC2.AV_LOC2.LOCATION_TYPE; + } + + @Override + public Field getLocationKind() { + return AV_LOC2.AV_LOC2.LOCATION_KIND_ID; + } + + @Override + public Field getBoundingOfficeId() { + return AV_LOC2.AV_LOC2.BOUNDING_OFFICE_ID; + } + + @Override + public Field getAliasGroup() { + return AV_LOC2.AV_LOC2.LOC_ALIAS_GROUP; + } + + @Override + public Field getAliasCategory() { + return AV_LOC2.AV_LOC2.LOC_ALIAS_CATEGORY; + } + + @Override + public Field getSubLocationId() { + return AV_LOC2.AV_LOC2.SUB_LOCATION_ID; + } + + @Override + public Field getNearestCity() { + return AV_LOC2.AV_LOC2.NEAREST_CITY; + } + + @Override + public Field getPublicName() { + return AV_LOC2.AV_LOC2.PUBLIC_NAME; + } + + @Override + public Field getLongName() { + return AV_LOC2.AV_LOC2.LONG_NAME; + } + + @Override + public Field getDescription() { + return AV_LOC2.AV_LOC2.DESCRIPTION; + } + + @Override + public Field getTimeZoneName() { + return AV_LOC2.AV_LOC2.TIME_ZONE_NAME; + } + + @Override + public Field getLatitude() { + return AV_LOC2.AV_LOC2.LATITUDE; + } + + @Override + public Field getLongitude() { + return AV_LOC2.AV_LOC2.LONGITUDE; + } + + @Override + public Field getPublishedLatitude() { + return AV_LOC2.AV_LOC2.PUBLISHED_LATITUDE; + } + + @Override + public Field getPublishedLongitude() { + return AV_LOC2.AV_LOC2.PUBLISHED_LONGITUDE; + } + + @Override + public Field getHorizontalDatum() { + return AV_LOC2.AV_LOC2.HORIZONTAL_DATUM; + } + + @Override + public Field getElevation() { + return AV_LOC2.AV_LOC2.ELEVATION; + } + + @Override + public Field getUnit() { + return AV_LOC2.AV_LOC2.UNIT_ID; + } + + @Override + public Field getVerticalDatum() { + return AV_LOC2.AV_LOC2.VERTICAL_DATUM; + } + + @Override + public Field getStateInitial() { + return AV_LOC2.AV_LOC2.STATE_INITIAL; + } + + @Override + public Field getCountyName() { + return AV_LOC2.AV_LOC2.COUNTY_NAME; + } + + @Override + public Field getActiveFlag() { + return AV_LOC2.AV_LOC2.ACTIVE_FLAG; + } + + @Override + public Field getMapLabel() { + return AV_LOC2.AV_LOC2.MAP_LABEL; + } + + @Override + public Field getNation() { + return AV_LOC2.AV_LOC2.NATION_ID; + } + + @Override + public boolean includesAliases() { + return true; + } + + @Override + public Table getTable() { + return AV_LOC2.AV_LOC2; + } + } + + private static class AvLocFieldMapping implements FieldMapping { + @Override + public Field getLocationCode() { + return AV_LOC.LOCATION_CODE; + } + + @Override + public Field getLocationId() { + return AV_LOC.LOCATION_ID; + } + + @Override + public Field getAliasedItem() { + return null; + } + + @Override + public Field getDbOfficeId() { + return AV_LOC.DB_OFFICE_ID; + } + + @Override + public Field getUnitSystem() { + return AV_LOC.UNIT_SYSTEM; + } + + @Override + public Field getLocationType() { + return AV_LOC.LOCATION_TYPE; + } + + @Override + public Field getLocationKind() { + return AV_LOC.LOCATION_KIND_ID; + } + + @Override + public Field getBoundingOfficeId() { + return AV_LOC.BOUNDING_OFFICE_ID; + } + + @Override + public Field getAliasGroup() { + return null; + } + + @Override + public Field getAliasCategory() { + return null; + } + + @Override + public Field getSubLocationId() { + return null; + } + + @Override + public Field getNearestCity() { + return AV_LOC.NEAREST_CITY; + } + + @Override + public Field getPublicName() { + return AV_LOC.PUBLIC_NAME; + } + + @Override + public Field getLongName() { + return AV_LOC.LONG_NAME; + } + + @Override + public Field getDescription() { + return AV_LOC.DESCRIPTION; + } + + @Override + public Field getTimeZoneName() { + return AV_LOC.TIME_ZONE_NAME; + } + + @Override + public Field getLatitude() { + return AV_LOC.LATITUDE; + } + + @Override + public Field getLongitude() { + return AV_LOC.LONGITUDE; + } + + @Override + public Field getPublishedLatitude() { + return AV_LOC.PUBLISHED_LATITUDE; + } + + @Override + public Field getPublishedLongitude() { + return AV_LOC.PUBLISHED_LONGITUDE; + } + + @Override + public Field getHorizontalDatum() { + return AV_LOC.HORIZONTAL_DATUM; + } + + @Override + public Field getElevation() { + return AV_LOC.ELEVATION; + } + + @Override + public Field getUnit() { + return AV_LOC.UNIT_ID; + } + + @Override + public Field getVerticalDatum() { + return AV_LOC.VERTICAL_DATUM; + } + + @Override + public Field getStateInitial() { + return AV_LOC.STATE_INITIAL; + } + + @Override + public Field getCountyName() { + return AV_LOC.COUNTY_NAME; + } + + @Override + public Field getActiveFlag() { + return AV_LOC.ACTIVE_FLAG; + } + + @Override + public Field getMapLabel() { + return AV_LOC.MAP_LABEL; + } + + @Override + public Field getNation() { + return AV_LOC.NATION_ID; + } + + @Override + public boolean includesAliases() { + return false; + } + + @Override + public Table getTable() { + return AV_LOC; + } + } } diff --git a/cwms-data-api/src/test/java/cwms/cda/api/CatalogControllerTestIT.java b/cwms-data-api/src/test/java/cwms/cda/api/CatalogControllerTestIT.java index 8ced1fdc06..3e1d251eb1 100644 --- a/cwms-data-api/src/test/java/cwms/cda/api/CatalogControllerTestIT.java +++ b/cwms-data-api/src/test/java/cwms/cda/api/CatalogControllerTestIT.java @@ -82,7 +82,7 @@ static void setup_data() throws Exception { // Complicated loadSqlDataFromResource("cwms/cda/data/sql/ts_catalog_setup.sql"); - + loadSqlDataFromResource("cwms/cda/data/sql/location_catalog_setup.sql"); } private static void createProject(String id, String office) throws SQLException { @@ -447,6 +447,53 @@ void test_loc_kind() { ; } + @Test + void test_loc_aliases() { + + String pattern = "*Streamflow"; + + // Retrieve without aliases + given() + .accept("application/json;version=2") + .queryParam(Controllers.OFFICE, OFFICE) + .queryParam(LIKE, pattern) + .queryParam(INCLUDE_ALIASES, false) + .when() + .get("/catalog/LOCATIONS") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(200)) + .body("$", hasKey("total")) + .body("total", is(2)) + .body("$", hasKey("entries")) + .body("entries.size()", is(2)) + .body("entries[0].aliases.size()", is(0)) + ; + + // retrieve with aliases + given() + .accept("application/json;version=2") + .queryParam(Controllers.OFFICE, OFFICE) + .queryParam(LIKE, pattern) + .queryParam(INCLUDE_ALIASES, true) + .when() + .get("/catalog/LOCATIONS") + .then() + .log().ifValidationFails(LogDetail.ALL, true) + .assertThat() + .statusCode(is(200)) + .body("$", hasKey("total")) + .body("total", is(2)) + .body("$", hasKey("entries")) + .body("entries.size()", is(2)) + .body("entries[0].name", isOneOf("Alder Springs Streamflow", "Pine Flat-Outflow Streamflow")) + .body("entries[0].aliases.size()", isOneOf(1, 2)) + .body("entries[0].aliases[0].value", + isOneOf("Alder Stream Alias Loc", "Alder Stream Alias Loc 2", "Pine Stream Alias Loc")) + ; + } + @Test void testFilterLocations() throws Exception{ TestAccounts.KeyUser user = TestAccounts.KeyUser.SPK_NORMAL; diff --git a/cwms-data-api/src/test/java/cwms/cda/api/TimeseriesControllerTestIT.java b/cwms-data-api/src/test/java/cwms/cda/api/TimeseriesControllerTestIT.java index 61e5111ecb..268753a2c9 100644 --- a/cwms-data-api/src/test/java/cwms/cda/api/TimeseriesControllerTestIT.java +++ b/cwms-data-api/src/test/java/cwms/cda/api/TimeseriesControllerTestIT.java @@ -118,7 +118,7 @@ void test_local_regular_new_LRTS_ID() throws Exception { InputStream resource = this.getClass().getResourceAsStream( "/cwms/cda/api/timeseries/local_regular_ts.json"); assertNotNull(resource); - String tsData = IOUtils.toString(resource, "UTF-8"); + String tsData = IOUtils.toString(resource, StandardCharsets.UTF_8); JsonNode ts = mapper.readTree(tsData); String location = ts.get(NAME).asText().split("\\.")[0]; @@ -539,7 +539,7 @@ void test_lrl_timeseries_psuedo_reg1week() throws Exception { InputStream resource = this.getClass().getResourceAsStream( "/cwms/cda/api/lrl/pseudo_reg_1week.json"); assertNotNull(resource); - String tsData = IOUtils.toString(resource, "UTF-8"); + String tsData = IOUtils.toString(resource, StandardCharsets.UTF_8); JsonNode ts = mapper.readTree(tsData); String location = ts.get("name").asText().split("\\.")[0]; @@ -601,7 +601,7 @@ void test_lrl_timeseries_lrts_reg1week() throws Exception { InputStream resource = this.getClass().getResourceAsStream( "/cwms/cda/api/lrl/pseudo_reg_1week.json"); assertNotNull(resource); - String tsData = IOUtils.toString(resource, "UTF-8"); + String tsData = IOUtils.toString(resource, StandardCharsets.UTF_8); JsonNode ts = mapper.readTree(tsData); String location = ts.get("name").asText().split("\\.")[0]; @@ -1401,18 +1401,20 @@ void test_lrl_trim_with_data_entry_date() throws Exception { } @Test - void test_big_create() throws Exception { + void test_medium_create() throws Exception { InputStream resource = this.getClass().getResourceAsStream( "/cwms/cda/api/lrl/1day_offset.json"); assertNotNull(resource); String tsData = IOUtils.toString(resource, StandardCharsets.UTF_8); - String giantString = buildBigString(tsData, 200000); + // Note 09/08/25 Changed from 200k to 12k b/c the test was failing b/c zstore_ts was taking too long. + // 5k took 13s, 10k = 26s, 12k = 31s, 15k closed @47s, 20k closed @83s + String giantString = buildBigString(tsData, 12000); // 200k points looked like about 6MB. long bytes = giantString.getBytes().length; - assertTrue(bytes > 2000000, "The string should be over 2MB"); + assertTrue(bytes > 350000, "The string should be over 350kB"); ObjectMapper mapper = new ObjectMapper(); JsonNode ts = mapper.readTree(tsData); @@ -1674,7 +1676,7 @@ void test_wrong_units() throws Exception { InputStream resource = this.getClass().getResourceAsStream( "/cwms/cda/api/lrl/1day_offset.json"); assertNotNull(resource); - String tsData = IOUtils.toString(resource, "UTF-8"); + String tsData = IOUtils.toString(resource, StandardCharsets.UTF_8); JsonNode ts = mapper.readTree(tsData); String location = ts.get(NAME).asText().split("\\.")[0]; diff --git a/cwms-data-api/src/test/resources/cwms/cda/data/sql/location_catalog_setup.sql b/cwms-data-api/src/test/resources/cwms/cda/data/sql/location_catalog_setup.sql new file mode 100644 index 0000000000..b4f81c39a7 --- /dev/null +++ b/cwms-data-api/src/test/resources/cwms/cda/data/sql/location_catalog_setup.sql @@ -0,0 +1,92 @@ +declare +ts_code NUMBER; + l_office varchar2(16) := 'SPK'; + l_loc_cat varchar2(32) := 'ALIASED LOC Category'; +begin +-- create some locations + cwms_loc.create_location('Alder Springs Streamflow', + null, + 6000, + 'ft', + 'NAVD88', + 40.0, + -120.0, + 'NAD83', + 'Alder Springs Streamflow', + 'Alder Springs Streamflow', + 'Alder Springs Streamflow', + 'PST', + 'Lassen', + 'CA', + 'T', + l_office + ); + + cwms_loc.create_location('Pine Flat-Outflow Streamflow', + null, + 4000, + 'ft', + 'NAVD88', + 42.0, + -122.0, + 'NAD83', + 'Pine Flat-Outflow Streamflow', + 'Pine Flat-Outflow Streamflow', + 'Pine Flat-Outflow Streamflow', + 'PST', + 'Lassen', + 'CA', + 'T', + l_office + ); + + cwms_loc.store_loc_category(l_loc_cat, + 'For Testing', + 'F', + 'T', + l_office + ); + + cwms_loc.store_loc_group (l_loc_cat, + 'Group 1', + 'For Testing', + 'F', + 'T', + 'Alder Springs Streamflow', + null, + l_office + ); + + cwms_loc.store_loc_group (l_loc_cat, + 'Group 2', + 'For Testing', + 'F', + 'T', + null, + null, + l_office + ); + + cwms_loc.unassign_loc_group( p_loc_category_id => l_loc_cat, p_loc_group_id => 'Group 1', p_location_id => NULL, p_unassign_all => 'T', p_db_office_id => l_office); + cwms_loc.unassign_loc_group( p_loc_category_id =>l_loc_cat, p_loc_group_id => 'Group 2', p_location_id => NULL, p_unassign_all => 'T', p_db_office_id => l_office); + + cwms_loc.assign_loc_group(l_loc_cat, + 'Group 1', + 'Alder Springs Streamflow', + 'Alder Stream Alias Loc', + l_office + ); + cwms_loc.assign_loc_group(l_loc_cat, + 'Group 2', + 'Alder Springs Streamflow', + 'Alder Stream Alias Loc 2', + l_office + ); + cwms_loc.assign_loc_group(l_loc_cat, + 'Group 2', + 'Pine Flat-Outflow Streamflow', + 'Pine Stream Alias Loc', + l_office + ); + +end; \ No newline at end of file