diff --git a/service/src/main/java/gov/nasa/pds/api/registry/controllers/ProductsController.java b/service/src/main/java/gov/nasa/pds/api/registry/controllers/ProductsController.java index 2dba1106..3fc31667 100644 --- a/service/src/main/java/gov/nasa/pds/api/registry/controllers/ProductsController.java +++ b/service/src/main/java/gov/nasa/pds/api/registry/controllers/ProductsController.java @@ -249,11 +249,7 @@ public ResponseEntity productList(List fields, List keyw Integer limit, String q, List sort, List searchAfter) throws Exception { SearchRequest searchRequest = new RegistrySearchRequestBuilder(this.connectionContext) - .constrainByQueryString(q) - .addKeywordsParam(keywords) - .fieldsFromStrings(fields) - .paginate(limit, sort, searchAfter) - .onlyLatest() + .applyMultipleProductsDefaults(fields, q, keywords, limit, sort, searchAfter, true) .build(); SearchResponse searchResponse = @@ -299,7 +295,7 @@ private HashMap getLatestLidVid(PdsProductIdentifier identifier, SearchRequest searchRequest = new RegistrySearchRequestBuilder(this.connectionContext) .matchLid(identifier) .fieldsFromStrings(fields) - .onlyLatest() + .excludeSupersededProducts() .build(); // useless to detail here that the HashMap is parameterized @@ -347,7 +343,7 @@ private PdsProductClasses resolveProductClass(PdsProductIdentifier identifier) SearchRequest searchRequest = new RegistrySearchRequestBuilder(this.connectionContext) .matchLid(identifier) .fieldsFromStrings(List.of(PdsProductClasses.getPropertyName())) - .onlyLatest() + .excludeSupersededProducts() .build(); SearchResponse searchResponse = this.openSearchClient.search(searchRequest, HashMap.class); @@ -367,7 +363,7 @@ private PdsLidVid resolveLatestLidvid(PdsProductIdentifier identifier) SearchRequest searchRequest = new RegistrySearchRequestBuilder(this.connectionContext) .matchLid(identifier.getLid()) .fieldsFromStrings(List.of()) - .onlyLatest() + .excludeSupersededProducts() .build(); SearchResponse searchResponse = this.openSearchClient.search(searchRequest, HashMap.class); @@ -437,9 +433,7 @@ public ResponseEntity productMembers( } SearchRequest searchRequest = searchRequestBuilder - .fieldsFromStrings(fields) - .paginate(limit, sort, searchAfter) - .onlyLatest() + .applyMultipleProductsDefaults(fields, "", List.of(), limit, sort, searchAfter, true) .build(); SearchResponse searchResponse = @@ -449,7 +443,7 @@ public ResponseEntity productMembers( return formatMultipleProducts(products, fields); - } catch (IOException | OpenSearchException e) { + } catch (IOException | OpenSearchException | UnparsableQParamException e) { throw new UnhandledException(e); } } @@ -476,9 +470,7 @@ public ResponseEntity productMembersMembers( } SearchRequest searchRequest = searchRequestBuilder - .fieldsFromStrings(fields) - .paginate(limit, sort, searchAfter) - .onlyLatest() + .applyMultipleProductsDefaults(fields, "", List.of(), limit, sort, searchAfter, true) .build(); SearchResponse searchResponse = @@ -488,7 +480,7 @@ public ResponseEntity productMembersMembers( return formatMultipleProducts(products, fields); - } catch (IOException | OpenSearchException e) { + } catch (IOException | OpenSearchException | UnparsableQParamException e) { throw new UnhandledException(e); } } @@ -533,7 +525,7 @@ private List resolveLidVidsFromProductField(PdsProductIdentifier iden public ResponseEntity productMemberOf( String identifier, List fields, Integer limit, List sort, List searchAfter) throws NotFoundException, UnhandledException, SortSearchAfterMismatchException, BadRequestException, - AcceptFormatNotSupportedException{ + AcceptFormatNotSupportedException, UnparsableQParamException { try{ PdsProductIdentifier pdsIdentifier = PdsProductIdentifier.fromString(identifier); @@ -551,10 +543,8 @@ public ResponseEntity productMemberOf( } SearchRequest searchRequest = new RegistrySearchRequestBuilder(this.connectionContext) + .applyMultipleProductsDefaults(fields, "", List.of(), limit, sort, searchAfter, true) .matchFieldAnyOfIdentifiers("_id", parentIds) - .fieldsFromStrings(fields) - .paginate(limit, sort, searchAfter) - .onlyLatest() .build(); SearchResponse searchResponse = @@ -573,7 +563,7 @@ public ResponseEntity productMemberOf( public ResponseEntity productMemberOfOf( String identifier, List fields, Integer limit, List sort, List searchAfter) throws NotFoundException, UnhandledException, SortSearchAfterMismatchException, BadRequestException, - AcceptFormatNotSupportedException{ + AcceptFormatNotSupportedException, UnparsableQParamException { try{ PdsProductIdentifier pdsIdentifier = PdsProductIdentifier.fromString(identifier); @@ -590,10 +580,8 @@ public ResponseEntity productMemberOfOf( } SearchRequest searchRequest = new RegistrySearchRequestBuilder(this.connectionContext) + .applyMultipleProductsDefaults(fields, "", List.of(), limit, sort, searchAfter, true) .matchFieldAnyOfIdentifiers("_id", parentIds) - .fieldsFromStrings(fields) - .paginate(limit, sort, searchAfter) - .onlyLatest() .build(); SearchResponse searchResponse = @@ -619,12 +607,8 @@ public ResponseEntity classList(String propertyClass, List field } SearchRequest searchRequest = new RegistrySearchRequestBuilder(this.connectionContext) + .applyMultipleProductsDefaults(fields, q, keywords, limit, sort, searchAfter, true) .matchProductClass(pdsProductClass) - .constrainByQueryString(q) - .addKeywordsParam(keywords) - .fieldsFromStrings(fields) - .paginate(limit, sort, searchAfter) - .onlyLatest() .build(); SearchResponse searchResponse = diff --git a/service/src/main/java/gov/nasa/pds/api/registry/search/RegistrySearchRequestBuilder.java b/service/src/main/java/gov/nasa/pds/api/registry/search/RegistrySearchRequestBuilder.java index 66e3e065..ab1ed850 100644 --- a/service/src/main/java/gov/nasa/pds/api/registry/search/RegistrySearchRequestBuilder.java +++ b/service/src/main/java/gov/nasa/pds/api/registry/search/RegistrySearchRequestBuilder.java @@ -106,6 +106,39 @@ public BoolQuery.Builder getQueryBuilder() { return this.queryBuilder; } + /** + * Applies a common set of constraints and other build options which generally apply to any endpoint which queries + * OpenSearch for a result-set of multiple products. + * @param includeFieldNames - which properties to include in the results (JSON format, not OpenSearch format) + * @param queryString - a querystring (q=) to constrain the result-set by + * @param keywords - a set of keyword matches to + * @param pageSize - the page size to use for pagination + * @param sortFieldNames - the fields by which results are sorted (ascending), from highest to lowest priority + * @param searchAfterFieldValues - the values corresponding to the sort fields, for pagination + * @param excludeSupersededProducts - whether to exclude superseded products from the result set + */ + public RegistrySearchRequestBuilder applyMultipleProductsDefaults( + List includeFieldNames, + String queryString, + List keywords, + Integer pageSize, + List sortFieldNames, + List searchAfterFieldValues, + Boolean excludeSupersededProducts + ) throws UnparsableQParamException, SortSearchAfterMismatchException { + this + .fieldsFromStrings(includeFieldNames) + .constrainByQueryString(queryString) + .addKeywordsParam(keywords) + .paginate(pageSize, sortFieldNames, searchAfterFieldValues); + + if (excludeSupersededProducts) { + this.excludeSupersededProducts(); + } + + return this; + } + public SearchRequest build() { this.query(this.queryBuilder.build().toQuery()); this.trackTotalHits(t -> t.enabled(true)); @@ -325,7 +358,7 @@ public RegistrySearchRequestBuilder addKeywordsParam(List keywords) { * N.B. this does *not* mean the latest version which satisfies other constraints, so application of this constraint * can result in no hits being returned despite valid results existing. */ - public RegistrySearchRequestBuilder onlyLatest() { + public RegistrySearchRequestBuilder excludeSupersededProducts() { ExistsQuery supersededByExists = new ExistsQuery.Builder() .field("ops:Provenance/ops:superseded_by")