cleanup
This commit is contained in:
parent
55f8e85d21
commit
40045fd3fe
|
@ -1574,7 +1574,6 @@ public class QueryStack {
|
||||||
if (wantChainedAndNormal) {
|
if (wantChainedAndNormal) {
|
||||||
|
|
||||||
if (theSourceJoinColumn == null) {
|
if (theSourceJoinColumn == null) {
|
||||||
// fixme mb HERE!!!
|
|
||||||
retVal = new InCondition(
|
retVal = new InCondition(
|
||||||
mySqlBuilder.getOrCreateFirstPredicateBuilder(false).getResourceIdColumn(), union);
|
mySqlBuilder.getOrCreateFirstPredicateBuilder(false).getResourceIdColumn(), union);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -26,7 +26,6 @@ import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||||
import ca.uhn.fhir.jpa.search.builder.sql.SearchQueryBuilder;
|
import ca.uhn.fhir.jpa.search.builder.sql.SearchQueryBuilder;
|
||||||
import ca.uhn.fhir.jpa.util.QueryParameterUtils;
|
import ca.uhn.fhir.jpa.util.QueryParameterUtils;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
|
||||||
import ca.uhn.fhir.rest.param.TokenParam;
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
import ca.uhn.fhir.rest.param.TokenParamModifier;
|
import ca.uhn.fhir.rest.param.TokenParamModifier;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
|
@ -136,7 +135,6 @@ public class ResourceIdPredicateBuilder extends BasePredicateBuilder {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DbColumn resIdColumn = getResourceIdColumn(theSourceJoinColumn);
|
DbColumn resIdColumn = getResourceIdColumn(theSourceJoinColumn);
|
||||||
// FIXME: find a test that lands here and make sure we have a Keep test doing the same
|
|
||||||
return QueryParameterUtils.toEqualToOrInPredicate(
|
return QueryParameterUtils.toEqualToOrInPredicate(
|
||||||
resIdColumn,
|
resIdColumn,
|
||||||
generatePlaceholders(resourceIds),
|
generatePlaceholders(resourceIds),
|
||||||
|
|
|
@ -182,7 +182,6 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder im
|
||||||
* one of these, use {@link #getJoinColumnsForSource()} or {@link #getJoinColumnsForTarget()}.
|
* one of these, use {@link #getJoinColumnsForSource()} or {@link #getJoinColumnsForTarget()}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
// fixme dig into this
|
|
||||||
public DbColumn[] getJoinColumns() {
|
public DbColumn[] getJoinColumns() {
|
||||||
return super.getJoinColumns();
|
return super.getJoinColumns();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
package ca.uhn.fhir.jpa.search.builder.sql;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
|
||||||
import com.healthmarketscience.common.util.AppendableExt;
|
|
||||||
import com.healthmarketscience.sqlbuilder.Expression;
|
|
||||||
import com.healthmarketscience.sqlbuilder.ValidationContext;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Outputs an SQL tuple for a collection of JpaPids, consisting of
|
|
||||||
* ((resId,partitionId),(resId,partitionId),(resId,partitionId),...)
|
|
||||||
*/
|
|
||||||
public class JpaPidValueTupleObject extends Expression {
|
|
||||||
|
|
||||||
private final Collection<String> myValues;
|
|
||||||
|
|
||||||
public JpaPidValueTupleObject(Collection<String> theValues) {
|
|
||||||
myValues = theValues;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void collectSchemaObjects(ValidationContext vContext) {
|
|
||||||
// nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void appendTo(AppendableExt app) throws IOException {
|
|
||||||
app.append('(');
|
|
||||||
|
|
||||||
String value;
|
|
||||||
for (Iterator<String> iter = myValues.iterator(); iter.hasNext(); ) {
|
|
||||||
if (hasParens()) {
|
|
||||||
// fixme do we want the quotes? I think these are numbers.
|
|
||||||
app.append("('");
|
|
||||||
}
|
|
||||||
value = iter.next();
|
|
||||||
app.append(value);
|
|
||||||
app.append("','");
|
|
||||||
value = iter.next();
|
|
||||||
app.append(value);
|
|
||||||
app.append("')");
|
|
||||||
if (iter.hasNext()) {
|
|
||||||
app.append(',');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hasParens()) {
|
|
||||||
app.append(')');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JpaPidValueTupleObject from(SearchQueryBuilder theSearchQueryBuilder, JpaPid[] thePids) {
|
|
||||||
List<String> placeholders = new ArrayList<>(thePids.length * 2);
|
|
||||||
for (JpaPid next : thePids) {
|
|
||||||
placeholders.add(theSearchQueryBuilder.generatePlaceholder(next.getPartitionId()));
|
|
||||||
placeholders.add(theSearchQueryBuilder.generatePlaceholder(next.getId()));
|
|
||||||
}
|
|
||||||
return new JpaPidValueTupleObject(placeholders);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -55,9 +55,8 @@ import com.healthmarketscience.sqlbuilder.FunctionCall;
|
||||||
import com.healthmarketscience.sqlbuilder.InCondition;
|
import com.healthmarketscience.sqlbuilder.InCondition;
|
||||||
import com.healthmarketscience.sqlbuilder.OrderObject;
|
import com.healthmarketscience.sqlbuilder.OrderObject;
|
||||||
import com.healthmarketscience.sqlbuilder.SelectQuery;
|
import com.healthmarketscience.sqlbuilder.SelectQuery;
|
||||||
import com.healthmarketscience.sqlbuilder.dbspec.Join;
|
import com.healthmarketscience.sqlbuilder.UnaryCondition;
|
||||||
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn;
|
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn;
|
||||||
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbJoin;
|
|
||||||
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbSchema;
|
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbSchema;
|
||||||
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbSpec;
|
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbSpec;
|
||||||
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbTable;
|
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbTable;
|
||||||
|
@ -75,6 +74,7 @@ import org.slf4j.LoggerFactory;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -484,8 +484,29 @@ public class SearchQueryBuilder {
|
||||||
DbColumn[] theToColumn,
|
DbColumn[] theToColumn,
|
||||||
SelectQuery.JoinType theJoinType) {
|
SelectQuery.JoinType theJoinType) {
|
||||||
assert theFromColumn.length == theToColumn.length;
|
assert theFromColumn.length == theToColumn.length;
|
||||||
Join join = new DbJoin(mySpec, theFromTable, theToTable, theFromColumn, theToColumn);
|
assert theFromColumn.length > 0;
|
||||||
mySelect.addJoins(theJoinType, join);
|
// create custom join condition, allowing nullable columns.
|
||||||
|
var onCondition = ComboCondition.and();
|
||||||
|
for (int i = 0; i < theFromColumn.length; ++i) {
|
||||||
|
boolean isNullable =
|
||||||
|
theFromColumn[i].getColumnNameSQL().toLowerCase(Locale.ROOT).contains("partition_id");
|
||||||
|
onCondition.addCondition(buildJoinColumnCondition(isNullable, theFromColumn[i], theToColumn[i]));
|
||||||
|
}
|
||||||
|
mySelect.addCustomJoin(theJoinType, theFromTable, theToTable, onCondition);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static @Nonnull Condition buildJoinColumnCondition(
|
||||||
|
boolean theColumnNullability, DbColumn theFromColumn, DbColumn theToColumn) {
|
||||||
|
var normalEqualCondition = BinaryCondition.equalTo(theFromColumn, theToColumn);
|
||||||
|
if (!theColumnNullability) {
|
||||||
|
return normalEqualCondition;
|
||||||
|
} else {
|
||||||
|
// the column can be null
|
||||||
|
// we must combine raw = with IS NULL checks.
|
||||||
|
var orBothNullCondition =
|
||||||
|
ComboCondition.and(UnaryCondition.isNull(theFromColumn), UnaryCondition.isNull(theToColumn));
|
||||||
|
return ComboCondition.or(normalEqualCondition, orBothNullCondition);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -678,7 +699,7 @@ public class SearchQueryBuilder {
|
||||||
* for its generated SQL. So we work around this by replacing our contents with a string in the SQL consisting
|
* for its generated SQL. So we work around this by replacing our contents with a string in the SQL consisting
|
||||||
* of <code>[random UUID]-[value index]</code> and then
|
* of <code>[random UUID]-[value index]</code> and then
|
||||||
*/
|
*/
|
||||||
public String generatePlaceholder(Object theValue) {
|
public String generatePlaceholder(Object theValue) {
|
||||||
String placeholder = myBindVariableSubstitutionBase + myBindVariableValues.size();
|
String placeholder = myBindVariableSubstitutionBase + myBindVariableValues.size();
|
||||||
myBindVariableValues.add(theValue);
|
myBindVariableValues.add(theValue);
|
||||||
return placeholder;
|
return placeholder;
|
||||||
|
|
|
@ -65,9 +65,7 @@ public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
|
||||||
myPatientDao.search(map);
|
myPatientDao.search(map);
|
||||||
assertEquals(1, myCaptureQueriesListener.countSelectQueries());
|
assertEquals(1, myCaptureQueriesListener.countSelectQueries());
|
||||||
String sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
|
String sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
|
||||||
assertEquals("SELECT t1.RES_ID FROM HFJ_RESOURCE t1 INNER JOIN HFJ_SPIDX_STRING t0 ON (t1.RES_ID = t0.RES_ID AND ((t1.PARTITION_ID = t0.PARTITION_ID) OR (t1.PARTITION_ID is null AND t0.PARTITION_ID is null))) INNER JOIN HFJ_SPIDX_TOKEN t2 ON (t1.RES_ID = t2.RES_ID AND ((t1.PARTITION_ID = t2.PARTITION_ID) OR (t1.PARTITION_ID is null AND t2.PARTITION_ID is null)) ) WHERE (((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?)) AND (t2.HASH_SYS_AND_VALUE = ?))", sql);
|
assertEquals("SELECT t1.RES_ID FROM HFJ_RESOURCE t1 INNER JOIN HFJ_SPIDX_STRING t0 ON (((t1.PARTITION_ID = t0.PARTITION_ID) OR ((t1.PARTITION_ID IS NULL) AND (t0.PARTITION_ID IS NULL))) AND (t1.RES_ID = t0.RES_ID)) INNER JOIN HFJ_SPIDX_TOKEN t2 ON (((t1.PARTITION_ID = t2.PARTITION_ID) OR ((t1.PARTITION_ID IS NULL) AND (t2.PARTITION_ID IS NULL))) AND (t1.RES_ID = t2.RES_ID)) WHERE (((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?)) AND (t2.HASH_SYS_AND_VALUE = ?))", sql);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -88,7 +86,7 @@ public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
|
||||||
assertEquals(3, myCaptureQueriesListener.countSelectQueries());
|
assertEquals(3, myCaptureQueriesListener.countSelectQueries());
|
||||||
// Query 1 - Find resources: Make sure we search for tag type+system+code always
|
// Query 1 - Find resources: Make sure we search for tag type+system+code always
|
||||||
String sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
|
String sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
|
||||||
assertEquals("SELECT t0.RES_ID FROM HFJ_RESOURCE t0 INNER JOIN HFJ_RES_TAG t1 ON (t0.RES_ID = t1.RES_ID) INNER JOIN HFJ_TAG_DEF t2 ON (t1.TAG_ID = t2.TAG_ID) WHERE (((t0.RES_TYPE = ?) AND (t0.RES_DELETED_AT IS NULL)) AND ((t2.TAG_TYPE = ?) AND (t2.TAG_SYSTEM = ?) AND (t2.TAG_CODE = ?)))", sql);
|
assertEquals("SELECT t0.RES_ID FROM HFJ_RESOURCE t0 INNER JOIN HFJ_RES_TAG t1 ON (((t0.PARTITION_ID = t1.PARTITION_ID) OR ((t0.PARTITION_ID IS NULL) AND (t1.PARTITION_ID IS NULL))) AND (t0.RES_ID = t1.RES_ID)) INNER JOIN HFJ_TAG_DEF t2 ON (t1.TAG_ID = t2.TAG_ID) WHERE (((t0.RES_TYPE = ?) AND (t0.RES_DELETED_AT IS NULL)) AND ((t2.TAG_TYPE = ?) AND (t2.TAG_SYSTEM = ?) AND (t2.TAG_CODE = ?)))", sql);
|
||||||
// Query 2 - Load resourece contents
|
// Query 2 - Load resourece contents
|
||||||
sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(1).getSql(false, false);
|
sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(1).getSql(false, false);
|
||||||
assertThat(sql).contains("where rsv1_0.RES_ID in (?)");
|
assertThat(sql).contains("where rsv1_0.RES_ID in (?)");
|
||||||
|
|
Loading…
Reference in New Issue