Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
3640e5d
Add new filter/sort models
jloux-brapi May 7, 2026
fd64178
Preliminary generic sortBy implementation on searchRequests
jloux-brapi May 7, 2026
32664a2
Use @Formula to derive needed addInfo entity attrs, update SearchQuer…
jloux-brapi May 21, 2026
2d51285
Preliminary pass at allowed fields mapping
jloux-brapi May 21, 2026
f9440f0
Add parametrization logic for filter values, infrastructure for 400 e…
jloux-brapi May 22, 2026
90214e0
Use new SortBy class in all use cases.
jloux-brapi May 22, 2026
90e77dd
Make filter case insensitive
jloux-brapi May 29, 2026
3bf581a
Fix pom jackson depedency issues
jloux-brapi Jun 1, 2026
da60a1a
Migrate parent observation ids on ou_level to brapi dbIds
jloux-brapi Jul 21, 2026
c2afc76
Add some clarifying comments
jloux-brapi Jul 21, 2026
5809fa9
Merge branch 'develop' into feature/BI-2861
jloux-brapi Jul 21, 2026
47e1c27
Merge branch 'feature/BI-2861' into feature/BI-2995
jloux-brapi Jul 21, 2026
56c9821
Migrate sample bi ouIds to brapi ouIds
jloux-brapi Jul 22, 2026
e079626
Add back in distinct to general search build query
jloux-brapi Jul 24, 2026
647b44f
Implement data types for filtering
jloux-brapi Jul 27, 2026
b095c97
Add code for filtering on one to many relationship entity collections
jloux-brapi Aug 3, 2026
05fb082
Fix issue with sorting for GET study/trial endpoints
jloux-brapi Aug 4, 2026
b0bf8ba
Fix issues with using distinct in sorting
jloux-brapi Aug 6, 2026
22736ae
Add Pattern to end of filter params in SearchQueryBuilder
jloux-brapi Aug 7, 2026
2bd1d47
Create migration script, add programDbId to entity and model
jloux-brapi Aug 10, 2026
2bad4ff
Support for programId in GermplasmApi
jloux-brapi Aug 11, 2026
5a747b4
Use more restrictive exref query, add assertion to migration
jloux-brapi Aug 18, 2026
c17b97a
Add semicolon
jloux-brapi Aug 18, 2026
3867e85
Merge branch 'feature/BI-2995' into feature/BI-2996
jloux-brapi Aug 18, 2026
cc05724
Update comment
jloux-brapi Aug 19, 2026
7358397
Merge branch 'feature/BI-2995' into feature/BI-2996
jloux-brapi Aug 19, 2026
cc82ecd
Update migration script with stricter matching to OU, add assertion
jloux-brapi Aug 19, 2026
bd8e00a
Merge branch 'feature/BI-2996' into feature/BI-2903
jloux-brapi Aug 19, 2026
b6f2c9b
Merge branch 'develop' into feature/BI-2861
jloux-brapi Aug 20, 2026
6a928e3
Merge branch 'feature/BI-2861' into feature/BI-2995
jloux-brapi Aug 20, 2026
9f20402
Merge branch 'feature/BI-2995' into feature/BI-2996
jloux-brapi Aug 20, 2026
ad1c04a
Merge branch 'feature/BI-2996' into feature/BI-2903
jloux-brapi Aug 20, 2026
b308330
Undo removed changes from develop
jloux-brapi Aug 20, 2026
cb8c576
Merge branch 'feature/BI-2861' into feature/BI-2995
jloux-brapi Aug 20, 2026
05478ff
Merge branch 'feature/BI-2995' into feature/BI-2996
jloux-brapi Aug 20, 2026
7248c4d
Merge branch 'feature/BI-2996' into feature/BI-2903
jloux-brapi Aug 20, 2026
265da14
Ignore getMethod on sortFilter map that was breaking async use case
jloux-brapi Aug 24, 2026
f57dc76
Merge branch 'feature/BI-2861' into feature/BI-2995
jloux-brapi Aug 24, 2026
6c60dc0
Merge branch 'feature/BI-2995' into feature/BI-2996
jloux-brapi Aug 24, 2026
ef2bade
Merge branch 'feature/BI-2996' into feature/BI-2903
jloux-brapi Aug 24, 2026
ccc5e1d
Merge pull request #17 from Breeding-Insight/feature/BI-2861
jloux-brapi Aug 24, 2026
7de362b
Merge pull request #19 from Breeding-Insight/feature/BI-2995
jloux-brapi Aug 24, 2026
d2a62d2
Merge pull request #20 from Breeding-Insight/feature/BI-2996
jloux-brapi Aug 24, 2026
5a39677
Fix createEntities in batch error, address migration concerns
jloux-brapi Aug 26, 2026
5bdde47
Merge pull request #23 from Breeding-Insight/feature/BI-2903
jloux-brapi Aug 27, 2026
1ec9363
Remove dbIds from paramCount for Germplasm
jloux-brapi Aug 31, 2026
f6033fd
BI-2922: Added the filter parms.
humsika Sep 22, 2026
5503404
Changes to support filtering/sorting for germplasm
jloux-brapi Sep 16, 2026
1757a39
Address issues with removing sorting from getIdQuery
jloux-brapi Sep 28, 2026
a22c0a3
Removed exref ids/source, germplasm names from async check, add comment
jloux-brapi Sep 29, 2026
1c20998
Ensure subquery uses proper alias, add more clarifying comments
jloux-brapi Sep 30, 2026
5b13c4e
Support for collation on germplasm search columns
jloux-brapi Sep 30, 2026
551a5b2
Use exact matching for NUMBER data types
jloux-brapi Oct 1, 2026
9002fd6
Merge pull request #27 from Breeding-Insight/feature/BI-2922
jloux-brapi Oct 2, 2026
af9a82b
Implement regex expression for entity replacement for more fine grain…
jloux-brapi Oct 5, 2026
362fa6d
Merge branch 'feature/BI-2907' into feature/BI-3061-3057
jloux-brapi Oct 5, 2026
9eb055b
Support for nullable defaults
jloux-brapi Oct 5, 2026
e3eeb37
Merge pull request #28 from Breeding-Insight/feature/BI-2907
jloux-brapi Oct 6, 2026
67d6a03
Merge pull request #29 from Breeding-Insight/feature/BI-3061-3057
jloux-brapi Oct 6, 2026
076d92f
Make changes to migration and filtering to support default date value
jloux-brapi Oct 6, 2026
85c1116
Merge pull request #31 from Breeding-Insight/bug/BI-3066
jloux-brapi Oct 8, 2026
bcf87be
BI-2964: Updated the logic of how the pages are calculate to avoid ge…
humsika Oct 12, 2026
091f833
Lay groundwork for generic ListItem implementation
jloux-brapi Oct 12, 2026
5e18e83
Fix some bugs, add working example query
jloux-brapi Oct 13, 2026
9fd14f8
Clean out sample code, bolster SearchQueryBuilder attributes
jloux-brapi Oct 13, 2026
87f9608
Get /lists/{listDbId}/search/items into fully functional state
jloux-brapi Oct 14, 2026
3c08de5
Add @Formula for checking item position with 1 index
jloux-brapi Oct 14, 2026
6b906c9
Fix GermplasmService redline in IDE not causing compile or runtime er…
jloux-brapi Oct 14, 2026
4b0dd0e
Merge pull request #32 from Breeding-Insight/feature/BI-2964
jloux-brapi Oct 15, 2026
abe7364
Merge branch 'epic/BI-2862' into feature/BI-3082
jloux-brapi Oct 15, 2026
bb71d95
Model edits
jloux-brapi Oct 15, 2026
4452596
Force type deserialization on client, changes to support this
jloux-brapi Oct 16, 2026
500a833
Validate fields in submitted search request to ensure proper searches
jloux-brapi Oct 16, 2026
6bb6f83
Simplify validation logic
jloux-brapi Oct 19, 2026
4a31b8e
Add clarifying comments
jloux-brapi Oct 19, 2026
677d759
Fix alias bug with synonyms
jloux-brapi Oct 19, 2026
aa58f06
Add comment to BrAPIRepositoryImpl
jloux-brapi Oct 19, 2026
84ec9bd
Add comments to SortAndFilterEntityColumnInfo
jloux-brapi Oct 19, 2026
1fc0445
Add comment for extra synonyms join
jloux-brapi Oct 19, 2026
f7593b2
Fix synonym wrong object setting/getting, SearchRequest sort/filter *…
jloux-brapi Oct 22, 2026
6e8e32d
Only re-add synonym join if filter present
jloux-brapi Oct 22, 2026
4db1b4f
Remove 202 from searchListByItemRequest, not relevant
jloux-brapi Oct 23, 2026
0c67028
Merge pull request #33 from Breeding-Insight/feature/BI-3082
jloux-brapi Oct 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions src/main/java/io/swagger/api/core/ListsApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,10 @@
*/
package io.swagger.api.core;

