Skip to content

Commit

Permalink
Issue #1922 - support _tag text and sort searches
Browse files Browse the repository at this point in the history
Signed-off-by: Mike Schroeder <mschroed@us.ibm.com>
  • Loading branch information
michaelwschroeder committed Jun 21, 2021
1 parent 6e2d0ae commit cc105f3
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 78 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,23 @@ public class SearchWholeSystemQuery extends SearchQuery {
// Flag indicating if a count query or a data query
boolean isCountQuery;

// Is pagination required?
boolean addPagination = true;

// Sort parameters
final List<DomainSortParameter> sortParameters = new ArrayList<>();

/**
* Public constructor
* @param domainModels
* @param isCountQuery
* @param addPagination
*/
public SearchWholeSystemQuery(List<SearchQuery> domainModels, boolean isCountQuery) {
public SearchWholeSystemQuery(List<SearchQuery> domainModels, boolean isCountQuery, boolean addPagination) {
super(Resource.class.getSimpleName());
this.domainModels = domainModels;
this.isCountQuery = isCountQuery;
this.addPagination = addPagination;
}

/**
Expand Down Expand Up @@ -68,6 +73,11 @@ public <T> T visit(SearchQueryVisitor<T> visitor) throws FHIRPersistenceExceptio
query = visitor.addWholeSystemSorting(query, sortParameters, "COMBINED_RESULTS");
}

// Add pagination
if (addPagination) {
query = visitor.addPagination(query);
}

return query;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -473,9 +473,11 @@ private SqlQueryData processStringParm(QueryParameter queryParm, String tableAli

appendEscape = false;
if (LIKE.equals(operator)) {
// Must escape special wildcard characters _ and % in the parameter value string.
// Must escape special wildcard characters _ and % in the parameter value string
// as well as the escape character itself.
tempSearchValue =
SqlParameterEncoder.encode(value.getValueString()
.replace("+", "++")
.replace(PERCENT_WILDCARD, ESCAPE_PERCENT)
.replace(UNDERSCORE_WILDCARD, ESCAPE_UNDERSCORE));
if (Modifier.CONTAINS.equals(queryParm.getModifier())) {
Expand Down Expand Up @@ -1275,8 +1277,10 @@ private SqlQueryData processTokenParm(Class<?> resourceType, QueryParameter quer
if (LIKE.equals(operator)) {
whereClauseSegment.append(tableAlias + DOT).append(TOKEN_VALUE).append(operator).append(BIND_VAR);

// Must escape special wildcard characters _ and % in the parameter value string.
// Must escape special wildcard characters _ and % in the parameter value string
// as well as the escape character itself.
String textSearchString = SqlParameterEncoder.encode(value.getValueCode())
.replace("+", "++")
.replace(PERCENT_WILDCARD, ESCAPE_PERCENT)
.replace(UNDERSCORE_WILDCARD, ESCAPE_UNDERSCORE) + PERCENT_WILDCARD;
bindVariables.add(SearchUtil.normalizeForSearch(textSearchString));
Expand Down Expand Up @@ -2244,11 +2248,12 @@ private SqlQueryData processTagParm(Class<?> resourceType, QueryParameter queryP
if (code != null) {
whereClauseSegment.append(tableAlias).append(DOT).append(TOKEN_VALUE).append(operator).append(BIND_VAR);
if (LIKE.equals(operator)) {
// Must escape special wildcard characters _ and % in the parameter value string.
// Must escape special wildcard characters _ and % in the parameter value string
// as well as the escape character itself.
String textSearchString = normalizedCode
.replace("+", "++")
.replace(PERCENT_WILDCARD, ESCAPE_PERCENT)
.replace(UNDERSCORE_WILDCARD, ESCAPE_UNDERSCORE)
.replace("+", "++")+ PERCENT_WILDCARD;
.replace(UNDERSCORE_WILDCARD, ESCAPE_UNDERSCORE) + PERCENT_WILDCARD;
bindVariables.add(SearchUtil.normalizeForSearch(textSearchString));
appendEscape = true;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ public Select buildCountQuery(Class<?> resourceType, FHIRSearchContext searchCon
subDomainModels.add(subDomainModel);
}
// Create whole-system search domain model
domainModel = new SearchWholeSystemQuery(subDomainModels, true);
domainModel = new SearchWholeSystemQuery(subDomainModels, true, false);
} else {
domainModel = new SearchCountQuery(resourceType.getSimpleName());
}
Expand Down Expand Up @@ -219,7 +219,7 @@ public Select buildQuery(Class<?> resourceType, FHIRSearchContext searchContext)
}
// Create whole-system search domain model
SearchWholeSystemQuery wholeSystemAllDataQuery =
new SearchWholeSystemQuery(subDomainModels, false);
new SearchWholeSystemQuery(subDomainModels, false, true);
for (SortParameter sp: searchContext.getSortParameters()) {
wholeSystemAllDataQuery.add(new DomainSortParameter(sp));
}
Expand Down Expand Up @@ -340,7 +340,7 @@ public Select buildWholeSystemDataQuery(FHIRSearchContext searchContext, Map<Int
}
// Create whole-system search domain model
SearchWholeSystemQuery wholeSystemAllDataQuery =
new SearchWholeSystemQuery(subDomainModels, false);
new SearchWholeSystemQuery(subDomainModels, false, false);
for (SortParameter sp: searchContext.getSortParameters()) {
wholeSystemAllDataQuery.add(new DomainSortParameter(sp));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,9 @@ public static String tableName(String resourceType, QueryParameter param) {
case TOKEN:
if (param.isReverseChained()) {
name.append("_LOGICAL_RESOURCES");
} else if (PARAM_NAME_TAG.equals(param.getCode())) {
} else if (PARAM_NAME_TAG.equals(param.getCode()) &&
(param.getModifier() == null ||
!Modifier.TEXT.equals(param.getModifier()))) {
name.append("_TAGS ");
} else {
name.append("_TOKEN_VALUES_V "); // uses view to hide new issue #1366 schema
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* (C) Copyright IBM Corp. 2017, 2020
* (C) Copyright IBM Corp. 2017, 2021
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -19,13 +19,16 @@
import static com.ibm.fhir.persistence.jdbc.JDBCConstants.NUMBER_VALUE;
import static com.ibm.fhir.persistence.jdbc.JDBCConstants.ON;
import static com.ibm.fhir.persistence.jdbc.JDBCConstants.ORDER_BY;
import static com.ibm.fhir.persistence.jdbc.JDBCConstants.PARAM_NAME_PROFILE;
import static com.ibm.fhir.persistence.jdbc.JDBCConstants.PARAM_NAME_TAG;
import static com.ibm.fhir.persistence.jdbc.JDBCConstants.QUANTITY_VALUE;
import static com.ibm.fhir.persistence.jdbc.JDBCConstants.RIGHT_PAREN;
import static com.ibm.fhir.persistence.jdbc.JDBCConstants.SPACE;
import static com.ibm.fhir.persistence.jdbc.JDBCConstants.STR_VALUE;
import static com.ibm.fhir.persistence.jdbc.JDBCConstants.TOKEN_VALUE;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;

Expand Down Expand Up @@ -205,7 +208,11 @@ private String buildAggregateExpression(SortParameter sortParm, int sortParmInde
StringBuilder expression = new StringBuilder();
List<String> valueAttributeNames;

valueAttributeNames = this.getValueAttributeNames(sortParm);
if (PARAM_NAME_TAG.equals(sortParm.getCode()) || PARAM_NAME_PROFILE.equals(sortParm.getCode())) {
valueAttributeNames = Collections.singletonList(TOKEN_VALUE);
} else {
valueAttributeNames = this.getValueAttributeNames(sortParm);
}
boolean nameProcessed = false;
for (String attributeName : valueAttributeNames) {
if (nameProcessed) {
Expand Down Expand Up @@ -306,20 +313,35 @@ private String buildSortJoinClause() throws FHIRPersistenceException {
int sortParmIndex = 1;
for (SortParameter sortParm : this.sortParameters) {
if (!SearchConstants.LAST_UPDATED.equals(sortParm.getCode())) {
sortParameterNameId = ParameterNamesCache.getParameterNameId(sortParm.getCode());
if (sortParameterNameId == null) {
// Only read...don't try and create the parameter name if it doesn't exist
sortParameterNameId = this.parameterDao.readParameterNameId(sortParm.getCode());
if (sortParameterNameId != null) {
this.parameterDao.addParameterNamesCacheCandidate(sortParm.getCode(), sortParameterNameId);
} else {
sortParameterNameId = -1; // so we don't break the query syntax
if (PARAM_NAME_TAG.equals(sortParm.getCode()) || PARAM_NAME_PROFILE.equals(sortParm.getCode())) {
// For a sort by _tag or _profile, we need to join the parameter-specific token
// table with the common token values table.
joinBuffer.append(" LEFT OUTER JOIN ").append(this.getSortParameterTableName(sortParm)).append(SPACE)
.append(SORT_PARAMETER_ALIAS).append(sortParmIndex).append("_P")
.append(ON)
.append(SORT_PARAMETER_ALIAS).append(sortParmIndex).append("_P")
.append(".LOGICAL_RESOURCE_ID = R.LOGICAL_RESOURCE_ID")
.append(" INNER JOIN ").append("COMMON_TOKEN_VALUES").append(SPACE)
.append(SORT_PARAMETER_ALIAS).append(sortParmIndex)
.append(ON)
.append(SORT_PARAMETER_ALIAS).append(sortParmIndex)
.append(".COMMON_TOKEN_VALUE_ID = ").append(SORT_PARAMETER_ALIAS).append(sortParmIndex)
.append("_P.COMMON_TOKEN_VALUE_ID").append(SPACE);
} else {
sortParameterNameId = ParameterNamesCache.getParameterNameId(sortParm.getCode());
if (sortParameterNameId == null) {
// Only read...don't try and create the parameter name if it doesn't exist
sortParameterNameId = this.parameterDao.readParameterNameId(sortParm.getCode());
if (sortParameterNameId != null) {
this.parameterDao.addParameterNamesCacheCandidate(sortParm.getCode(), sortParameterNameId);
} else {
sortParameterNameId = -1; // so we don't break the query syntax
}
}
}

// Note...the PARAMETER_NAME_ID=xxx is provided as a literal because this helps
// the query optimizer significantly with index range scan cardinality estimation
joinBuffer.append(" LEFT OUTER JOIN ").append(this.getSortParameterTableName(sortParm)).append(SPACE)
// Note...the PARAMETER_NAME_ID=xxx is provided as a literal because this helps
// the query optimizer significantly with index range scan cardinality estimation
joinBuffer.append(" LEFT OUTER JOIN ").append(this.getSortParameterTableName(sortParm)).append(SPACE)
.append(SORT_PARAMETER_ALIAS).append(sortParmIndex)
.append(ON)
.append(LEFT_PAREN)
Expand All @@ -329,6 +351,7 @@ private String buildSortJoinClause() throws FHIRPersistenceException {
.append(SORT_PARAMETER_ALIAS).append(sortParmIndex)
.append(".LOGICAL_RESOURCE_ID = R.LOGICAL_RESOURCE_ID")
.append(RIGHT_PAREN).append(SPACE);
}

sortParmIndex++;
}
Expand Down Expand Up @@ -356,14 +379,22 @@ private String getSortParameterTableName(SortParameter sortParm) throws FHIRPers
switch (sortParm.getType()) {
case URI:
case STRING:
sortParameterTableName.append("STR_VALUES");
if (PARAM_NAME_PROFILE.equals(sortParm.getCode())) {
sortParameterTableName.append("PROFILES");
} else {
sortParameterTableName.append("STR_VALUES");
}
break;
case DATE:
sortParameterTableName.append("DATE_VALUES");
break;
case REFERENCE:
case TOKEN:
sortParameterTableName.append("TOKEN_VALUES_V");
if (PARAM_NAME_TAG.equals(sortParm.getCode())) {
sortParameterTableName.append("TAGS");
} else {
sortParameterTableName.append("TOKEN_VALUES_V");
}
break;
case NUMBER:
sortParameterTableName.append("NUMBER_VALUES");
Expand Down

0 comments on commit cc105f3

Please sign in to comment.