Skip to content

Commit

Permalink
Issue #1922 - add union support, implement whole-system with _type
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 14, 2021
1 parent f32ffa4 commit 3b81116
Show file tree
Hide file tree
Showing 18 changed files with 466 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import static com.ibm.fhir.database.utils.query.SqlConstants.FROM;
import static com.ibm.fhir.database.utils.query.SqlConstants.SELECT;
import static com.ibm.fhir.database.utils.query.SqlConstants.SPACE;
import static com.ibm.fhir.database.utils.query.SqlConstants.UNION;
import static com.ibm.fhir.database.utils.query.SqlConstants.UNION_ALL;

import com.ibm.fhir.database.utils.api.IDatabaseTranslator;
import com.ibm.fhir.database.utils.derby.DerbyTranslator;
Expand Down Expand Up @@ -48,6 +50,12 @@ public class Select {
// offset/limit for pagination
private PaginationClause paginationClause;

// Another Select to UNION with this select. Optional
private Select union;

// If true, the specified UNION is a UNION ALL
private boolean unionAll = false;

/**
* Default constructor. Not a DISTINCT select.
*/
Expand Down Expand Up @@ -218,6 +226,11 @@ public String toString() {
result.append(SPACE).append(this.paginationClause.toString());
}

if (this.union != null) {
result.append(SPACE).append(unionAll ? UNION_ALL : UNION).append(SPACE)
.append(this.union.toString());
}

return result.toString();
}