import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.model.BrAPIResponse;
import io.swagger.model.Model202AcceptedSearchResponse;
import io.swagger.model.core.ListNewRequest;
import io.swagger.model.core.ListResponse;
import io.swagger.model.core.ListSearchRequest;
import io.swagger.model.core.ListsListResponse;
import io.swagger.model.core.ListsSingleResponse;
import io.swagger.model.core.*;
import io.swagger.annotations.*;

import org.brapi.test.BrAPITestServer.exceptions.BrAPIServerException;
Expand Down Expand Up @@ -166,4 +163,15 @@ ResponseEntity<? extends BrAPIResponse> searchListsSearchResultsDbIdGet(
@ApiParam(value = "pageSize") @Valid @RequestParam(value = "pageSize", required = false) Integer pageSize,
@ApiParam(value = "HTTP HEADER - Token used for Authorization <strong> Bearer {token_string} </strong>") @RequestHeader(value = "Authorization", required = false) String authorization) throws BrAPIServerException;

@ApiOperation(value = "Submit a search request for List Items", nickname = "searchListByItemRequest", notes = "Advanced searching for the list item resource. See Search Services for additional implementation details.", response = ListItemsListResponse.class, authorizations = {
@Authorization(value = "AuthorizationToken") }, tags = { "Lists", })
@ApiResponses(value = { @ApiResponse(code = 200, message = "OK", response = ListItemsListResponse.class),
@ApiResponse(code = 400, message = "Bad Request", response = String.class),
@ApiResponse(code = 401, message = "Unauthorized", response = String.class),
@ApiResponse(code = 403, message = "Forbidden", response = String.class) })
@RequestMapping(value = "/search/lists/{listDbId}/items", produces = { "application/json" }, consumes = {
"application/json" }, method = RequestMethod.POST)
ResponseEntity<? extends BrAPIResponse> searchListByItemRequest(@ApiParam(value = "") @Valid @RequestBody JsonNode body,
@ApiParam(value = "Permanent unique identifier of list to perform search on", required = true) @PathVariable("listDbId") String listDbId,
@ApiParam(value = "HTTP HEADER - Token used for Authorization <strong> Bearer {token_string} </strong>") @RequestHeader(value = "Authorization", required = false) String authorization) throws BrAPIServerException;
}
1 change: 1 addition & 0 deletions src/main/java/io/swagger/api/germ/GermplasmApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ ResponseEntity<GermplasmListResponse> germplasmGet(
@ApiParam(value = "progenyDbId") @Valid @RequestParam(value = "progenyDbId", required = false) String progenyDbId,
@ApiParam(value = "commonCropName") @Valid @RequestParam(value = "commonCropName", required = false) String commonCropName,
@ApiParam(value = "programDbId") @Valid @RequestParam(value = "programDbId", required = false) String programDbId,
@ApiParam(value = "programName") @Valid @RequestParam(value = "programName", required = false) String programName,
@ApiParam(value = "externalReferenceID") @Valid @RequestParam(value = "externalReferenceID", required = false) String externalReferenceID,
@ApiParam(value = "externalReferenceId") @Valid @RequestParam(value = "externalReferenceId", required = false) String externalReferenceId,
@ApiParam(value = "externalReferenceSource") @Valid @RequestParam(value = "externalReferenceSource", required = false) String externalReferenceSource,
Expand Down
24 changes: 24 additions & 0 deletions src/main/java/io/swagger/model/FilterBy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.swagger.model;

public class FilterBy {

private String filterOn;
private String value;

public String getFilterOn() {
return filterOn;
}

public void setFilterOn(String filterOn) {
this.filterOn = filterOn;
}

public String getValue() {
return value;
}

public void setValue(String value) {
this.value = value;
}

}
92 changes: 92 additions & 0 deletions src/main/java/io/swagger/model/SearchRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.model.sort.SortBy;
import org.brapi.test.BrAPITestServer.exceptions.BrAPIServerException;
import org.brapi.test.BrAPITestServer.model.dto.SortAndFilterEntityColumnInfo;
import org.brapi.test.BrAPITestServer.model.dto.EntityType;
import org.springframework.http.HttpStatus;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public abstract class SearchRequest {
@JsonIgnore
Expand All @@ -25,6 +31,20 @@ public abstract class SearchRequest {
@JsonProperty("externalReferenceSources")
protected List<String> externalReferenceSources = null;

@JsonProperty("filterBy")
protected List<FilterBy> filterBy = null;

@JsonProperty("sortBy")
protected List<SortBy> sortBy = null;

@JsonIgnore
protected Map<String, String> sortFilterEntityColumnNamesByRequestName = null;

@JsonIgnore
public List<String> getExternalReferenceIds() {
return externalReferenceIds;
}

final public SearchRequest page(Integer page) {
this.page = page;
return this;
Expand Down Expand Up @@ -119,4 +139,76 @@ public void addExternalReferenceItem(String externalReferenceId, String external
}

}

public List<FilterBy> getFilterBy() {
return filterBy;
}

public void setFilterBy(List<FilterBy> filterBy) throws BrAPIServerException {

if (filterBy == null || filterBy.isEmpty()) {
return;
}

Map<String, SortAndFilterEntityColumnInfo> allowedSortFilterNames = getEntityColInfoBySubmittedNameMap();

for (FilterBy filterByItem : filterBy) {

if (filterByItem.getFilterOn() == null || filterByItem.getFilterOn().isEmpty()) {
throw new BrAPIServerException(HttpStatus.BAD_REQUEST, "filterOn attribute not provided in element of filterBy list.");
}

if (filterByItem.getValue() == null || filterByItem.getValue().isEmpty()) {
throw new BrAPIServerException(HttpStatus.BAD_REQUEST, "value attribute not provided in element of filterBy list.");
}

SortAndFilterEntityColumnInfo sortAndFilterEntityColumnInfo = allowedSortFilterNames.get(filterByItem.getFilterOn());

if (sortAndFilterEntityColumnInfo == null) {
throw new BrAPIServerException(HttpStatus.BAD_REQUEST,
String.format("Supplied filterColumn [%s] not available in allowed names [%s]", filterByItem.getFilterOn(), allowedSortFilterNames.keySet())
);
}

if (sortAndFilterEntityColumnInfo.getEntityType() == EntityType.BOOLEAN) {
// TODO: Add support for this when it becomes relevant for BI or when there is time.
throw new BrAPIServerException(HttpStatus.BAD_REQUEST, String.format("Filtering not implemented for column name [%s] with associated data type [%s]", sortAndFilterEntityColumnInfo.getEntityColumnName(), EntityType.BOOLEAN));
}
}
this.filterBy = filterBy;
}

public List<SortBy> getSortByElements() {
return sortBy;
}

public void setSortBy(List<SortBy> sortBy) throws BrAPIServerException {

if (sortBy == null || sortBy.isEmpty()) {
return;
}

Map<String, SortAndFilterEntityColumnInfo> allowedSortFilterNames = getEntityColInfoBySubmittedNameMap();

for (SortBy sortByItem : sortBy) {
if (sortByItem.getSortedOn() == null || sortByItem.getSortedOn().isEmpty()) {
throw new BrAPIServerException(HttpStatus.BAD_REQUEST, "sortedOn attribute not provided in element of sortBy list");
}

SortAndFilterEntityColumnInfo sortColumnEntityNameAndType = getEntityColInfoBySubmittedNameMap().get(sortByItem.getSortedOn());

if (sortColumnEntityNameAndType == null) {
throw new BrAPIServerException(HttpStatus.BAD_REQUEST,
String.format("Supplied sortColumn [%s] not available in allowed names [%s]", sortByItem.getSortedOn(), allowedSortFilterNames.keySet())
);
}
}

this.sortBy = sortBy;
}

@JsonIgnore
public Map<String, SortAndFilterEntityColumnInfo> getEntityColInfoBySubmittedNameMap() throws BrAPIServerException {
throw new BrAPIServerException(HttpStatus.BAD_REQUEST, String.format("Sort/Filtering not implemented for %s", this.getClass().getSimpleName()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.swagger.model.core;

import io.swagger.model.germ.GermplasmSearchRequest;
import org.brapi.test.BrAPITestServer.model.dto.SortAndFilterEntityColumnInfo;
import org.brapi.test.BrAPITestServer.model.dto.EntityType;

import java.util.Collections;
import java.util.Map;

public class GermplasmListSearchRequest extends GermplasmSearchRequest {

// The only real difference in this request is that there's an extra sort/filter field that GermplasmSearchRequest doesn't have.
// It is specific to lists. In general, other EntityListSearchRequests like this one should look the same, but have different base search requests.
private static final Map<String, SortAndFilterEntityColumnInfo>
LIST_ALLOWED_FIELDS;

static {
Map<String, SortAndFilterEntityColumnInfo> fields =
copyAllowedSortAndFilterFields();

fields.put(
"listItemPosition",
new SortAndFilterEntityColumnInfo("*listItem.positionIndexedBy1", EntityType.NUMBER, false, true)
);

LIST_ALLOWED_FIELDS = Collections.unmodifiableMap(fields);
}

@Override
public Map<String, SortAndFilterEntityColumnInfo> getEntityColInfoBySubmittedNameMap() {
return LIST_ALLOWED_FIELDS;
}
}
95 changes: 95 additions & 0 deletions src/main/java/io/swagger/model/core/ListItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package io.swagger.model.core;

import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.validation.annotation.Validated;

/**
* ListItem
*/
@Validated
@javax.annotation.processing.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2020-03-20T16:31:52.030Z[GMT]")
public class ListItem {
@JsonProperty("listItemDbId")
private String listItemDbId = null;

@JsonProperty("position")
private Integer position = null;

// This represents the actual value stored in the list_item table
@JsonProperty("item")
private String item = null;

/**
* The unique identifier for a List
* @return listDbId
**/
@ApiModelProperty(example = "6f621cfa", required = true, value = "The unique identifier for a List")


public String getListItemDbId() {
return listItemDbId;
}

public void setListItemDbId(String listItemDbId) {
this.listItemDbId = listItemDbId;
}

public Integer getPosition() {
return position;
}

public void setPosition(Integer position) {
this.position = position;
}

public String getItem() {
return item;
}

public void setItem(String item) {
this.item = item;
}

@Override
public boolean equals(java.lang.Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ListItem ListItem = (ListItem) o;
return Objects.equals(this.listItemDbId, ListItem.listItemDbId) &&
super.equals(o);
}

@Override
public int hashCode() {
return Objects.hash(listItemDbId, super.hashCode());
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("class ListItem {\n");
sb.append(" ").append(toIndentedString(super.toString())).append("\n");
sb.append(" listDbId: ").append(toIndentedString(listItemDbId)).append("\n");
sb.append("}");
return sb.toString();
}

/**
* Convert the given object to string with each line indented by 4 spaces
* (except the first line).
*/
private String toIndentedString(java.lang.Object o) {
if (o == null) {
return "null";
}
return o.toString().replace("\n", "\n ");
}
}


83 changes: 83 additions & 0 deletions src/main/java/io/swagger/model/core/ListItemWithFullItem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package io.swagger.model.core;

import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.validation.annotation.Validated;

/**
* ListItemWithFullItem
*/
@Validated
@javax.annotation.processing.Generated(value = "io.swagger.codegen.v3.generators.java.SpringCodegen", date = "2020-03-20T16:31:52.030Z[GMT]")
public class ListItemWithFullItem<T> {
@JsonProperty("listItem")
private ListItem listItem = null;

// The full actual BrAPI model object of the list item is supplied/written into here
@JsonProperty("item")
private T item = null;

/**
* The unique identifier for a List
* @return listItem
**/
@ApiModelProperty(example = "6f621cfa", required = true, value = "The unique identifier for a List")


public ListItem getListItem() {
return listItem;
}

public void setListItem(ListItem listItem) {
this.listItem = listItem;
}

public T getItem() {
return item;
}

public void setItem(T item) {
this.item = item;
}

@Override
public boolean equals(java.lang.Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ListItemWithFullItem<T> listItemWithFullItem = (ListItemWithFullItem<T>) o;
return Objects.equals(this.listItem, listItemWithFullItem.listItem) &&
super.equals(o);
}

@Override
public int hashCode() {
return Objects.hash(listItem, super.hashCode());
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("class ListItemWithFullItem {\n");
sb.append(" ").append(toIndentedString(super.toString())).append("\n");
sb.append(" listItem: ").append(toIndentedString(listItem)).append("\n");
sb.append("}");
return sb.toString();
}

/**
* Convert the given object to string with each line indented by 4 spaces
* (except the first line).
*/
private String toIndentedString(java.lang.Object o) {
if (o == null) {
return "null";
}
return o.toString().replace("\n", "\n ");
}
}

Loading
Loading