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 3be9574ac3..dcd0e7b1a4 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 @@ -245,6 +245,8 @@ public void getOne(@NotNull Context ctx, @NotNull String dataSet) { String.class, null, metrics, name(CatalogController.class.getName(), GET_ONE)); boolean includeAliases = ctx.queryParamAsClass(INCLUDE_ALIASES, Boolean.class) .getOrDefault(false); + String searchText = ctx.queryParamAsClass(SEARCH_TEXT, String.class) + .getOrDefault(null); String acceptHeader = ctx.header(ACCEPT); ContentType contentType = Formats.parseHeader(acceptHeader, Catalog.class); Catalog cat = null; @@ -292,6 +294,7 @@ public void getOne(@NotNull Context ctx, @NotNull String dataSet) { .withLocationType(locationType) .withFilterBaseLocations(filterBaseLocations) .withNegateLocationKindLike(negateLocationKind) + .withSearchText(searchText) .withIncludeAliases(includeAliases) .build(); diff --git a/cwms-data-api/src/main/java/cwms/cda/api/Controllers.java b/cwms-data-api/src/main/java/cwms/cda/api/Controllers.java index 04bcf6eb82..0cf6e2bfec 100644 --- a/cwms-data-api/src/main/java/cwms/cda/api/Controllers.java +++ b/cwms-data-api/src/main/java/cwms/cda/api/Controllers.java @@ -164,6 +164,7 @@ public final class Controllers { public static final String QUALITY = "quality"; public static final String NAMES = "names"; public static final String FILTER_BASE_LOCATIONS = "filter-base-locations"; + public static final String SEARCH_TEXT = "search-text"; public static final String GROUP_ID = "group-id"; public static final String REPLACE_ASSIGNED_LOCS = "replace-assigned-locs"; diff --git a/cwms-data-api/src/main/java/cwms/cda/data/dao/CatalogRequestParameters.java b/cwms-data-api/src/main/java/cwms/cda/data/dao/CatalogRequestParameters.java index cdffb65d90..048d604d8d 100644 --- a/cwms-data-api/src/main/java/cwms/cda/data/dao/CatalogRequestParameters.java +++ b/cwms-data-api/src/main/java/cwms/cda/data/dao/CatalogRequestParameters.java @@ -24,6 +24,7 @@ public class CatalogRequestParameters { private final boolean includeAliases; private final boolean filterBaseLocations; private final boolean negateLocationKindLike; + private final String searchText; private CatalogRequestParameters(Builder builder) { this.office = builder.office; @@ -42,6 +43,7 @@ private CatalogRequestParameters(Builder builder) { this.includeAliases = builder.includeAliases; this.filterBaseLocations = builder.filterBaseLocations; this.negateLocationKindLike = builder.negateLocationKindLike; + this.searchText = builder.searchText; } public String getBoundingOfficeLike() { @@ -108,6 +110,10 @@ public boolean isNegateLocationKindLike() { return negateLocationKindLike; } + public String getSearchText() { + return searchText; + } + public static class Builder { String office; String idLike; @@ -125,6 +131,7 @@ public static class Builder { private boolean includeAliases = false; private boolean filterBaseLocations = false; private boolean negateLocationKindLike = false; + private String searchText; public Builder() { @@ -210,6 +217,11 @@ public Builder withNegateLocationKindLike(boolean negateLocationKindLike) { return this; } + public Builder withSearchText(String searchText) { + this.searchText = searchText; + return this; + } + public static Builder from(CatalogRequestParameters params) { // This NEEDS to include every field in the CatalogRequestParameters return new Builder() @@ -228,6 +240,7 @@ public static Builder from(CatalogRequestParameters params) { .withLocationType(params.locationType) .withFilterBaseLocations(params.filterBaseLocations) .withNegateLocationKindLike(params.negateLocationKindLike) + .withSearchText(params.searchText) ; } 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 7a783df3c0..2e170b734a 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 @@ -102,7 +102,7 @@ public class LocationsDaoImpl extends JooqDao implements LocationsDao { private static final FluentLogger logger = FluentLogger.forEnclosingClass(); private static final long DELETED_TS_MARKER = 0L; - + private static Boolean HAS_SEARCH_COLUMN; public LocationsDaoImpl(DSLContext dsl) { @@ -620,6 +620,12 @@ private Catalog getLocationCatalog(Catalog.CatalogPage catPage, int pageSize, Ca //location codes (previous implementation used location_id) for joins, feel free to implement. Objects.requireNonNull(params.getIdLike(), "A value must be provided for the idLike field. Specify .* if you don't care."); + String textSearch = params.getSearchText(); + if (textSearch != null && !textSearch.isBlank() && !hasSearchDocColumn(dsl, table)) { + throw new IllegalArgumentException( + "Text search is not supported because SEARCH_DOC is not present in " + table.getName() + ); + } // "condition" needs to be used by the count query and the results query. Condition condition = buildWhereCondition(params); @@ -767,6 +773,17 @@ private static Condition buildWhereCondition(CatalogRequestParameters params) { condition = condition.and(fieldMapping.getSubLocationId().isNotNull()); } + String textSearch = params.getSearchText(); + if (textSearch != null && !textSearch.isBlank()) { + condition = condition.and( + DSL.condition( + "CONTAINS({0}, ?) > 0", + fieldMapping.getSearchDoc(), + textSearch + ) + ); + } + return condition; } @@ -797,6 +814,18 @@ private LocationAlias buildLocationAlias(Record row, FieldMapping mapping) { row.get(mapping.getLocationId())); } + private static synchronized boolean hasSearchDocColumn(DSLContext dsl, Table table) { + if(HAS_SEARCH_COLUMN != null) { + return HAS_SEARCH_COLUMN; + } + HAS_SEARCH_COLUMN = dsl.meta() + .getTables(table.getName()) + .stream() + .flatMap(t -> Arrays.stream(t.fields())) + .anyMatch(c -> c.getName().equalsIgnoreCase("SEARCH_DOC")); + return HAS_SEARCH_COLUMN; + } + @NotNull private static LocationCatalogEntry buildCatalogEntry(Record loc, Set aliases, FieldMapping mapping) { @@ -925,6 +954,8 @@ private interface FieldMapping { boolean includesAliases(); Table getTable(); + + Field getSearchDoc(); } private static class AvLoc2FieldMapping implements FieldMapping { @@ -1082,6 +1113,11 @@ public boolean includesAliases() { public Table getTable() { return AV_LOC2.AV_LOC2; } + + @Override + public Field getSearchDoc() { + return DSL.field(DSL.name(getTable().getName(), "SEARCH_DOC"), String.class); + } } private static class AvLocFieldMapping implements FieldMapping { @@ -1235,6 +1271,11 @@ public boolean includesAliases() { return false; } + @Override + public Field getSearchDoc() { + return DSL.field(DSL.name(getTable().getName(), "SEARCH_DOC"), String.class); + } + @Override public Table getTable() { return AV_LOC;