Compare commits
16 Commits
b1ef24a43a
...
c955bc8ac9
Author | SHA1 | Date |
---|---|---|
Michael Buckley | c955bc8ac9 | |
Michael Buckley | d05079da22 | |
Michael Buckley | 4df01b1945 | |
Michael Buckley | afa1c2f0b6 | |
Michael Buckley | dad7094362 | |
Michael Buckley | 8e5784f934 | |
Michael Buckley | 75b894e9b4 | |
Michael Buckley | 93d520a422 | |
Michael Buckley | e7fed79e5c | |
Michael Buckley | 8ecc7728c7 | |
Michael Buckley | 40a2a7ceb7 | |
Michael Buckley | 75f7defc74 | |
Michael Buckley | 785f218382 | |
Michael Buckley | 4e240a8087 | |
Michael Buckley | 40045fd3fe | |
Michael Buckley | 55f8e85d21 |
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
issue: 6325
|
||||||
|
title: "Add support for including the partitioning column in search query joins."
|
|
@ -55,6 +55,7 @@ import ca.uhn.fhir.jpa.search.builder.predicate.StringPredicateBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.TagPredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.TagPredicateBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.TokenPredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.TokenPredicateBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.UriPredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.UriPredicateBuilder;
|
||||||
|
import ca.uhn.fhir.jpa.search.builder.sql.ColumnTupleObject;
|
||||||
import ca.uhn.fhir.jpa.search.builder.sql.PredicateBuilderFactory;
|
import ca.uhn.fhir.jpa.search.builder.sql.PredicateBuilderFactory;
|
||||||
import ca.uhn.fhir.jpa.search.builder.sql.SearchQueryBuilder;
|
import ca.uhn.fhir.jpa.search.builder.sql.SearchQueryBuilder;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
|
@ -123,6 +124,7 @@ import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static ca.uhn.fhir.jpa.search.builder.QueryStack.SearchForIdsParams.with;
|
import static ca.uhn.fhir.jpa.search.builder.QueryStack.SearchForIdsParams.with;
|
||||||
|
import static ca.uhn.fhir.jpa.search.builder.predicate.ResourceIdPredicateBuilder.getResourceIdColumn;
|
||||||
import static ca.uhn.fhir.jpa.util.QueryParameterUtils.fromOperation;
|
import static ca.uhn.fhir.jpa.util.QueryParameterUtils.fromOperation;
|
||||||
import static ca.uhn.fhir.jpa.util.QueryParameterUtils.getChainedPart;
|
import static ca.uhn.fhir.jpa.util.QueryParameterUtils.getChainedPart;
|
||||||
import static ca.uhn.fhir.jpa.util.QueryParameterUtils.getParamNameWithPrefix;
|
import static ca.uhn.fhir.jpa.util.QueryParameterUtils.getParamNameWithPrefix;
|
||||||
|
@ -245,7 +247,7 @@ public class QueryStack {
|
||||||
resourceTablePredicateBuilder = (ResourceTablePredicateBuilder) firstPredicateBuilder;
|
resourceTablePredicateBuilder = (ResourceTablePredicateBuilder) firstPredicateBuilder;
|
||||||
} else {
|
} else {
|
||||||
resourceTablePredicateBuilder =
|
resourceTablePredicateBuilder =
|
||||||
mySqlBuilder.addResourceTablePredicateBuilder(firstPredicateBuilder.getResourceIdColumn());
|
mySqlBuilder.addResourceTablePredicateBuilder(firstPredicateBuilder.getJoinColumns());
|
||||||
}
|
}
|
||||||
mySqlBuilder.addSortDate(resourceTablePredicateBuilder.getColumnLastUpdated(), theAscending, myUseAggregate);
|
mySqlBuilder.addSortDate(resourceTablePredicateBuilder.getColumnLastUpdated(), theAscending, myUseAggregate);
|
||||||
}
|
}
|
||||||
|
@ -282,7 +284,7 @@ public class QueryStack {
|
||||||
resourceTablePredicateBuilder = (ResourceTablePredicateBuilder) firstPredicateBuilder;
|
resourceTablePredicateBuilder = (ResourceTablePredicateBuilder) firstPredicateBuilder;
|
||||||
} else {
|
} else {
|
||||||
resourceTablePredicateBuilder =
|
resourceTablePredicateBuilder =
|
||||||
mySqlBuilder.addResourceTablePredicateBuilder(firstPredicateBuilder.getResourceIdColumn());
|
mySqlBuilder.addResourceTablePredicateBuilder(firstPredicateBuilder.getJoinColumns());
|
||||||
}
|
}
|
||||||
mySqlBuilder.addSortString(resourceTablePredicateBuilder.getColumnFhirId(), theAscending, myUseAggregate);
|
mySqlBuilder.addSortString(resourceTablePredicateBuilder.getColumnFhirId(), theAscending, myUseAggregate);
|
||||||
}
|
}
|
||||||
|
@ -358,7 +360,7 @@ public class QueryStack {
|
||||||
case STRING:
|
case STRING:
|
||||||
StringPredicateBuilder stringPredicateBuilder = mySqlBuilder.createStringPredicateBuilder();
|
StringPredicateBuilder stringPredicateBuilder = mySqlBuilder.createStringPredicateBuilder();
|
||||||
addSortCustomJoin(
|
addSortCustomJoin(
|
||||||
resourceLinkPredicateBuilder.getColumnTargetResourceId(),
|
resourceLinkPredicateBuilder.getJoinColumnsForTarget(),
|
||||||
stringPredicateBuilder,
|
stringPredicateBuilder,
|
||||||
stringPredicateBuilder.createHashIdentityPredicate(targetType, theChain));
|
stringPredicateBuilder.createHashIdentityPredicate(targetType, theChain));
|
||||||
|
|
||||||
|
@ -369,7 +371,7 @@ public class QueryStack {
|
||||||
case TOKEN:
|
case TOKEN:
|
||||||
TokenPredicateBuilder tokenPredicateBuilder = mySqlBuilder.createTokenPredicateBuilder();
|
TokenPredicateBuilder tokenPredicateBuilder = mySqlBuilder.createTokenPredicateBuilder();
|
||||||
addSortCustomJoin(
|
addSortCustomJoin(
|
||||||
resourceLinkPredicateBuilder.getColumnTargetResourceId(),
|
resourceLinkPredicateBuilder.getJoinColumnsForTarget(),
|
||||||
tokenPredicateBuilder,
|
tokenPredicateBuilder,
|
||||||
tokenPredicateBuilder.createHashIdentityPredicate(targetType, theChain));
|
tokenPredicateBuilder.createHashIdentityPredicate(targetType, theChain));
|
||||||
|
|
||||||
|
@ -380,7 +382,7 @@ public class QueryStack {
|
||||||
case DATE:
|
case DATE:
|
||||||
DatePredicateBuilder datePredicateBuilder = mySqlBuilder.createDatePredicateBuilder();
|
DatePredicateBuilder datePredicateBuilder = mySqlBuilder.createDatePredicateBuilder();
|
||||||
addSortCustomJoin(
|
addSortCustomJoin(
|
||||||
resourceLinkPredicateBuilder.getColumnTargetResourceId(),
|
resourceLinkPredicateBuilder.getJoinColumnsForTarget(),
|
||||||
datePredicateBuilder,
|
datePredicateBuilder,
|
||||||
datePredicateBuilder.createHashIdentityPredicate(targetType, theChain));
|
datePredicateBuilder.createHashIdentityPredicate(targetType, theChain));
|
||||||
|
|
||||||
|
@ -405,7 +407,7 @@ public class QueryStack {
|
||||||
double latitudeValue = location.getLatitudeValue();
|
double latitudeValue = location.getLatitudeValue();
|
||||||
double longitudeValue = location.getLongitudeValue();
|
double longitudeValue = location.getLongitudeValue();
|
||||||
final CoordsPredicateBuilder coordsPredicateBuilder = mySqlBuilder.addCoordsPredicateBuilder(
|
final CoordsPredicateBuilder coordsPredicateBuilder = mySqlBuilder.addCoordsPredicateBuilder(
|
||||||
resourceLinkPredicateBuilder.getColumnTargetResourceId());
|
resourceLinkPredicateBuilder.getJoinColumnsForTarget());
|
||||||
mySqlBuilder.addSortCoordsNear(
|
mySqlBuilder.addSortCoordsNear(
|
||||||
coordsPredicateBuilder, latitudeValue, longitudeValue, theAscending);
|
coordsPredicateBuilder, latitudeValue, longitudeValue, theAscending);
|
||||||
} else {
|
} else {
|
||||||
|
@ -418,6 +420,7 @@ public class QueryStack {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//noinspection fallthrough
|
||||||
case NUMBER:
|
case NUMBER:
|
||||||
case REFERENCE:
|
case REFERENCE:
|
||||||
case COMPOSITE:
|
case COMPOSITE:
|
||||||
|
@ -473,16 +476,16 @@ public class QueryStack {
|
||||||
BaseJoiningPredicateBuilder theFromJoiningPredicateBuilder,
|
BaseJoiningPredicateBuilder theFromJoiningPredicateBuilder,
|
||||||
BaseJoiningPredicateBuilder theToJoiningPredicateBuilder,
|
BaseJoiningPredicateBuilder theToJoiningPredicateBuilder,
|
||||||
Condition theCondition) {
|
Condition theCondition) {
|
||||||
addSortCustomJoin(
|
addSortCustomJoin(theFromJoiningPredicateBuilder.getJoinColumns(), theToJoiningPredicateBuilder, theCondition);
|
||||||
theFromJoiningPredicateBuilder.getResourceIdColumn(), theToJoiningPredicateBuilder, theCondition);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addSortCustomJoin(
|
private void addSortCustomJoin(
|
||||||
DbColumn theFromDbColumn,
|
DbColumn theFromDbColumn[],
|
||||||
BaseJoiningPredicateBuilder theToJoiningPredicateBuilder,
|
BaseJoiningPredicateBuilder theToJoiningPredicateBuilder,
|
||||||
Condition theCondition) {
|
Condition theCondition) {
|
||||||
|
|
||||||
ComboCondition onCondition =
|
ComboCondition onCondition =
|
||||||
mySqlBuilder.createOnCondition(theFromDbColumn, theToJoiningPredicateBuilder.getResourceIdColumn());
|
mySqlBuilder.createOnCondition(theFromDbColumn, theToJoiningPredicateBuilder.getJoinColumns());
|
||||||
|
|
||||||
if (theCondition != null) {
|
if (theCondition != null) {
|
||||||
onCondition.addCondition(theCondition);
|
onCondition.addCondition(theCondition);
|
||||||
|
@ -490,7 +493,7 @@ public class QueryStack {
|
||||||
|
|
||||||
mySqlBuilder.addCustomJoin(
|
mySqlBuilder.addCustomJoin(
|
||||||
SelectQuery.JoinType.LEFT_OUTER,
|
SelectQuery.JoinType.LEFT_OUTER,
|
||||||
theFromDbColumn.getTable(),
|
theFromDbColumn[0].getTable(),
|
||||||
theToJoiningPredicateBuilder.getTable(),
|
theToJoiningPredicateBuilder.getTable(),
|
||||||
onCondition);
|
onCondition);
|
||||||
}
|
}
|
||||||
|
@ -502,7 +505,7 @@ public class QueryStack {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private <T extends BaseJoiningPredicateBuilder> PredicateBuilderCacheLookupResult<T> createOrReusePredicateBuilder(
|
private <T extends BaseJoiningPredicateBuilder> PredicateBuilderCacheLookupResult<T> createOrReusePredicateBuilder(
|
||||||
PredicateBuilderTypeEnum theType,
|
PredicateBuilderTypeEnum theType,
|
||||||
DbColumn theSourceJoinColumn,
|
DbColumn[] theSourceJoinColumn,
|
||||||
String theParamName,
|
String theParamName,
|
||||||
Supplier<T> theFactoryMethod) {
|
Supplier<T> theFactoryMethod) {
|
||||||
boolean cacheHit = false;
|
boolean cacheHit = false;
|
||||||
|
@ -534,7 +537,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Condition createPredicateComposite(
|
private Condition createPredicateComposite(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theSpnamePrefix,
|
String theSpnamePrefix,
|
||||||
RuntimeSearchParam theParamDef,
|
RuntimeSearchParam theParamDef,
|
||||||
|
@ -551,7 +554,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Condition createPredicateComposite(
|
private Condition createPredicateComposite(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theSpnamePrefix,
|
String theSpnamePrefix,
|
||||||
RuntimeSearchParam theParamDef,
|
RuntimeSearchParam theParamDef,
|
||||||
|
@ -605,7 +608,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Condition createPredicateCompositePart(
|
private Condition createPredicateCompositePart(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theSpnamePrefix,
|
String theSpnamePrefix,
|
||||||
RuntimeSearchParam theParam,
|
RuntimeSearchParam theParam,
|
||||||
|
@ -813,7 +816,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Condition createPredicateCoords(
|
public Condition createPredicateCoords(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theSpnamePrefix,
|
String theSpnamePrefix,
|
||||||
RuntimeSearchParam theSearchParam,
|
RuntimeSearchParam theSearchParam,
|
||||||
|
@ -858,7 +861,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Condition createPredicateDate(
|
public Condition createPredicateDate(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theSpnamePrefix,
|
String theSpnamePrefix,
|
||||||
RuntimeSearchParam theSearchParam,
|
RuntimeSearchParam theSearchParam,
|
||||||
|
@ -877,7 +880,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Condition createPredicateDate(
|
public Condition createPredicateDate(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theSpnamePrefix,
|
String theSpnamePrefix,
|
||||||
RuntimeSearchParam theSearchParam,
|
RuntimeSearchParam theSearchParam,
|
||||||
|
@ -1105,7 +1108,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Condition createPredicateHas(
|
private Condition createPredicateHas(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceType,
|
String theResourceType,
|
||||||
List<List<IQueryParameterType>> theHasParameters,
|
List<List<IQueryParameterType>> theHasParameters,
|
||||||
RequestDetails theRequest,
|
RequestDetails theRequest,
|
||||||
|
@ -1225,7 +1228,7 @@ public class QueryStack {
|
||||||
resourceLinkTableJoin.getColumnSourcePath(), mySqlBuilder.generatePlaceholders(paths));
|
resourceLinkTableJoin.getColumnSourcePath(), mySqlBuilder.generatePlaceholders(paths));
|
||||||
|
|
||||||
Condition linkedPredicate =
|
Condition linkedPredicate =
|
||||||
searchForIdsWithAndOr(with().setSourceJoinColumn(resourceLinkTableJoin.getColumnSrcResourceId())
|
searchForIdsWithAndOr(with().setSourceJoinColumn(resourceLinkTableJoin.getJoinColumnsForSource())
|
||||||
.setResourceName(targetResourceType)
|
.setResourceName(targetResourceType)
|
||||||
.setParamName(parameterName)
|
.setParamName(parameterName)
|
||||||
.setAndOrParams(Collections.singletonList(orValues))
|
.setAndOrParams(Collections.singletonList(orValues))
|
||||||
|
@ -1239,7 +1242,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Condition createPredicateNumber(
|
public Condition createPredicateNumber(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theSpnamePrefix,
|
String theSpnamePrefix,
|
||||||
RuntimeSearchParam theSearchParam,
|
RuntimeSearchParam theSearchParam,
|
||||||
|
@ -1258,7 +1261,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Condition createPredicateNumber(
|
public Condition createPredicateNumber(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theSpnamePrefix,
|
String theSpnamePrefix,
|
||||||
RuntimeSearchParam theSearchParam,
|
RuntimeSearchParam theSearchParam,
|
||||||
|
@ -1318,7 +1321,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Condition createPredicateQuantity(
|
public Condition createPredicateQuantity(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theSpnamePrefix,
|
String theSpnamePrefix,
|
||||||
RuntimeSearchParam theSearchParam,
|
RuntimeSearchParam theSearchParam,
|
||||||
|
@ -1337,7 +1340,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Condition createPredicateQuantity(
|
public Condition createPredicateQuantity(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theSpnamePrefix,
|
String theSpnamePrefix,
|
||||||
RuntimeSearchParam theSearchParam,
|
RuntimeSearchParam theSearchParam,
|
||||||
|
@ -1405,7 +1408,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Condition createPredicateReference(
|
public Condition createPredicateReference(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theParamName,
|
String theParamName,
|
||||||
List<String> theQualifiers,
|
List<String> theQualifiers,
|
||||||
|
@ -1426,7 +1429,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Condition createPredicateReference(
|
public Condition createPredicateReference(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theParamName,
|
String theParamName,
|
||||||
List<String> theQualifiers,
|
List<String> theQualifiers,
|
||||||
|
@ -1474,16 +1477,16 @@ public class QueryStack {
|
||||||
|
|
||||||
public void addGrouping() {
|
public void addGrouping() {
|
||||||
BaseJoiningPredicateBuilder firstPredicateBuilder = mySqlBuilder.getOrCreateFirstPredicateBuilder();
|
BaseJoiningPredicateBuilder firstPredicateBuilder = mySqlBuilder.getOrCreateFirstPredicateBuilder();
|
||||||
mySqlBuilder.getSelect().addGroupings(firstPredicateBuilder.getResourceIdColumn());
|
mySqlBuilder.getSelect().addGroupings(firstPredicateBuilder.getJoinColumns());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addOrdering() {
|
public void addOrdering() {
|
||||||
BaseJoiningPredicateBuilder firstPredicateBuilder = mySqlBuilder.getOrCreateFirstPredicateBuilder();
|
BaseJoiningPredicateBuilder firstPredicateBuilder = mySqlBuilder.getOrCreateFirstPredicateBuilder();
|
||||||
mySqlBuilder.getSelect().addOrderings(firstPredicateBuilder.getResourceIdColumn());
|
mySqlBuilder.getSelect().addOrderings(firstPredicateBuilder.getJoinColumns());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Condition createPredicateReferenceForEmbeddedChainedSearchResource(
|
public Condition createPredicateReferenceForEmbeddedChainedSearchResource(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
RuntimeSearchParam theSearchParam,
|
RuntimeSearchParam theSearchParam,
|
||||||
List<? extends IQueryParameterType> theList,
|
List<? extends IQueryParameterType> theList,
|
||||||
|
@ -1527,12 +1530,12 @@ public class QueryStack {
|
||||||
for (LeafNodeDefinition leafNodeDefinition : referenceLinks.get(nextReferenceLink)) {
|
for (LeafNodeDefinition leafNodeDefinition : referenceLinks.get(nextReferenceLink)) {
|
||||||
SearchQueryBuilder builder;
|
SearchQueryBuilder builder;
|
||||||
if (wantChainedAndNormal) {
|
if (wantChainedAndNormal) {
|
||||||
builder = mySqlBuilder.newChildSqlBuilder();
|
builder = mySqlBuilder.newChildSqlBuilder(mySqlBuilder.isIncludePartitionIdInJoins());
|
||||||
} else {
|
} else {
|
||||||
builder = mySqlBuilder;
|
builder = mySqlBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
DbColumn previousJoinColumn = null;
|
DbColumn[] previousJoinColumn = null;
|
||||||
|
|
||||||
// Create a reference link predicates to the subselect for every link but the last one
|
// Create a reference link predicates to the subselect for every link but the last one
|
||||||
for (String nextLink : nextReferenceLink) {
|
for (String nextLink : nextReferenceLink) {
|
||||||
|
@ -1543,7 +1546,7 @@ public class QueryStack {
|
||||||
builder.addReferencePredicateBuilder(this, previousJoinColumn);
|
builder.addReferencePredicateBuilder(this, previousJoinColumn);
|
||||||
builder.addPredicate(
|
builder.addPredicate(
|
||||||
resourceLinkPredicateBuilder.createPredicateSourcePaths(Lists.newArrayList(nextLink)));
|
resourceLinkPredicateBuilder.createPredicateSourcePaths(Lists.newArrayList(nextLink)));
|
||||||
previousJoinColumn = resourceLinkPredicateBuilder.getColumnTargetResourceId();
|
previousJoinColumn = resourceLinkPredicateBuilder.getJoinColumnsForTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
Condition containedCondition = createIndexPredicate(
|
Condition containedCondition = createIndexPredicate(
|
||||||
|
@ -1572,8 +1575,15 @@ public class QueryStack {
|
||||||
if (wantChainedAndNormal) {
|
if (wantChainedAndNormal) {
|
||||||
|
|
||||||
if (theSourceJoinColumn == null) {
|
if (theSourceJoinColumn == null) {
|
||||||
retVal = new InCondition(
|
BaseJoiningPredicateBuilder root = mySqlBuilder.getOrCreateFirstPredicateBuilder(false);
|
||||||
mySqlBuilder.getOrCreateFirstPredicateBuilder(false).getResourceIdColumn(), union);
|
DbColumn[] joinColumns = root.getJoinColumns();
|
||||||
|
Object joinColumnObject;
|
||||||
|
if (joinColumns.length == 1) {
|
||||||
|
joinColumnObject = joinColumns[0];
|
||||||
|
} else {
|
||||||
|
joinColumnObject = ColumnTupleObject.from(joinColumns);
|
||||||
|
}
|
||||||
|
retVal = new InCondition(joinColumnObject, union);
|
||||||
} else {
|
} else {
|
||||||
// -- for the resource link, need join with target_resource_id
|
// -- for the resource link, need join with target_resource_id
|
||||||
retVal = new InCondition(theSourceJoinColumn, union);
|
retVal = new InCondition(theSourceJoinColumn, union);
|
||||||
|
@ -1769,7 +1779,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Condition createIndexPredicate(
|
private Condition createIndexPredicate(
|
||||||
DbColumn theSourceJoinColumn,
|
DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theSpnamePrefix,
|
String theSpnamePrefix,
|
||||||
String theParamName,
|
String theParamName,
|
||||||
|
@ -1883,7 +1893,7 @@ public class QueryStack {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Condition createPredicateResourceId(
|
public Condition createPredicateResourceId(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
List<List<IQueryParameterType>> theValues,
|
List<List<IQueryParameterType>> theValues,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
SearchFilterParser.CompareOperation theOperation,
|
SearchFilterParser.CompareOperation theOperation,
|
||||||
|
@ -1894,7 +1904,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Condition createPredicateSourceForAndList(
|
private Condition createPredicateSourceForAndList(
|
||||||
@Nullable DbColumn theSourceJoinColumn, List<List<IQueryParameterType>> theAndOrParams) {
|
@Nullable DbColumn[] theSourceJoinColumn, List<List<IQueryParameterType>> theAndOrParams) {
|
||||||
mySqlBuilder.getOrCreateFirstPredicateBuilder();
|
mySqlBuilder.getOrCreateFirstPredicateBuilder();
|
||||||
|
|
||||||
List<Condition> andPredicates = new ArrayList<>(theAndOrParams.size());
|
List<Condition> andPredicates = new ArrayList<>(theAndOrParams.size());
|
||||||
|
@ -1905,7 +1915,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Condition createPredicateSource(
|
private Condition createPredicateSource(
|
||||||
@Nullable DbColumn theSourceJoinColumn, List<? extends IQueryParameterType> theList) {
|
@Nullable DbColumn[] theSourceJoinColumn, List<? extends IQueryParameterType> theList) {
|
||||||
if (myStorageSettings.getStoreMetaSourceInformation()
|
if (myStorageSettings.getStoreMetaSourceInformation()
|
||||||
== JpaStorageSettings.StoreMetaSourceInformationEnum.NONE) {
|
== JpaStorageSettings.StoreMetaSourceInformationEnum.NONE) {
|
||||||
String msg = myFhirContext.getLocalizer().getMessage(QueryStack.class, "sourceParamDisabled");
|
String msg = myFhirContext.getLocalizer().getMessage(QueryStack.class, "sourceParamDisabled");
|
||||||
|
@ -1948,7 +1958,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
private SourcePredicateBuilder getSourcePredicateBuilder(
|
private SourcePredicateBuilder getSourcePredicateBuilder(
|
||||||
@Nullable DbColumn theSourceJoinColumn, SelectQuery.JoinType theJoinType) {
|
@Nullable DbColumn[] theSourceJoinColumn, SelectQuery.JoinType theJoinType) {
|
||||||
return createOrReusePredicateBuilder(
|
return createOrReusePredicateBuilder(
|
||||||
PredicateBuilderTypeEnum.SOURCE,
|
PredicateBuilderTypeEnum.SOURCE,
|
||||||
theSourceJoinColumn,
|
theSourceJoinColumn,
|
||||||
|
@ -1958,7 +1968,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Condition createPredicateString(
|
public Condition createPredicateString(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theSpnamePrefix,
|
String theSpnamePrefix,
|
||||||
RuntimeSearchParam theSearchParam,
|
RuntimeSearchParam theSearchParam,
|
||||||
|
@ -1977,7 +1987,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Condition createPredicateString(
|
public Condition createPredicateString(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theSpnamePrefix,
|
String theSpnamePrefix,
|
||||||
RuntimeSearchParam theSearchParam,
|
RuntimeSearchParam theSearchParam,
|
||||||
|
@ -2017,7 +2027,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Condition createPredicateTag(
|
public Condition createPredicateTag(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
List<List<IQueryParameterType>> theList,
|
List<List<IQueryParameterType>> theList,
|
||||||
String theParamName,
|
String theParamName,
|
||||||
RequestPartitionId theRequestPartitionId) {
|
RequestPartitionId theRequestPartitionId) {
|
||||||
|
@ -2048,7 +2058,8 @@ public class QueryStack {
|
||||||
BaseJoiningPredicateBuilder join;
|
BaseJoiningPredicateBuilder join;
|
||||||
if (paramInverted) {
|
if (paramInverted) {
|
||||||
|
|
||||||
SearchQueryBuilder sqlBuilder = mySqlBuilder.newChildSqlBuilder();
|
boolean selectPartitionId = myPartitionSettings.isPartitionIdsInPrimaryKeys();
|
||||||
|
SearchQueryBuilder sqlBuilder = mySqlBuilder.newChildSqlBuilder(selectPartitionId);
|
||||||
TagPredicateBuilder tagSelector = sqlBuilder.addTagPredicateBuilder(null);
|
TagPredicateBuilder tagSelector = sqlBuilder.addTagPredicateBuilder(null);
|
||||||
sqlBuilder.addPredicate(
|
sqlBuilder.addPredicate(
|
||||||
tagSelector.createPredicateTag(tagType, tokens, theParamName, theRequestPartitionId));
|
tagSelector.createPredicateTag(tagType, tokens, theParamName, theRequestPartitionId));
|
||||||
|
@ -2056,7 +2067,14 @@ public class QueryStack {
|
||||||
|
|
||||||
join = mySqlBuilder.getOrCreateFirstPredicateBuilder();
|
join = mySqlBuilder.getOrCreateFirstPredicateBuilder();
|
||||||
Expression subSelect = new Subquery(sql);
|
Expression subSelect = new Subquery(sql);
|
||||||
tagPredicate = new InCondition(join.getResourceIdColumn(), subSelect).setNegate(true);
|
|
||||||
|
Object left;
|
||||||
|
if (selectPartitionId) {
|
||||||
|
left = new ColumnTupleObject(join.getJoinColumns());
|
||||||
|
} else {
|
||||||
|
left = join.getResourceIdColumn();
|
||||||
|
}
|
||||||
|
tagPredicate = new InCondition(left, subSelect).setNegate(true);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Tag table can't be a query root because it will include deleted resources, and can't select by
|
// Tag table can't be a query root because it will include deleted resources, and can't select by
|
||||||
|
@ -2129,7 +2147,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Condition createPredicateToken(
|
public Condition createPredicateToken(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theSpnamePrefix,
|
String theSpnamePrefix,
|
||||||
RuntimeSearchParam theSearchParam,
|
RuntimeSearchParam theSearchParam,
|
||||||
|
@ -2148,7 +2166,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Condition createPredicateToken(
|
public Condition createPredicateToken(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theSpnamePrefix,
|
String theSpnamePrefix,
|
||||||
RuntimeSearchParam theSearchParam,
|
RuntimeSearchParam theSearchParam,
|
||||||
|
@ -2219,7 +2237,8 @@ public class QueryStack {
|
||||||
BaseJoiningPredicateBuilder join;
|
BaseJoiningPredicateBuilder join;
|
||||||
|
|
||||||
if (paramInverted) {
|
if (paramInverted) {
|
||||||
SearchQueryBuilder sqlBuilder = theSqlBuilder.newChildSqlBuilder();
|
boolean selectPartitionId = myPartitionSettings.isPartitionIdsInPrimaryKeys();
|
||||||
|
SearchQueryBuilder sqlBuilder = theSqlBuilder.newChildSqlBuilder(selectPartitionId);
|
||||||
TokenPredicateBuilder tokenSelector = sqlBuilder.addTokenPredicateBuilder(null);
|
TokenPredicateBuilder tokenSelector = sqlBuilder.addTokenPredicateBuilder(null);
|
||||||
sqlBuilder.addPredicate(tokenSelector.createPredicateToken(
|
sqlBuilder.addPredicate(tokenSelector.createPredicateToken(
|
||||||
tokens, theResourceName, theSpnamePrefix, theSearchParam, theRequestPartitionId));
|
tokens, theResourceName, theSpnamePrefix, theSearchParam, theRequestPartitionId));
|
||||||
|
@ -2228,13 +2247,16 @@ public class QueryStack {
|
||||||
|
|
||||||
join = theSqlBuilder.getOrCreateFirstPredicateBuilder();
|
join = theSqlBuilder.getOrCreateFirstPredicateBuilder();
|
||||||
|
|
||||||
|
DbColumn[] leftColumns;
|
||||||
if (theSourceJoinColumn == null) {
|
if (theSourceJoinColumn == null) {
|
||||||
predicate = new InCondition(join.getResourceIdColumn(), subSelect).setNegate(true);
|
leftColumns = join.getJoinColumns();
|
||||||
} else {
|
} else {
|
||||||
// -- for the resource link, need join with target_resource_id
|
leftColumns = theSourceJoinColumn;
|
||||||
predicate = new InCondition(theSourceJoinColumn, subSelect).setNegate(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Object left = new ColumnTupleObject(leftColumns);
|
||||||
|
predicate = new InCondition(left, subSelect).setNegate(true);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Boolean isMissing = theList.get(0).getMissing();
|
Boolean isMissing = theList.get(0).getMissing();
|
||||||
if (isMissing != null) {
|
if (isMissing != null) {
|
||||||
|
@ -2264,7 +2286,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Condition createPredicateUri(
|
public Condition createPredicateUri(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theSpnamePrefix,
|
String theSpnamePrefix,
|
||||||
RuntimeSearchParam theSearchParam,
|
RuntimeSearchParam theSearchParam,
|
||||||
|
@ -2285,7 +2307,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Condition createPredicateUri(
|
public Condition createPredicateUri(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theSpnamePrefix,
|
String theSpnamePrefix,
|
||||||
RuntimeSearchParam theSearchParam,
|
RuntimeSearchParam theSearchParam,
|
||||||
|
@ -2400,9 +2422,9 @@ public class QueryStack {
|
||||||
* Raw match on RES_ID
|
* Raw match on RES_ID
|
||||||
*/
|
*/
|
||||||
private Condition createPredicateResourcePID(
|
private Condition createPredicateResourcePID(
|
||||||
DbColumn theSourceJoinColumn, List<List<IQueryParameterType>> theAndOrParams) {
|
DbColumn[] theSourceJoinColumn, List<List<IQueryParameterType>> theAndOrParams) {
|
||||||
|
|
||||||
DbColumn pidColumn = theSourceJoinColumn;
|
DbColumn pidColumn = getResourceIdColumn(theSourceJoinColumn);
|
||||||
|
|
||||||
if (pidColumn == null) {
|
if (pidColumn == null) {
|
||||||
BaseJoiningPredicateBuilder predicateBuilder = mySqlBuilder.getOrCreateFirstPredicateBuilder();
|
BaseJoiningPredicateBuilder predicateBuilder = mySqlBuilder.getOrCreateFirstPredicateBuilder();
|
||||||
|
@ -2427,7 +2449,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Condition createReverseSearchPredicateLastUpdated(
|
private Condition createReverseSearchPredicateLastUpdated(
|
||||||
List<List<IQueryParameterType>> theAndOrParams, DbColumn theSourceColumn) {
|
List<List<IQueryParameterType>> theAndOrParams, DbColumn[] theSourceColumn) {
|
||||||
|
|
||||||
ResourceTablePredicateBuilder resourceTableJoin =
|
ResourceTablePredicateBuilder resourceTableJoin =
|
||||||
mySqlBuilder.addResourceTablePredicateBuilder(theSourceColumn);
|
mySqlBuilder.addResourceTablePredicateBuilder(theSourceColumn);
|
||||||
|
@ -2448,7 +2470,7 @@ public class QueryStack {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Condition createPredicateSearchParameter(
|
private Condition createPredicateSearchParameter(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theParamName,
|
String theParamName,
|
||||||
List<List<IQueryParameterType>> theAndOrParams,
|
List<List<IQueryParameterType>> theAndOrParams,
|
||||||
|
@ -2690,7 +2712,7 @@ public class QueryStack {
|
||||||
* by this method
|
* by this method
|
||||||
*/
|
*/
|
||||||
private boolean handleFullyChainedParameter(
|
private boolean handleFullyChainedParameter(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
String theParamName,
|
String theParamName,
|
||||||
RequestDetails theRequest,
|
RequestDetails theRequest,
|
||||||
|
@ -3147,7 +3169,7 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SearchForIdsParams {
|
public static class SearchForIdsParams {
|
||||||
DbColumn mySourceJoinColumn;
|
DbColumn[] mySourceJoinColumn;
|
||||||
String myResourceName;
|
String myResourceName;
|
||||||
String myParamName;
|
String myParamName;
|
||||||
List<List<IQueryParameterType>> myAndOrParams;
|
List<List<IQueryParameterType>> myAndOrParams;
|
||||||
|
@ -3159,11 +3181,11 @@ public class QueryStack {
|
||||||
return new SearchForIdsParams();
|
return new SearchForIdsParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DbColumn getSourceJoinColumn() {
|
public DbColumn[] getSourceJoinColumn() {
|
||||||
return mySourceJoinColumn;
|
return mySourceJoinColumn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SearchForIdsParams setSourceJoinColumn(DbColumn theSourceJoinColumn) {
|
public SearchForIdsParams setSourceJoinColumn(DbColumn[] theSourceJoinColumn) {
|
||||||
mySourceJoinColumn = theSourceJoinColumn;
|
mySourceJoinColumn = theSourceJoinColumn;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ public class MissingParameterQueryParams {
|
||||||
/**
|
/**
|
||||||
* The column on which to join.
|
* The column on which to join.
|
||||||
*/
|
*/
|
||||||
private final DbColumn mySourceJoinColumn;
|
private final DbColumn[] mySourceJoinColumn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The partition id
|
* The partition id
|
||||||
|
@ -76,7 +76,7 @@ public class MissingParameterQueryParams {
|
||||||
List<? extends IQueryParameterType> theList,
|
List<? extends IQueryParameterType> theList,
|
||||||
String theParamName,
|
String theParamName,
|
||||||
String theResourceType,
|
String theResourceType,
|
||||||
DbColumn theSourceJoinColumn,
|
DbColumn[] theSourceJoinColumn,
|
||||||
RequestPartitionId theRequestPartitionId) {
|
RequestPartitionId theRequestPartitionId) {
|
||||||
mySqlBuilder = theSqlBuilder;
|
mySqlBuilder = theSqlBuilder;
|
||||||
myParamType = theParamType;
|
myParamType = theParamType;
|
||||||
|
@ -116,7 +116,7 @@ public class MissingParameterQueryParams {
|
||||||
return myResourceType;
|
return myResourceType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DbColumn getSourceJoinColumn() {
|
public DbColumn[] getSourceJoinColumn() {
|
||||||
return mySourceJoinColumn;
|
return mySourceJoinColumn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,20 +24,22 @@ import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||||
|
|
||||||
public class PredicateBuilderCacheKey {
|
public class PredicateBuilderCacheKey {
|
||||||
private final DbColumn myDbColumn;
|
private final DbColumn[] myDbColumn;
|
||||||
private final PredicateBuilderTypeEnum myType;
|
private final PredicateBuilderTypeEnum myType;
|
||||||
private final String myParamName;
|
private final String myParamName;
|
||||||
private final int myHashCode;
|
private final int myHashCode;
|
||||||
|
|
||||||
public PredicateBuilderCacheKey(DbColumn theDbColumn, PredicateBuilderTypeEnum theType, String theParamName) {
|
public PredicateBuilderCacheKey(DbColumn[] theDbColumn, PredicateBuilderTypeEnum theType, String theParamName) {
|
||||||
myDbColumn = theDbColumn;
|
myDbColumn = theDbColumn;
|
||||||
myType = theType;
|
myType = theType;
|
||||||
myParamName = theParamName;
|
myParamName = theParamName;
|
||||||
myHashCode = new HashCodeBuilder()
|
HashCodeBuilder hashBuilder = new HashCodeBuilder().append(myType).append(myParamName);
|
||||||
.append(myDbColumn)
|
if (theDbColumn != null) {
|
||||||
.append(myType)
|
for (DbColumn next : theDbColumn) {
|
||||||
.append(myParamName)
|
hashBuilder.append(next);
|
||||||
.toHashCode();
|
}
|
||||||
|
}
|
||||||
|
myHashCode = hashBuilder.toHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -51,10 +51,14 @@ public abstract class BaseJoiningPredicateBuilder extends BasePredicateBuilder {
|
||||||
|
|
||||||
public abstract DbColumn getResourceIdColumn();
|
public abstract DbColumn getResourceIdColumn();
|
||||||
|
|
||||||
DbColumn getPartitionIdColumn() {
|
public DbColumn getPartitionIdColumn() {
|
||||||
return myColumnPartitionId;
|
return myColumnPartitionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DbColumn[] getJoinColumns() {
|
||||||
|
return getSearchQueryBuilder().toJoinColumns(getPartitionIdColumn(), getResourceIdColumn());
|
||||||
|
}
|
||||||
|
|
||||||
public Condition combineWithRequestPartitionIdPredicate(
|
public Condition combineWithRequestPartitionIdPredicate(
|
||||||
RequestPartitionId theRequestPartitionId, Condition theCondition) {
|
RequestPartitionId theRequestPartitionId, Condition theCondition) {
|
||||||
Condition partitionIdPredicate = createPartitionIdPredicate(theRequestPartitionId);
|
Condition partitionIdPredicate = createPartitionIdPredicate(theRequestPartitionId);
|
||||||
|
|
|
@ -41,6 +41,10 @@ public abstract class BasePredicateBuilder {
|
||||||
mySearchSqlBuilder = theSearchSqlBuilder;
|
mySearchSqlBuilder = theSearchSqlBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected SearchQueryBuilder getSearchQueryBuilder() {
|
||||||
|
return mySearchSqlBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
PartitionSettings getPartitionSettings() {
|
PartitionSettings getPartitionSettings() {
|
||||||
return mySearchSqlBuilder.getPartitionSettings();
|
return mySearchSqlBuilder.getPartitionSettings();
|
||||||
}
|
}
|
||||||
|
@ -84,7 +88,7 @@ public abstract class BasePredicateBuilder {
|
||||||
return mySearchSqlBuilder.getOrCreateFirstPredicateBuilder(theIncludeResourceTypeAndNonDeletedFlag);
|
return mySearchSqlBuilder.getOrCreateFirstPredicateBuilder(theIncludeResourceTypeAndNonDeletedFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addJoin(DbTable theFromTable, DbTable theToTable, DbColumn theFromColumn, DbColumn theToColumn) {
|
public void addJoin(DbTable theFromTable, DbTable theToTable, DbColumn[] theFromColumn, DbColumn[] theToColumn) {
|
||||||
mySearchSqlBuilder.addJoin(theFromTable, theToTable, theFromColumn, theToColumn);
|
mySearchSqlBuilder.addJoin(theFromTable, theToTable, theFromColumn, theToColumn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,7 @@ public class ResourceIdPredicateBuilder extends BasePredicateBuilder {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public Condition createPredicateResourceId(
|
public Condition createPredicateResourceId(
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumn,
|
||||||
String theResourceName,
|
String theResourceName,
|
||||||
List<List<IQueryParameterType>> theValues,
|
List<List<IQueryParameterType>> theValues,
|
||||||
SearchFilterParser.CompareOperation theOperation,
|
SearchFilterParser.CompareOperation theOperation,
|
||||||
|
@ -134,8 +134,9 @@ public class ResourceIdPredicateBuilder extends BasePredicateBuilder {
|
||||||
return queryRootTable.combineWithRequestPartitionIdPredicate(theRequestPartitionId, predicate);
|
return queryRootTable.combineWithRequestPartitionIdPredicate(theRequestPartitionId, predicate);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
DbColumn resIdColumn = getResourceIdColumn(theSourceJoinColumn);
|
||||||
return QueryParameterUtils.toEqualToOrInPredicate(
|
return QueryParameterUtils.toEqualToOrInPredicate(
|
||||||
theSourceJoinColumn,
|
resIdColumn,
|
||||||
generatePlaceholders(resourceIds),
|
generatePlaceholders(resourceIds),
|
||||||
operation == SearchFilterParser.CompareOperation.ne);
|
operation == SearchFilterParser.CompareOperation.ne);
|
||||||
}
|
}
|
||||||
|
@ -143,4 +144,23 @@ public class ResourceIdPredicateBuilder extends BasePredicateBuilder {
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method takes 1-2 columns and returns the last one. This is useful where the input is an array of
|
||||||
|
* join columns for SQL Search expressions. In partition key mode, there are 2 columns (partition id and resource id).
|
||||||
|
* In non partition key mode, only the resource id column is used.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static DbColumn getResourceIdColumn(@Nullable DbColumn[] theJoinColumns) {
|
||||||
|
DbColumn resIdColumn;
|
||||||
|
if (theJoinColumns == null) {
|
||||||
|
return null;
|
||||||
|
} else if (theJoinColumns.length == 1) {
|
||||||
|
resIdColumn = theJoinColumns[0];
|
||||||
|
} else {
|
||||||
|
assert theJoinColumns.length == 2;
|
||||||
|
resIdColumn = theJoinColumns[1];
|
||||||
|
}
|
||||||
|
return resIdColumn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,6 +108,9 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder im
|
||||||
private final QueryStack myQueryStack;
|
private final QueryStack myQueryStack;
|
||||||
private final boolean myReversed;
|
private final boolean myReversed;
|
||||||
|
|
||||||
|
private final DbColumn myColumnTargetPartitionId;
|
||||||
|
private final DbColumn myColumnSrcPartitionId;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private JpaStorageSettings myStorageSettings;
|
private JpaStorageSettings myStorageSettings;
|
||||||
|
|
||||||
|
@ -133,9 +136,11 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder im
|
||||||
QueryStack theQueryStack, SearchQueryBuilder theSearchSqlBuilder, boolean theReversed) {
|
QueryStack theQueryStack, SearchQueryBuilder theSearchSqlBuilder, boolean theReversed) {
|
||||||
super(theSearchSqlBuilder, theSearchSqlBuilder.addTable("HFJ_RES_LINK"));
|
super(theSearchSqlBuilder, theSearchSqlBuilder.addTable("HFJ_RES_LINK"));
|
||||||
myColumnSrcResourceId = getTable().addColumn("SRC_RESOURCE_ID");
|
myColumnSrcResourceId = getTable().addColumn("SRC_RESOURCE_ID");
|
||||||
|
myColumnSrcPartitionId = getTable().addColumn("PARTITION_ID");
|
||||||
myColumnSrcType = getTable().addColumn("SOURCE_RESOURCE_TYPE");
|
myColumnSrcType = getTable().addColumn("SOURCE_RESOURCE_TYPE");
|
||||||
myColumnSrcPath = getTable().addColumn("SRC_PATH");
|
myColumnSrcPath = getTable().addColumn("SRC_PATH");
|
||||||
myColumnTargetResourceId = getTable().addColumn("TARGET_RESOURCE_ID");
|
myColumnTargetResourceId = getTable().addColumn("TARGET_RESOURCE_ID");
|
||||||
|
myColumnTargetPartitionId = getTable().addColumn("TARGET_RES_PARTITION_ID");
|
||||||
myColumnTargetResourceUrl = getTable().addColumn("TARGET_RESOURCE_URL");
|
myColumnTargetResourceUrl = getTable().addColumn("TARGET_RESOURCE_URL");
|
||||||
myColumnTargetResourceType = getTable().addColumn("TARGET_RESOURCE_TYPE");
|
myColumnTargetResourceType = getTable().addColumn("TARGET_RESOURCE_TYPE");
|
||||||
|
|
||||||
|
@ -159,10 +164,36 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder im
|
||||||
return myColumnTargetResourceId;
|
return myColumnTargetResourceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DbColumn getColumnTargetPartitionId() {
|
||||||
|
return myColumnTargetPartitionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbColumn[] getJoinColumnsForTarget() {
|
||||||
|
return getSearchQueryBuilder().toJoinColumns(getColumnTargetPartitionId(), getColumnTargetResourceId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public DbColumn[] getJoinColumnsForSource() {
|
||||||
|
return getSearchQueryBuilder().toJoinColumns(getPartitionIdColumn(), myColumnSrcResourceId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note that this may return the SRC_RESOURCE_ID or TGT_RESOURCE_ID depending
|
||||||
|
* on whether we're building a forward or reverse link. If you need a specific
|
||||||
|
* one of these, use {@link #getJoinColumnsForSource()} or {@link #getJoinColumnsForTarget()}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public DbColumn[] getJoinColumns() {
|
||||||
|
return super.getJoinColumns();
|
||||||
|
}
|
||||||
|
|
||||||
public DbColumn getColumnSrcResourceId() {
|
public DbColumn getColumnSrcResourceId() {
|
||||||
return myColumnSrcResourceId;
|
return myColumnSrcResourceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public DbColumn getColumnSrcPartitionId() {
|
||||||
|
return myColumnSrcPartitionId;
|
||||||
|
}
|
||||||
|
|
||||||
public DbColumn getColumnTargetResourceType() {
|
public DbColumn getColumnTargetResourceType() {
|
||||||
return myColumnTargetResourceType;
|
return myColumnTargetResourceType;
|
||||||
}
|
}
|
||||||
|
@ -509,7 +540,7 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder im
|
||||||
|
|
||||||
List<List<IQueryParameterType>> chainParamValues = Collections.singletonList(orValues);
|
List<List<IQueryParameterType>> chainParamValues = Collections.singletonList(orValues);
|
||||||
andPredicates.add(
|
andPredicates.add(
|
||||||
childQueryFactory.searchForIdsWithAndOr(with().setSourceJoinColumn(myColumnTargetResourceId)
|
childQueryFactory.searchForIdsWithAndOr(with().setSourceJoinColumn(getJoinColumnsForTarget())
|
||||||
.setResourceName(subResourceName)
|
.setResourceName(subResourceName)
|
||||||
.setParamName(chain)
|
.setParamName(chain)
|
||||||
.setAndOrParams(chainParamValues)
|
.setAndOrParams(chainParamValues)
|
||||||
|
|
|
@ -53,9 +53,9 @@ public class SourcePredicateBuilder extends BaseJoiningPredicateBuilder {
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public SourcePredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) {
|
public SourcePredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) {
|
||||||
super(theSearchSqlBuilder, theSearchSqlBuilder.addTable("HFJ_RES_VER_PROV"));
|
super(theSearchSqlBuilder, theSearchSqlBuilder.addTable("HFJ_RES_VER"));
|
||||||
|
|
||||||
myResourceIdColumn = getTable().addColumn("RES_PID");
|
myResourceIdColumn = getTable().addColumn("RES_ID");
|
||||||
myColumnSourceUri = getTable().addColumn("SOURCE_URI");
|
myColumnSourceUri = getTable().addColumn("SOURCE_URI");
|
||||||
myColumnRequestId = getTable().addColumn("REQUEST_ID");
|
myColumnRequestId = getTable().addColumn("REQUEST_ID");
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,9 @@ public class TagPredicateBuilder extends BaseJoiningPredicateBuilder {
|
||||||
List<Triple<String, String, String>> theTokens,
|
List<Triple<String, String, String>> theTokens,
|
||||||
String theParamName,
|
String theParamName,
|
||||||
RequestPartitionId theRequestPartitionId) {
|
RequestPartitionId theRequestPartitionId) {
|
||||||
addJoin(getTable(), myTagDefinitionTable, myColumnTagId, myTagDefinitionColumnTagId);
|
addJoin(getTable(), myTagDefinitionTable, new DbColumn[] {myColumnTagId}, new DbColumn[] {
|
||||||
|
myTagDefinitionColumnTagId
|
||||||
|
});
|
||||||
return createPredicateTagList(theTagType, theTokens);
|
return createPredicateTagList(theTagType, theTokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
package ca.uhn.fhir.jpa.search.builder.sql;
|
||||||
|
|
||||||
|
import com.healthmarketscience.common.util.AppendableExt;
|
||||||
|
import com.healthmarketscience.sqlbuilder.SqlContext;
|
||||||
|
import com.healthmarketscience.sqlbuilder.SqlObject;
|
||||||
|
import com.healthmarketscience.sqlbuilder.ValidationContext;
|
||||||
|
import com.healthmarketscience.sqlbuilder.dbspec.Column;
|
||||||
|
import com.healthmarketscience.sqlbuilder.dbspec.Table;
|
||||||
|
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
|
public class ColumnTupleObject extends SqlObject {
|
||||||
|
|
||||||
|
private final List<Column> myColumns;
|
||||||
|
|
||||||
|
public ColumnTupleObject(Column... theColumns) {
|
||||||
|
myColumns = List.of(theColumns);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void collectSchemaObjects(ValidationContext vContext) {
|
||||||
|
myColumns.forEach(vContext::addColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void appendTo(AppendableExt app) throws IOException {
|
||||||
|
app.append('(');
|
||||||
|
|
||||||
|
for (Iterator<Column> iter = myColumns.iterator(); iter.hasNext(); ) {
|
||||||
|
Column column = iter.next();
|
||||||
|
appendTableAliasPrefix(app, column.getTable());
|
||||||
|
app.append(column.getColumnNameSQL());
|
||||||
|
|
||||||
|
if (iter.hasNext()) {
|
||||||
|
app.append(',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
app.append(')');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs the table alias prefix <code>"[<tableAlias>.]"</code> for a
|
||||||
|
* column reference if the current SqlContext specifies table aliases should
|
||||||
|
* be used (and the table has an alias), otherwise does nothing.
|
||||||
|
*/
|
||||||
|
static void appendTableAliasPrefix(AppendableExt app, Table table) throws IOException {
|
||||||
|
if (SqlContext.getContext(app).getUseTableAliases()) {
|
||||||
|
String alias = table.getAlias();
|
||||||
|
if (isNotBlank(alias)) {
|
||||||
|
app.append(alias).append(".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object from(DbColumn[] theJoinColumns) {
|
||||||
|
if (theJoinColumns.length == 1) {
|
||||||
|
return theJoinColumns[0];
|
||||||
|
} else {
|
||||||
|
return new ColumnTupleObject(theJoinColumns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -102,6 +102,7 @@ public class SearchQueryBuilder {
|
||||||
private final SqlObjectFactory mySqlBuilderFactory;
|
private final SqlObjectFactory mySqlBuilderFactory;
|
||||||
private final boolean myCountQuery;
|
private final boolean myCountQuery;
|
||||||
private final Dialect myDialect;
|
private final Dialect myDialect;
|
||||||
|
private final boolean mySelectPartitionId;
|
||||||
private boolean myMatchNothing;
|
private boolean myMatchNothing;
|
||||||
private ResourceTablePredicateBuilder myResourceTableRoot;
|
private ResourceTablePredicateBuilder myResourceTableRoot;
|
||||||
private boolean myHaveAtLeastOnePredicate;
|
private boolean myHaveAtLeastOnePredicate;
|
||||||
|
@ -111,6 +112,7 @@ public class SearchQueryBuilder {
|
||||||
private boolean myNeedResourceTableRoot;
|
private boolean myNeedResourceTableRoot;
|
||||||
private int myNextNearnessColumnId = 0;
|
private int myNextNearnessColumnId = 0;
|
||||||
private DbColumn mySelectedResourceIdColumn;
|
private DbColumn mySelectedResourceIdColumn;
|
||||||
|
private DbColumn mySelectedPartitionIdColumn;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -134,7 +136,8 @@ public class SearchQueryBuilder {
|
||||||
UUID.randomUUID() + "-",
|
UUID.randomUUID() + "-",
|
||||||
theDialectProvider.getDialect(),
|
theDialectProvider.getDialect(),
|
||||||
theCountQuery,
|
theCountQuery,
|
||||||
new ArrayList<>());
|
new ArrayList<>(),
|
||||||
|
thePartitionSettings.isPartitionIdsInPrimaryKeys());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -150,7 +153,8 @@ public class SearchQueryBuilder {
|
||||||
String theBindVariableSubstitutionBase,
|
String theBindVariableSubstitutionBase,
|
||||||
Dialect theDialect,
|
Dialect theDialect,
|
||||||
boolean theCountQuery,
|
boolean theCountQuery,
|
||||||
ArrayList<Object> theBindVariableValues) {
|
ArrayList<Object> theBindVariableValues,
|
||||||
|
boolean theSelectPartitionId) {
|
||||||
myFhirContext = theFhirContext;
|
myFhirContext = theFhirContext;
|
||||||
myStorageSettings = theStorageSettings;
|
myStorageSettings = theStorageSettings;
|
||||||
myPartitionSettings = thePartitionSettings;
|
myPartitionSettings = thePartitionSettings;
|
||||||
|
@ -172,6 +176,7 @@ public class SearchQueryBuilder {
|
||||||
|
|
||||||
myBindVariableSubstitutionBase = theBindVariableSubstitutionBase;
|
myBindVariableSubstitutionBase = theBindVariableSubstitutionBase;
|
||||||
myBindVariableValues = theBindVariableValues;
|
myBindVariableValues = theBindVariableValues;
|
||||||
|
mySelectPartitionId = theSelectPartitionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FhirContext getFhirContext() {
|
public FhirContext getFhirContext() {
|
||||||
|
@ -201,7 +206,7 @@ public class SearchQueryBuilder {
|
||||||
/**
|
/**
|
||||||
* Add and return a predicate builder (or a root query if no root query exists yet) for selecting on a COORDS search parameter
|
* Add and return a predicate builder (or a root query if no root query exists yet) for selecting on a COORDS search parameter
|
||||||
*/
|
*/
|
||||||
public CoordsPredicateBuilder addCoordsPredicateBuilder(@Nullable DbColumn theSourceJoinColumn) {
|
public CoordsPredicateBuilder addCoordsPredicateBuilder(@Nullable DbColumn[] theSourceJoinColumn) {
|
||||||
CoordsPredicateBuilder retVal = mySqlBuilderFactory.coordsPredicateBuilder(this);
|
CoordsPredicateBuilder retVal = mySqlBuilderFactory.coordsPredicateBuilder(this);
|
||||||
addTable(retVal, theSourceJoinColumn);
|
addTable(retVal, theSourceJoinColumn);
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -210,7 +215,7 @@ public class SearchQueryBuilder {
|
||||||
/**
|
/**
|
||||||
* Create, add and return a predicate builder (or a root query if no root query exists yet) for selecting on a DATE search parameter
|
* Create, add and return a predicate builder (or a root query if no root query exists yet) for selecting on a DATE search parameter
|
||||||
*/
|
*/
|
||||||
public DatePredicateBuilder addDatePredicateBuilder(@Nullable DbColumn theSourceJoinColumn) {
|
public DatePredicateBuilder addDatePredicateBuilder(@Nullable DbColumn[] theSourceJoinColumn) {
|
||||||
DatePredicateBuilder retVal = mySqlBuilderFactory.dateIndexTable(this);
|
DatePredicateBuilder retVal = mySqlBuilderFactory.dateIndexTable(this);
|
||||||
addTable(retVal, theSourceJoinColumn);
|
addTable(retVal, theSourceJoinColumn);
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -226,7 +231,7 @@ public class SearchQueryBuilder {
|
||||||
/**
|
/**
|
||||||
* Create, add and return a predicate builder (or a root query if no root query exists yet) for selecting on a NUMBER search parameter
|
* Create, add and return a predicate builder (or a root query if no root query exists yet) for selecting on a NUMBER search parameter
|
||||||
*/
|
*/
|
||||||
public NumberPredicateBuilder addNumberPredicateBuilder(@Nullable DbColumn theSourceJoinColumn) {
|
public NumberPredicateBuilder addNumberPredicateBuilder(@Nullable DbColumn[] theSourceJoinColumn) {
|
||||||
NumberPredicateBuilder retVal = createNumberPredicateBuilder();
|
NumberPredicateBuilder retVal = createNumberPredicateBuilder();
|
||||||
addTable(retVal, theSourceJoinColumn);
|
addTable(retVal, theSourceJoinColumn);
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -242,7 +247,7 @@ public class SearchQueryBuilder {
|
||||||
/**
|
/**
|
||||||
* Add and return a predicate builder (or a root query if no root query exists yet) for selecting on the Resource table
|
* Add and return a predicate builder (or a root query if no root query exists yet) for selecting on the Resource table
|
||||||
*/
|
*/
|
||||||
public ResourceTablePredicateBuilder addResourceTablePredicateBuilder(@Nullable DbColumn theSourceJoinColumn) {
|
public ResourceTablePredicateBuilder addResourceTablePredicateBuilder(@Nullable DbColumn[] theSourceJoinColumn) {
|
||||||
ResourceTablePredicateBuilder retVal = mySqlBuilderFactory.resourceTable(this);
|
ResourceTablePredicateBuilder retVal = mySqlBuilderFactory.resourceTable(this);
|
||||||
addTable(retVal, theSourceJoinColumn);
|
addTable(retVal, theSourceJoinColumn);
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -251,7 +256,7 @@ public class SearchQueryBuilder {
|
||||||
/**
|
/**
|
||||||
* Create, add and return a predicate builder (or a root query if no root query exists yet) for selecting on a QUANTITY search parameter
|
* Create, add and return a predicate builder (or a root query if no root query exists yet) for selecting on a QUANTITY search parameter
|
||||||
*/
|
*/
|
||||||
public QuantityPredicateBuilder addQuantityPredicateBuilder(@Nullable DbColumn theSourceJoinColumn) {
|
public QuantityPredicateBuilder addQuantityPredicateBuilder(@Nullable DbColumn[] theSourceJoinColumn) {
|
||||||
QuantityPredicateBuilder retVal = createQuantityPredicateBuilder();
|
QuantityPredicateBuilder retVal = createQuantityPredicateBuilder();
|
||||||
addTable(retVal, theSourceJoinColumn);
|
addTable(retVal, theSourceJoinColumn);
|
||||||
|
|
||||||
|
@ -266,7 +271,7 @@ public class SearchQueryBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public QuantityNormalizedPredicateBuilder addQuantityNormalizedPredicateBuilder(
|
public QuantityNormalizedPredicateBuilder addQuantityNormalizedPredicateBuilder(
|
||||||
@Nullable DbColumn theSourceJoinColumn) {
|
@Nullable DbColumn[] theSourceJoinColumn) {
|
||||||
|
|
||||||
QuantityNormalizedPredicateBuilder retVal = mySqlBuilderFactory.quantityNormalizedIndexTable(this);
|
QuantityNormalizedPredicateBuilder retVal = mySqlBuilderFactory.quantityNormalizedIndexTable(this);
|
||||||
addTable(retVal, theSourceJoinColumn);
|
addTable(retVal, theSourceJoinColumn);
|
||||||
|
@ -278,7 +283,7 @@ public class SearchQueryBuilder {
|
||||||
* Add and return a predicate builder (or a root query if no root query exists yet) for selecting on a <code>_source</code> search parameter
|
* Add and return a predicate builder (or a root query if no root query exists yet) for selecting on a <code>_source</code> search parameter
|
||||||
*/
|
*/
|
||||||
public SourcePredicateBuilder addSourcePredicateBuilder(
|
public SourcePredicateBuilder addSourcePredicateBuilder(
|
||||||
@Nullable DbColumn theSourceJoinColumn, SelectQuery.JoinType theJoinType) {
|
@Nullable DbColumn[] theSourceJoinColumn, SelectQuery.JoinType theJoinType) {
|
||||||
SourcePredicateBuilder retVal = mySqlBuilderFactory.newSourcePredicateBuilder(this);
|
SourcePredicateBuilder retVal = mySqlBuilderFactory.newSourcePredicateBuilder(this);
|
||||||
addTable(retVal, theSourceJoinColumn, theJoinType);
|
addTable(retVal, theSourceJoinColumn, theJoinType);
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -288,7 +293,7 @@ public class SearchQueryBuilder {
|
||||||
* Create, add and return a predicate builder (or a root query if no root query exists yet) for selecting on a REFERENCE search parameter
|
* Create, add and return a predicate builder (or a root query if no root query exists yet) for selecting on a REFERENCE search parameter
|
||||||
*/
|
*/
|
||||||
public ResourceLinkPredicateBuilder addReferencePredicateBuilder(
|
public ResourceLinkPredicateBuilder addReferencePredicateBuilder(
|
||||||
QueryStack theQueryStack, @Nullable DbColumn theSourceJoinColumn) {
|
QueryStack theQueryStack, @Nullable DbColumn[] theSourceJoinColumn) {
|
||||||
ResourceLinkPredicateBuilder retVal = createReferencePredicateBuilder(theQueryStack);
|
ResourceLinkPredicateBuilder retVal = createReferencePredicateBuilder(theQueryStack);
|
||||||
addTable(retVal, theSourceJoinColumn);
|
addTable(retVal, theSourceJoinColumn);
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -306,7 +311,7 @@ public class SearchQueryBuilder {
|
||||||
* source and target are reversed. This is used for _has queries.
|
* source and target are reversed. This is used for _has queries.
|
||||||
*/
|
*/
|
||||||
public ResourceLinkPredicateBuilder addReferencePredicateBuilderReversed(
|
public ResourceLinkPredicateBuilder addReferencePredicateBuilderReversed(
|
||||||
QueryStack theQueryStack, DbColumn theSourceJoinColumn) {
|
QueryStack theQueryStack, DbColumn[] theSourceJoinColumn) {
|
||||||
ResourceLinkPredicateBuilder retVal = mySqlBuilderFactory.referenceIndexTable(theQueryStack, this, true);
|
ResourceLinkPredicateBuilder retVal = mySqlBuilderFactory.referenceIndexTable(theQueryStack, this, true);
|
||||||
addTable(retVal, theSourceJoinColumn);
|
addTable(retVal, theSourceJoinColumn);
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -315,7 +320,7 @@ public class SearchQueryBuilder {
|
||||||
/**
|
/**
|
||||||
* Create, add and return a predicate builder (or a root query if no root query exists yet) for selecting on a STRING search parameter
|
* Create, add and return a predicate builder (or a root query if no root query exists yet) for selecting on a STRING search parameter
|
||||||
*/
|
*/
|
||||||
public StringPredicateBuilder addStringPredicateBuilder(@Nullable DbColumn theSourceJoinColumn) {
|
public StringPredicateBuilder addStringPredicateBuilder(@Nullable DbColumn[] theSourceJoinColumn) {
|
||||||
StringPredicateBuilder retVal = createStringPredicateBuilder();
|
StringPredicateBuilder retVal = createStringPredicateBuilder();
|
||||||
addTable(retVal, theSourceJoinColumn);
|
addTable(retVal, theSourceJoinColumn);
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -331,7 +336,7 @@ public class SearchQueryBuilder {
|
||||||
/**
|
/**
|
||||||
* Add and return a predicate builder (or a root query if no root query exists yet) for selecting on a <code>_tag</code> search parameter
|
* Add and return a predicate builder (or a root query if no root query exists yet) for selecting on a <code>_tag</code> search parameter
|
||||||
*/
|
*/
|
||||||
public TagPredicateBuilder addTagPredicateBuilder(@Nullable DbColumn theSourceJoinColumn) {
|
public TagPredicateBuilder addTagPredicateBuilder(@Nullable DbColumn[] theSourceJoinColumn) {
|
||||||
TagPredicateBuilder retVal = mySqlBuilderFactory.newTagPredicateBuilder(this);
|
TagPredicateBuilder retVal = mySqlBuilderFactory.newTagPredicateBuilder(this);
|
||||||
addTable(retVal, theSourceJoinColumn);
|
addTable(retVal, theSourceJoinColumn);
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -340,7 +345,7 @@ public class SearchQueryBuilder {
|
||||||
/**
|
/**
|
||||||
* Create, add and return a predicate builder (or a root query if no root query exists yet) for selecting on a TOKEN search parameter
|
* Create, add and return a predicate builder (or a root query if no root query exists yet) for selecting on a TOKEN search parameter
|
||||||
*/
|
*/
|
||||||
public TokenPredicateBuilder addTokenPredicateBuilder(@Nullable DbColumn theSourceJoinColumn) {
|
public TokenPredicateBuilder addTokenPredicateBuilder(@Nullable DbColumn[] theSourceJoinColumn) {
|
||||||
TokenPredicateBuilder retVal = createTokenPredicateBuilder();
|
TokenPredicateBuilder retVal = createTokenPredicateBuilder();
|
||||||
addTable(retVal, theSourceJoinColumn);
|
addTable(retVal, theSourceJoinColumn);
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -358,10 +363,11 @@ public class SearchQueryBuilder {
|
||||||
mySelect.addCustomJoin(theJoinType, theFromTable, theToTable, theCondition);
|
mySelect.addCustomJoin(theJoinType, theFromTable, theToTable, theCondition);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ComboCondition createOnCondition(DbColumn theSourceColumn, DbColumn theTargetColumn) {
|
public ComboCondition createOnCondition(DbColumn[] theSourceColumn, DbColumn[] theTargetColumn) {
|
||||||
ComboCondition onCondition = ComboCondition.and();
|
ComboCondition onCondition = ComboCondition.and();
|
||||||
onCondition.addCondition(BinaryCondition.equalTo(theSourceColumn, theTargetColumn));
|
for (int i = 0; i < theSourceColumn.length; i += 1) {
|
||||||
|
onCondition.addCondition(BinaryCondition.equalTo(theSourceColumn[i], theTargetColumn[i]));
|
||||||
|
}
|
||||||
return onCondition;
|
return onCondition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,7 +375,7 @@ public class SearchQueryBuilder {
|
||||||
* Add and return a predicate builder (or a root query if no root query exists yet) for selecting on a <code>:missing</code> search parameter
|
* Add and return a predicate builder (or a root query if no root query exists yet) for selecting on a <code>:missing</code> search parameter
|
||||||
*/
|
*/
|
||||||
public SearchParamPresentPredicateBuilder addSearchParamPresentPredicateBuilder(
|
public SearchParamPresentPredicateBuilder addSearchParamPresentPredicateBuilder(
|
||||||
@Nullable DbColumn theSourceJoinColumn) {
|
@Nullable DbColumn[] theSourceJoinColumn) {
|
||||||
SearchParamPresentPredicateBuilder retVal = mySqlBuilderFactory.searchParamPresentPredicateBuilder(this);
|
SearchParamPresentPredicateBuilder retVal = mySqlBuilderFactory.searchParamPresentPredicateBuilder(this);
|
||||||
addTable(retVal, theSourceJoinColumn);
|
addTable(retVal, theSourceJoinColumn);
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -378,7 +384,7 @@ public class SearchQueryBuilder {
|
||||||
/**
|
/**
|
||||||
* Create, add and return a predicate builder (or a root query if no root query exists yet) for selecting on a URI search parameter
|
* Create, add and return a predicate builder (or a root query if no root query exists yet) for selecting on a URI search parameter
|
||||||
*/
|
*/
|
||||||
public UriPredicateBuilder addUriPredicateBuilder(@Nullable DbColumn theSourceJoinColumn) {
|
public UriPredicateBuilder addUriPredicateBuilder(@Nullable DbColumn[] theSourceJoinColumn) {
|
||||||
UriPredicateBuilder retVal = createUriPredicateBuilder();
|
UriPredicateBuilder retVal = createUriPredicateBuilder();
|
||||||
addTable(retVal, theSourceJoinColumn);
|
addTable(retVal, theSourceJoinColumn);
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -402,19 +408,19 @@ public class SearchQueryBuilder {
|
||||||
/**
|
/**
|
||||||
* Add and return a predicate builder (or a root query if no root query exists yet) for an arbitrary table
|
* Add and return a predicate builder (or a root query if no root query exists yet) for an arbitrary table
|
||||||
*/
|
*/
|
||||||
private void addTable(BaseJoiningPredicateBuilder thePredicateBuilder, @Nullable DbColumn theSourceJoinColumn) {
|
private void addTable(BaseJoiningPredicateBuilder thePredicateBuilder, @Nullable DbColumn[] theSourceJoinColumn) {
|
||||||
addTable(thePredicateBuilder, theSourceJoinColumn, SelectQuery.JoinType.INNER);
|
addTable(thePredicateBuilder, theSourceJoinColumn, SelectQuery.JoinType.INNER);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addTable(
|
private void addTable(
|
||||||
BaseJoiningPredicateBuilder thePredicateBuilder,
|
BaseJoiningPredicateBuilder thePredicateBuilder,
|
||||||
@Nullable DbColumn theSourceJoinColumn,
|
@Nullable DbColumn[] theSourceJoinColumns,
|
||||||
SelectQuery.JoinType theJoinType) {
|
SelectQuery.JoinType theJoinType) {
|
||||||
if (theSourceJoinColumn != null) {
|
if (theSourceJoinColumns != null) {
|
||||||
DbTable fromTable = theSourceJoinColumn.getTable();
|
DbTable fromTable = theSourceJoinColumns[0].getTable();
|
||||||
DbTable toTable = thePredicateBuilder.getTable();
|
DbTable toTable = thePredicateBuilder.getTable();
|
||||||
DbColumn toColumn = thePredicateBuilder.getResourceIdColumn();
|
DbColumn[] toColumn = toJoinColumns(thePredicateBuilder);
|
||||||
addJoin(fromTable, toTable, theSourceJoinColumn, toColumn, theJoinType);
|
addJoin(fromTable, toTable, theSourceJoinColumns, toColumn, theJoinType);
|
||||||
} else {
|
} else {
|
||||||
if (myFirstPredicateBuilder == null) {
|
if (myFirstPredicateBuilder == null) {
|
||||||
|
|
||||||
|
@ -432,10 +438,16 @@ public class SearchQueryBuilder {
|
||||||
if (myCountQuery) {
|
if (myCountQuery) {
|
||||||
mySelect.addCustomColumns(
|
mySelect.addCustomColumns(
|
||||||
FunctionCall.count().setIsDistinct(true).addColumnParams(root.getResourceIdColumn()));
|
FunctionCall.count().setIsDistinct(true).addColumnParams(root.getResourceIdColumn()));
|
||||||
|
} else {
|
||||||
|
if (mySelectPartitionId) {
|
||||||
|
mySelectedResourceIdColumn = root.getResourceIdColumn();
|
||||||
|
mySelectedPartitionIdColumn = root.getPartitionIdColumn();
|
||||||
|
mySelect.addColumns(mySelectedPartitionIdColumn, mySelectedResourceIdColumn);
|
||||||
} else {
|
} else {
|
||||||
mySelectedResourceIdColumn = root.getResourceIdColumn();
|
mySelectedResourceIdColumn = root.getResourceIdColumn();
|
||||||
mySelect.addColumns(mySelectedResourceIdColumn);
|
mySelect.addColumns(mySelectedResourceIdColumn);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
mySelect.addFromTable(root.getTable());
|
mySelect.addFromTable(root.getTable());
|
||||||
myFirstPredicateBuilder = root;
|
myFirstPredicateBuilder = root;
|
||||||
|
|
||||||
|
@ -446,29 +458,50 @@ public class SearchQueryBuilder {
|
||||||
|
|
||||||
DbTable fromTable = myFirstPredicateBuilder.getTable();
|
DbTable fromTable = myFirstPredicateBuilder.getTable();
|
||||||
DbTable toTable = thePredicateBuilder.getTable();
|
DbTable toTable = thePredicateBuilder.getTable();
|
||||||
DbColumn fromColumn = myFirstPredicateBuilder.getResourceIdColumn();
|
DbColumn[] fromColumn = toJoinColumns(myFirstPredicateBuilder);
|
||||||
DbColumn toColumn = thePredicateBuilder.getResourceIdColumn();
|
DbColumn[] toColumn = toJoinColumns(thePredicateBuilder);
|
||||||
addJoin(fromTable, toTable, fromColumn, toColumn, theJoinType);
|
addJoin(fromTable, toTable, fromColumn, toColumn, theJoinType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public DbColumn[] toJoinColumns(BaseJoiningPredicateBuilder theBuilder) {
|
||||||
|
DbColumn partitionIdColumn = theBuilder.getPartitionIdColumn();
|
||||||
|
DbColumn resourceIdColumn = theBuilder.getResourceIdColumn();
|
||||||
|
return toJoinColumns(partitionIdColumn, resourceIdColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove or keep partition_id columns depending on settings.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
public DbColumn[] toJoinColumns(DbColumn partitionIdColumn, DbColumn resourceIdColumn) {
|
||||||
|
if (isIncludePartitionIdInJoins()) {
|
||||||
|
return new DbColumn[] {partitionIdColumn, resourceIdColumn};
|
||||||
|
} else {
|
||||||
|
return new DbColumn[] {resourceIdColumn};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isIncludePartitionIdInJoins() {
|
||||||
|
return mySelectPartitionId && myPartitionSettings.isPartitionIdsInPrimaryKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addJoin(DbTable theFromTable, DbTable theToTable, DbColumn[] theFromColumn, DbColumn[] theToColumn) {
|
||||||
|
addJoin(theFromTable, theToTable, theFromColumn, theToColumn, SelectQuery.JoinType.INNER);
|
||||||
|
}
|
||||||
|
|
||||||
public void addJoin(
|
public void addJoin(
|
||||||
DbTable theFromTable,
|
DbTable theFromTable,
|
||||||
DbTable theToTable,
|
DbTable theToTable,
|
||||||
DbColumn theFromColumn,
|
DbColumn[] theFromColumn,
|
||||||
DbColumn theToColumn,
|
DbColumn[] theToColumn,
|
||||||
SelectQuery.JoinType theJoinType) {
|
SelectQuery.JoinType theJoinType) {
|
||||||
Join join = new DbJoin(
|
assert theFromColumn.length == theToColumn.length;
|
||||||
mySpec, theFromTable, theToTable, new DbColumn[] {theFromColumn}, new DbColumn[] {theToColumn});
|
Join join = new DbJoin(mySpec, theFromTable, theToTable, theFromColumn, theToColumn);
|
||||||
mySelect.addJoins(theJoinType, join);
|
mySelect.addJoins(theJoinType, join);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addJoin(DbTable theFromTable, DbTable theToTable, DbColumn theFromColumn, DbColumn theToColumn) {
|
|
||||||
Join join = new DbJoin(
|
|
||||||
mySpec, theFromTable, theToTable, new DbColumn[] {theFromColumn}, new DbColumn[] {theToColumn});
|
|
||||||
mySelect.addJoins(SelectQuery.JoinType.INNER, join);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate and return the SQL generated by this builder
|
* Generate and return the SQL generated by this builder
|
||||||
*/
|
*/
|
||||||
|
@ -802,7 +835,7 @@ public class SearchQueryBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SearchQueryBuilder newChildSqlBuilder() {
|
public SearchQueryBuilder newChildSqlBuilder(boolean theSelectPartitionId) {
|
||||||
return new SearchQueryBuilder(
|
return new SearchQueryBuilder(
|
||||||
myFhirContext,
|
myFhirContext,
|
||||||
myStorageSettings,
|
myStorageSettings,
|
||||||
|
@ -813,7 +846,8 @@ public class SearchQueryBuilder {
|
||||||
myBindVariableSubstitutionBase,
|
myBindVariableSubstitutionBase,
|
||||||
myDialect,
|
myDialect,
|
||||||
false,
|
false,
|
||||||
myBindVariableValues);
|
myBindVariableValues,
|
||||||
|
theSelectPartitionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SelectQuery getSelect() {
|
public SelectQuery getSelect() {
|
||||||
|
|
|
@ -107,6 +107,7 @@ public class SearchQueryExecutor implements ISearchQueryExecutor {
|
||||||
* is managed by Spring has been started before this method is called.
|
* is managed by Spring has been started before this method is called.
|
||||||
*/
|
*/
|
||||||
HapiTransactionService.requireTransaction();
|
HapiTransactionService.requireTransaction();
|
||||||
|
ourLog.trace("About to execute SQL: {}. Parameters: {}", sql, Arrays.toString(args));
|
||||||
|
|
||||||
Query nativeQuery = myEntityManager.createNativeQuery(sql);
|
Query nativeQuery = myEntityManager.createNativeQuery(sql);
|
||||||
org.hibernate.query.Query<?> hibernateQuery = (org.hibernate.query.Query<?>) nativeQuery;
|
org.hibernate.query.Query<?> hibernateQuery = (org.hibernate.query.Query<?>) nativeQuery;
|
||||||
|
@ -114,8 +115,6 @@ public class SearchQueryExecutor implements ISearchQueryExecutor {
|
||||||
hibernateQuery.setParameter(i, args[i - 1]);
|
hibernateQuery.setParameter(i, args[i - 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.trace("About to execute SQL: {}. Parameters: {}", sql, Arrays.toString(args));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These settings help to ensure that we use a search cursor
|
* These settings help to ensure that we use a search cursor
|
||||||
* as opposed to loading all search results into memory
|
* as opposed to loading all search results into memory
|
||||||
|
@ -145,14 +144,7 @@ public class SearchQueryExecutor implements ISearchQueryExecutor {
|
||||||
if (myResultSet == null || !myResultSet.hasNext()) {
|
if (myResultSet == null || !myResultSet.hasNext()) {
|
||||||
myNext = NO_MORE;
|
myNext = NO_MORE;
|
||||||
} else {
|
} else {
|
||||||
Object nextRow = Objects.requireNonNull(myResultSet.next());
|
myNext = getNextPid(myResultSet);
|
||||||
Number next;
|
|
||||||
if (nextRow instanceof Number) {
|
|
||||||
next = (Number) nextRow;
|
|
||||||
} else {
|
|
||||||
next = (Number) ((Object[]) nextRow)[0];
|
|
||||||
}
|
|
||||||
myNext = next.longValue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -163,6 +155,40 @@ public class SearchQueryExecutor implements ISearchQueryExecutor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long getNextPid(ScrollableResultsIterator<Object> theResultSet) {
|
||||||
|
Object nextRow = Objects.requireNonNull(theResultSet.next());
|
||||||
|
// We should typically get two columns back, the first is the partition ID and the second
|
||||||
|
// is the resource ID. But if we're doing a count query, we'll get a single column in an array
|
||||||
|
// or maybe even just a single non array value depending on how the platform handles it.
|
||||||
|
if (nextRow instanceof Number) {
|
||||||
|
return ((Number) nextRow).longValue();
|
||||||
|
} else {
|
||||||
|
Object[] nextRowAsArray = (Object[]) nextRow;
|
||||||
|
if (nextRowAsArray.length == 1) {
|
||||||
|
return (Long) nextRowAsArray[0];
|
||||||
|
} else {
|
||||||
|
int i;
|
||||||
|
// TODO MB add a strategy object to GeneratedSql to describe the result set.
|
||||||
|
// or make SQE generic
|
||||||
|
// Comment to reviewer: this will be cleaner with the next
|
||||||
|
// merge from ja_20240718_pk_schema_selector
|
||||||
|
|
||||||
|
// We have some cases to distinguish:
|
||||||
|
// - res_id
|
||||||
|
// - count
|
||||||
|
// - partition_id, res_id
|
||||||
|
// - res_id, coord-dist
|
||||||
|
// - partition_id, res_id, coord-dist
|
||||||
|
// Assume res_id is first Long in row, and is in first two columns
|
||||||
|
if (nextRowAsArray[0] instanceof Long) {
|
||||||
|
return (long) nextRowAsArray[0];
|
||||||
|
} else {
|
||||||
|
return (long) nextRowAsArray[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static SearchQueryExecutor emptyExecutor() {
|
public static SearchQueryExecutor emptyExecutor() {
|
||||||
return NO_VALUE_EXECUTOR;
|
return NO_VALUE_EXECUTOR;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,8 +33,27 @@ public class PartitionSettings {
|
||||||
private Integer myDefaultPartitionId;
|
private Integer myDefaultPartitionId;
|
||||||
private boolean myAlwaysOpenNewTransactionForDifferentPartition;
|
private boolean myAlwaysOpenNewTransactionForDifferentPartition;
|
||||||
private boolean myConditionalCreateDuplicateIdentifiersEnabled = false;
|
private boolean myConditionalCreateDuplicateIdentifiersEnabled = false;
|
||||||
|
private boolean myPartitionIdsInPrimaryKeys = false;
|
||||||
|
|
||||||
public PartitionSettings() {}
|
public PartitionSettings() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the table partition column (usually PARTITION_ID)
|
||||||
|
* participating in primary and foreign keys.
|
||||||
|
* Affects sql joins, sql in() expressions, etc.
|
||||||
|
*/
|
||||||
|
public boolean isPartitionIdsInPrimaryKeys() {
|
||||||
|
return myPartitionIdsInPrimaryKeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inform the query engine if the primary and foreign keys
|
||||||
|
* of the partitioned tables include the partition column.
|
||||||
|
*/
|
||||||
|
public void setPartitionIdsInPrimaryKeys(boolean thePartitionIdsInPrimaryKeys) {
|
||||||
|
myPartitionIdsInPrimaryKeys = thePartitionIdsInPrimaryKeys;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should we always open a new database transaction if the partition context changes
|
* Should we always open a new database transaction if the partition context changes
|
||||||
*
|
*
|
||||||
|
|
|
@ -23,6 +23,7 @@ import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
|
||||||
import ca.uhn.fhir.rest.api.server.storage.BaseResourcePersistentId;
|
import ca.uhn.fhir.rest.api.server.storage.BaseResourcePersistentId;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -66,6 +67,10 @@ public class JpaPid extends BaseResourcePersistentId<Long> {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<Long> toLongList(JpaPid[] thePids) {
|
||||||
|
return toLongList(Arrays.asList(thePids));
|
||||||
|
}
|
||||||
|
|
||||||
public static List<Long> toLongList(Collection<JpaPid> thePids) {
|
public static List<Long> toLongList(Collection<JpaPid> thePids) {
|
||||||
List<Long> retVal = new ArrayList<>(thePids.size());
|
List<Long> retVal = new ArrayList<>(thePids.size());
|
||||||
for (JpaPid next : thePids) {
|
for (JpaPid next : thePids) {
|
||||||
|
@ -129,4 +134,10 @@ public class JpaPid extends BaseResourcePersistentId<Long> {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return myId.toString();
|
return myId.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getPartitionId() {
|
||||||
|
// wipmb should we return null instead?
|
||||||
|
assert getPartitionablePartitionId() != null;
|
||||||
|
return getPartitionablePartitionId().getPartitionId();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package ca.uhn.fhir.jpa.model.dao;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static ca.uhn.fhir.jpa.model.dao.JpaPid.fromId;
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class JpaPidTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testToLongList() {
|
||||||
|
assertEquals(List.of(), JpaPid.toLongList(List.of()));
|
||||||
|
assertEquals(List.of(1L, 2L), JpaPid.toLongList(List.of(fromId(1L), fromId(2L))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testArrayToLongList() {
|
||||||
|
assertEquals(List.of(), JpaPid.toLongList(new JpaPid[0]));
|
||||||
|
assertEquals(List.of(1L, 2L), JpaPid.toLongList(new JpaPid[]{fromId(1L), fromId(2L)}));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
package ca.uhn.fhir.jpa.provider.dstu3;
|
package ca.uhn.fhir.jpa.provider.dstu3;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||||
import ca.uhn.fhir.jpa.searchparam.ResourceSearch;
|
import ca.uhn.fhir.jpa.searchparam.ResourceSearch;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
|
@ -16,7 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
public class ResourceProviderSearchModifierDstu3Test extends BaseResourceProviderDstu3Test{
|
public class ResourceProviderSearchModifierDstu3Test extends BaseResourceProviderDstu3Test{
|
||||||
@Autowired
|
@Autowired
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package ca.uhn.fhir.jpa.dao.r4;
|
package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
||||||
|
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.test.BaseJpaR4Test;
|
import ca.uhn.fhir.jpa.test.BaseJpaR4Test;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
|
import ca.uhn.fhir.rest.api.SortSpec;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.param.StringParam;
|
import ca.uhn.fhir.rest.param.StringParam;
|
||||||
import ca.uhn.fhir.rest.param.TokenParam;
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
|
@ -15,11 +16,17 @@ import org.hl7.fhir.r4.model.SearchParameter;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.CsvSource;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
|
public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
|
@ -35,6 +42,9 @@ public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void after() {
|
public void after() {
|
||||||
myStorageSettings.setTagStorageMode(JpaStorageSettings.DEFAULT_TAG_STORAGE_MODE);
|
myStorageSettings.setTagStorageMode(JpaStorageSettings.DEFAULT_TAG_STORAGE_MODE);
|
||||||
|
myPartitionSettings.setDefaultPartitionId(new PartitionSettings().getDefaultPartitionId());
|
||||||
|
myPartitionSettings.setPartitionIdsInPrimaryKeys(new PartitionSettings().isPartitionIdsInPrimaryKeys());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,6 +62,50 @@ public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@CsvSource(textBlock = """
|
||||||
|
single param - no hfj_resource, Patient?name=smith , 'SELECT t0.RES_ID FROM HFJ_SPIDX_STRING t0 WHERE ((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?))'
|
||||||
|
single join, Patient?name=smith&active=true ,'SELECT t1.RES_ID FROM HFJ_RESOURCE t1 INNER JOIN HFJ_SPIDX_STRING t0 ON (t1.RES_ID = t0.RES_ID) INNER JOIN HFJ_SPIDX_TOKEN t2 ON (t1.RES_ID = t2.RES_ID) WHERE (((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?)) AND (t2.HASH_VALUE = ?))'
|
||||||
|
not, Encounter?class:not=not-there ,'SELECT t0.RES_ID FROM HFJ_RESOURCE t0 WHERE (((t0.RES_TYPE = ?) AND (t0.RES_DELETED_AT IS NULL)) AND ((t0.RES_ID) NOT IN (SELECT t0.RES_ID FROM HFJ_SPIDX_TOKEN t0 WHERE (t0.HASH_VALUE = ?)) ))'
|
||||||
|
not in chain, Observation?encounter.class:not=not-there ,'SELECT t0.SRC_RESOURCE_ID FROM HFJ_RES_LINK t0 WHERE ((t0.SRC_PATH = ?) AND ((t0.TARGET_RESOURCE_ID) NOT IN (SELECT t0.RES_ID FROM HFJ_SPIDX_TOKEN t0 WHERE (t0.HASH_VALUE = ?)) ))'
|
||||||
|
bare sort, Patient?_sort=name ,'SELECT t0.RES_ID FROM HFJ_RESOURCE t0 LEFT OUTER JOIN HFJ_SPIDX_STRING t1 ON ((t0.RES_ID = t1.RES_ID) AND (t1.HASH_IDENTITY = ?)) WHERE ((t0.RES_TYPE = ?) AND (t0.RES_DELETED_AT IS NULL)) ORDER BY t1.SP_VALUE_NORMALIZED ASC NULLS LAST'
|
||||||
|
""")
|
||||||
|
public void testSqlGeneration(String theComment, String theFhirRestQuery, String theExpectedSql) {
|
||||||
|
// setup
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
|
||||||
|
// execute
|
||||||
|
myTestDaoSearch.searchForIds(theFhirRestQuery);
|
||||||
|
|
||||||
|
// verify
|
||||||
|
assertEquals(1, myCaptureQueriesListener.countSelectQueries());
|
||||||
|
String sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
|
||||||
|
assertEquals(theExpectedSql, sql, theComment);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@CsvSource(textBlock = """
|
||||||
|
single- no hfj_resource,Patient?name=smith ,'SELECT t0.PARTITION_ID,t0.RES_ID FROM HFJ_SPIDX_STRING t0 WHERE ((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?))'
|
||||||
|
single join, Patient?name=smith&active=true ,'SELECT t1.PARTITION_ID,t1.RES_ID FROM HFJ_RESOURCE t1 INNER JOIN HFJ_SPIDX_STRING t0 ON ((t1.PARTITION_ID = t0.PARTITION_ID) AND (t1.RES_ID = t0.RES_ID)) INNER JOIN HFJ_SPIDX_TOKEN t2 ON ((t1.PARTITION_ID = t2.PARTITION_ID) AND (t1.RES_ID = t2.RES_ID)) WHERE (((t0.HASH_NORM_PREFIX = ?) AND (t0.SP_VALUE_NORMALIZED LIKE ?)) AND (t2.HASH_VALUE = ?))'
|
||||||
|
not, Encounter?class:not=not-there ,'SELECT t0.PARTITION_ID,t0.RES_ID FROM HFJ_RESOURCE t0 WHERE (((t0.RES_TYPE = ?) AND (t0.RES_DELETED_AT IS NULL)) AND ((t0.PARTITION_ID,t0.RES_ID) NOT IN (SELECT t0.PARTITION_ID,t0.RES_ID FROM HFJ_SPIDX_TOKEN t0 WHERE (t0.HASH_VALUE = ?)) ))'
|
||||||
|
not in chain, Observation?encounter.class:not=not-there ,'SELECT t0.PARTITION_ID,t0.SRC_RESOURCE_ID FROM HFJ_RES_LINK t0 WHERE ((t0.SRC_PATH = ?) AND ((t0.TARGET_RES_PARTITION_ID,t0.TARGET_RESOURCE_ID) NOT IN (SELECT t0.PARTITION_ID,t0.RES_ID FROM HFJ_SPIDX_TOKEN t0 WHERE (t0.HASH_VALUE = ?)) ))'
|
||||||
|
bare sort, Patient?_sort=name ,'SELECT t0.PARTITION_ID,t0.RES_ID FROM HFJ_RESOURCE t0 LEFT OUTER JOIN HFJ_SPIDX_STRING t1 ON ((t0.PARTITION_ID = t1.PARTITION_ID) AND (t0.RES_ID = t1.RES_ID) AND (t1.HASH_IDENTITY = ?)) WHERE ((t0.RES_TYPE = ?) AND (t0.RES_DELETED_AT IS NULL)) ORDER BY t1.SP_VALUE_NORMALIZED ASC NULLS LAST'
|
||||||
|
""")
|
||||||
|
public void testSqlGenerationWithPartitionJoins(String theComment, String theFhirRestQuery, String theExpectedSql) {
|
||||||
|
// setup
|
||||||
|
myPartitionSettings.setDefaultPartitionId(0);
|
||||||
|
myPartitionSettings.setPartitionIdsInPrimaryKeys(true);
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
|
||||||
|
// execute
|
||||||
|
myTestDaoSearch.searchForIds(theFhirRestQuery);
|
||||||
|
|
||||||
|
// verify
|
||||||
|
assertEquals(1, myCaptureQueriesListener.countSelectQueries());
|
||||||
|
String sql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(false, false);
|
||||||
|
assertEquals(theExpectedSql, sql, theComment);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Two regular search params - Should use HFJ_RESOURCE as root
|
* Two regular search params - Should use HFJ_RESOURCE as root
|
||||||
*/
|
*/
|
||||||
|
@ -66,8 +120,6 @@ public class FhirResourceDaoR4SearchSqlTest extends BaseJpaR4Test {
|
||||||
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) INNER JOIN HFJ_SPIDX_TOKEN t2 ON (t1.RES_ID = t2.RES_ID) 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.RES_ID = t0.RES_ID) INNER JOIN HFJ_SPIDX_TOKEN t2 ON (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
|
||||||
|
|
|
@ -49,7 +49,7 @@ public abstract class BaseSearchQueryBuilderDialectTest {
|
||||||
when(mySqlObjectFactory.dateIndexTable(any())).thenReturn(new DatePredicateBuilder(searchQueryBuilder));
|
when(mySqlObjectFactory.dateIndexTable(any())).thenReturn(new DatePredicateBuilder(searchQueryBuilder));
|
||||||
|
|
||||||
BaseJoiningPredicateBuilder firstPredicateBuilder = searchQueryBuilder.getOrCreateFirstPredicateBuilder();
|
BaseJoiningPredicateBuilder firstPredicateBuilder = searchQueryBuilder.getOrCreateFirstPredicateBuilder();
|
||||||
DatePredicateBuilder sortPredicateBuilder = searchQueryBuilder.addDatePredicateBuilder(firstPredicateBuilder.getResourceIdColumn());
|
DatePredicateBuilder sortPredicateBuilder = searchQueryBuilder.addDatePredicateBuilder(firstPredicateBuilder.getJoinColumns());
|
||||||
|
|
||||||
Condition hashIdentityPredicate = sortPredicateBuilder.createHashIdentityPredicate("MolecularSequence", "variant-start");
|
Condition hashIdentityPredicate = sortPredicateBuilder.createHashIdentityPredicate("MolecularSequence", "variant-start");
|
||||||
searchQueryBuilder.addPredicate(hashIdentityPredicate);
|
searchQueryBuilder.addPredicate(hashIdentityPredicate);
|
||||||
|
|
|
@ -63,7 +63,7 @@ public class SearchQueryBuilderDialectMySqlTest extends BaseSearchQueryBuilderDi
|
||||||
when(mySqlObjectFactory.stringIndexTable(any())).thenReturn(new StringPredicateBuilder(searchQueryBuilder));
|
when(mySqlObjectFactory.stringIndexTable(any())).thenReturn(new StringPredicateBuilder(searchQueryBuilder));
|
||||||
|
|
||||||
BaseJoiningPredicateBuilder firstPredicateBuilder = searchQueryBuilder.getOrCreateFirstPredicateBuilder();
|
BaseJoiningPredicateBuilder firstPredicateBuilder = searchQueryBuilder.getOrCreateFirstPredicateBuilder();
|
||||||
StringPredicateBuilder sortPredicateBuilder = searchQueryBuilder.addStringPredicateBuilder(firstPredicateBuilder.getResourceIdColumn());
|
StringPredicateBuilder sortPredicateBuilder = searchQueryBuilder.addStringPredicateBuilder(firstPredicateBuilder.getJoinColumns());
|
||||||
|
|
||||||
Condition hashIdentityPredicate = sortPredicateBuilder.createHashIdentityPredicate("patient", "family");
|
Condition hashIdentityPredicate = sortPredicateBuilder.createHashIdentityPredicate("patient", "family");
|
||||||
searchQueryBuilder.addPredicate(hashIdentityPredicate);
|
searchQueryBuilder.addPredicate(hashIdentityPredicate);
|
||||||
|
@ -112,7 +112,7 @@ public class SearchQueryBuilderDialectMySqlTest extends BaseSearchQueryBuilderDi
|
||||||
when(mySqlObjectFactory.dateIndexTable(any())).thenReturn(new DatePredicateBuilder(searchQueryBuilder));
|
when(mySqlObjectFactory.dateIndexTable(any())).thenReturn(new DatePredicateBuilder(searchQueryBuilder));
|
||||||
|
|
||||||
BaseJoiningPredicateBuilder firstPredicateBuilder = searchQueryBuilder.getOrCreateFirstPredicateBuilder();
|
BaseJoiningPredicateBuilder firstPredicateBuilder = searchQueryBuilder.getOrCreateFirstPredicateBuilder();
|
||||||
DatePredicateBuilder sortPredicateBuilder = searchQueryBuilder.addDatePredicateBuilder(firstPredicateBuilder.getResourceIdColumn());
|
DatePredicateBuilder sortPredicateBuilder = searchQueryBuilder.addDatePredicateBuilder(firstPredicateBuilder.getJoinColumns());
|
||||||
|
|
||||||
Condition hashIdentityPredicate = sortPredicateBuilder.createHashIdentityPredicate("patient", "birthdate");
|
Condition hashIdentityPredicate = sortPredicateBuilder.createHashIdentityPredicate("patient", "birthdate");
|
||||||
searchQueryBuilder.addPredicate(hashIdentityPredicate);
|
searchQueryBuilder.addPredicate(hashIdentityPredicate);
|
||||||
|
|
Loading…
Reference in New Issue