Expand All @@ -233,7 +246,13 @@ public String toDebugString() {
// Generate a pretty-printed string using the renderer so we
// get an accurate version of the string.
StringStatementRenderer renderer = new StringStatementRenderer(TRANSLATOR, null, true);
return this.render(renderer);
if (union != null) {
StringBuilder result = new StringBuilder();
result.append(this.render(renderer)).append(union.toDebugString());
return result.toString();
} else {
return this.render(renderer);
}
} catch (Exception x) {
// If we can't render, it's very likely this debug is being used already
// in a catch clause from an earlier exception. So rather than propagating
Expand All @@ -249,8 +268,18 @@ public String toDebugString() {
* @param renderer
* @return
*/
@SuppressWarnings("unchecked")
public <T> T render(StatementRenderer<T> renderer) {
return renderer.select(distinct, selectList, fromClause, whereClause, groupByClause, havingClause, orderByClause, paginationClause);
if (union != null) {
StringBuilder result = new StringBuilder();
T rendered = renderer.select(distinct, selectList, fromClause, whereClause,
groupByClause, havingClause, orderByClause, paginationClause, unionAll, union);
result.append(rendered).append(union.render(renderer));
return (T) result.toString();
} else {
return renderer.select(distinct, selectList, fromClause, whereClause, groupByClause, havingClause,
orderByClause, paginationClause, unionAll, union);
}
}

/**
Expand Down Expand Up @@ -319,4 +348,20 @@ public void addPagination(int offset, int rowsPerPage) {
public OrderByClause getOrderByClause() {
return this.orderByClause;
}

/**
* Add a select to UNION with this query.
*/
public void addUnion(Select union) {
this.union = union;
this.unionAll = false;
}

/**
* Add a select to UNION ALL with this query.
*/
public void addUnionAll(Select unionAll) {
this.union = unionAll;
this.unionAll = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,26 @@ public void pagination(int offset, int rowsPerPage) {
select.addPagination(offset, rowsPerPage);
}

/**
* Add a select via UNION
*
* @param unionSelect the select to be UNION'd to this select statement
* @return
*/
public void union(Select unionSelect) {
select.addUnion(unionSelect);
}

/**
* Add a select via UNION ALL
*
* @param unionAllSelect the select to be UNION ALL'd to this select statement
* @return
*/
public void unionAll(Select unionAllSelect) {
select.addUnionAll(unionAllSelect);
}

/**
* Get the statement we've been constructing
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ public class SqlConstants {
public static final String THEN = "THEN";
public static final String END = "END";
public static final String ORDER_BY = "ORDER BY";
public static final String UNION = "UNION";
public static final String UNION_ALL = "UNION ALL";
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.ibm.fhir.database.utils.query.HavingClause;
import com.ibm.fhir.database.utils.query.OrderByClause;
import com.ibm.fhir.database.utils.query.PaginationClause;
import com.ibm.fhir.database.utils.query.Select;
import com.ibm.fhir.database.utils.query.SelectList;
import com.ibm.fhir.database.utils.query.WhereClause;
import com.ibm.fhir.database.utils.query.node.ExpNode;
Expand All @@ -36,10 +37,12 @@ public interface StatementRenderer<T> {
* @param havingClause
* @param orderByClause
* @param paginationClause
* @param unionAll
* @param union
* @return
*/
T select(boolean distinct, SelectList selectList, FromClause fromClause, WhereClause whereClause, GroupByClause groupByClause, HavingClause havingClause,
OrderByClause orderByClause, PaginationClause paginationClause);
OrderByClause orderByClause, PaginationClause paginationClause, boolean unionAll, Select union);

/**
* @param items
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import static com.ibm.fhir.database.utils.query.SqlConstants.FROM;
import static com.ibm.fhir.database.utils.query.SqlConstants.SELECT;
import static com.ibm.fhir.database.utils.query.SqlConstants.SPACE;
import static com.ibm.fhir.database.utils.query.SqlConstants.UNION;
import static com.ibm.fhir.database.utils.query.SqlConstants.UNION_ALL;
import static com.ibm.fhir.database.utils.query.SqlConstants.WHERE;

import java.util.List;
Expand All @@ -21,6 +23,7 @@
import com.ibm.fhir.database.utils.query.HavingClause;
import com.ibm.fhir.database.utils.query.OrderByClause;
import com.ibm.fhir.database.utils.query.PaginationClause;
import com.ibm.fhir.database.utils.query.Select;
import com.ibm.fhir.database.utils.query.SelectList;
import com.ibm.fhir.database.utils.query.WhereClause;
import com.ibm.fhir.database.utils.query.node.BindMarkerNode;
Expand Down Expand Up @@ -59,7 +62,7 @@ public StringStatementRenderer(IDatabaseTranslator translator, List<BindMarkerNo

@Override
public String select(boolean distinct, SelectList selectList, FromClause fromClause, WhereClause whereClause, GroupByClause groupByClause, HavingClause havingClause,
OrderByClause orderByClause, PaginationClause paginationClause) {
OrderByClause orderByClause, PaginationClause paginationClause, boolean unionAll, Select union) {

StringExpNodeVisitor whereClauseRenderer = new StringExpNodeVisitor(this.translator, this.collectBindMarkersInto, this.pretty);

Expand Down Expand Up @@ -115,6 +118,13 @@ public String select(boolean distinct, SelectList selectList, FromClause fromCla
result.append(SPACE).append(paginationClause.getSqlString(this.translator));
}

if (union != null) {
if (this.pretty) {
result.append(NEWLINE).append(" "); // 5 spaces
}
result.append(SPACE).append(unionAll ? UNION_ALL : UNION);
}

return result.toString();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.math.BigDecimal;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.testng.annotations.Test;
Expand Down Expand Up @@ -420,4 +421,47 @@ public void bindBigDecimal(BigDecimal value) {
};
bindMarker.visit(v);
}

/**
* Simple union all of select statements
*/
@Test
public void unionAllTest() {

List<String> resourceTypes = Arrays.asList("Patient", "Condition", "Observation");
Select first = null;
Select previous = null;

// Create a set of selects combined by UNION ALL
for (String resourceType : resourceTypes) {
// Create a simple select statement
Select select = Select.select("1")
.from(resourceType + "_TOKEN_VALUES_V", alias("param"))
.where("param", "PARAMETER_NAME_ID").eq(1274)
.build();

// Link to previous select via UNION ALL
if (previous != null) {
previous.addUnionAll(select);
} else {
first = select;
}
previous = select;
}

// And make sure it renders to the correct string
final String SQL = "SELECT 1"
+ " FROM Patient_TOKEN_VALUES_V AS param"
+ " WHERE param.PARAMETER_NAME_ID = 1274"
+ " UNION ALL"
+ " SELECT 1"
+ " FROM Condition_TOKEN_VALUES_V AS param"
+ " WHERE param.PARAMETER_NAME_ID = 1274"
+ " UNION ALL"
+ " SELECT 1"
+ " FROM Observation_TOKEN_VALUES_V AS param"
+ " WHERE param.PARAMETER_NAME_ID = 1274";
assertEquals(first.toString(), SQL);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ public class JDBCConstants {
public static final String IS_DELETED = "IS_DELETED";

// Special parameter names
public static final String PARAM_NAME_ID = "_id";
public static final String PARAM_NAME_LAST_UPDATED = "_lastUpdated";
public static final String PARAM_NAME_PROFILE = "_profile";
public static final String PARAM_NAME_TAG = "_tag";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package com.ibm.fhir.persistence.jdbc.dao.api;

import java.util.List;
import java.util.Set;

import com.ibm.fhir.persistence.exception.FHIRPersistenceException;

Expand All @@ -25,6 +26,15 @@ public interface JDBCIdentityCache {
*/
Integer getResourceTypeId(String resourceType) throws FHIRPersistenceException;

/**
* Get the resource type name for the resourceTypeId. Reads from a cache or database
* if required.
* @param resourceTypeId
* @return
* @throws FHIRPersistenceException
*/
String getResourceTypeName(Integer resourceTypeId) throws FHIRPersistenceException;

/**
* Get the database id for the named code-system. Creates new records if necessary
* @param codeSystem
Expand Down Expand Up @@ -69,4 +79,10 @@ public interface JDBCIdentityCache {
* @return
*/
List<Long> getCommonTokenValueIdList(String tokenValue);

/**
* Get the set of all resource type names.
* @return
*/
Set<String> getResourceTypeNames() throws FHIRPersistenceException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
package com.ibm.fhir.persistence.jdbc.dao.impl;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

Expand Down Expand Up @@ -70,6 +72,30 @@ public Integer getResourceTypeId(String resourceType) throws FHIRPersistenceExce
return result;
}

@Override
public String getResourceTypeName(Integer resourceTypeId) throws FHIRPersistenceException {
String result = cache.getResourceTypeNameCache().getName(resourceTypeId);
if (result == null) {
// try the database instead and cache the result
Map<String, Integer> resourceMap = resourceDAO.readAllResourceTypeNames();
for (Map.Entry<String, Integer> entry : resourceMap.entrySet()) {
if (entry.getValue() == resourceTypeId) {
result = entry.getKey();
break;
}
}

if (result == null) {
// likely a configuration error, caused by the schema being generated
// for a subset of all possible resource types
throw new FHIRPersistenceDataAccessException("Resource type ID not registered in database: '" + resourceTypeId + "'");
}

cache.getResourceTypeNameCache().addEntry(resourceTypeId, result);
}
return result;
}

@Override
public Integer getCodeSystemId(String codeSystemName) throws FHIRPersistenceException {
Integer result = cache.getResourceReferenceCache().getCodeSystemId(codeSystemName);
Expand Down Expand Up @@ -137,4 +163,9 @@ public Long getCommonTokenValueId(String codeSystem, String tokenValue) {
public List<Long> getCommonTokenValueIdList(String tokenValue) {
return resourceReferenceDAO.readCommonTokenValueIdList(tokenValue);
}

@Override
public Set<String> getResourceTypeNames() throws FHIRPersistenceException {
return resourceDAO.readAllResourceTypeNames().keySet();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ public DomainSortParameter(SortParameter sp) {
this.sortParameter = sp;
}

/**
* Get the sort parameter.
* @return sort parameter
*/
public SortParameter getSortParameter() {
return this.sortParameter;
}

/**
* Visitor to apply the sort parameter to the query builder represented by the visitor
* @param queryData
Expand Down
Loading

0 comments on commit 3b81116

Please sign in to comment.