extractResourceLinks(IBaseResource theResource, boolean theWantLocalReferences);
@@ -130,6 +129,20 @@ public interface ISearchParamExtractor {
String getDisplayTextFromCodeableConcept(IBase theValue);
+ @FunctionalInterface
+ interface ISearchParamFilter {
+
+ /**
+ * Given the list of search parameters for indexing, an implementation of this
+ * interface may selectively remove any that it wants to remove (or can add if desired).
+ *
+ * Implementations must not modify the list that is passed in. If changes are
+ * desired, a new list must be created and returned.
+ */
+ Collection filterSearchParams(Collection theSearchParams);
+
+ }
+
class SearchParamSet extends HashSet {
private List myWarnings;
diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ResourceIndexedSearchParams.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ResourceIndexedSearchParams.java
index 5610f1f63dd..e847757dbd1 100644
--- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ResourceIndexedSearchParams.java
+++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ResourceIndexedSearchParams.java
@@ -59,6 +59,7 @@ public final class ResourceIndexedSearchParams {
final public Collection myComboTokenNonUnique = new HashSet<>();
final public Collection myLinks = new HashSet<>();
final public Set myPopulatedResourceLinkParameters = new HashSet<>();
+ final public Collection mySearchParamPresentEntities = new HashSet<>();
final public Collection myCompositeParams = new HashSet<>();
public ResourceIndexedSearchParams() {
@@ -116,6 +117,7 @@ public final class ResourceIndexedSearchParams {
theEntity.setParamsUriPopulated(myUriParams.isEmpty() == false);
theEntity.setParamsCoordsPopulated(myCoordsParams.isEmpty() == false);
theEntity.setParamsComboStringUniquePresent(myComboStringUniques.isEmpty() == false);
+ theEntity.setParamsComboTokensNonUniquePresent(myComboTokenNonUnique.isEmpty() == false);
theEntity.setHasLinks(myLinks.isEmpty() == false);
}
diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/SearchParamExtractorService.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/SearchParamExtractorService.java
index bf19c243652..80d726737fa 100644
--- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/SearchParamExtractorService.java
+++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/SearchParamExtractorService.java
@@ -47,9 +47,9 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
+import ca.uhn.fhir.jpa.model.entity.SearchParamPresentEntity;
import ca.uhn.fhir.jpa.model.entity.StorageSettings;
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
-import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
@@ -57,6 +57,7 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.rest.server.util.CompositeInterceptorBroadcaster;
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
+import ca.uhn.fhir.rest.server.util.ResourceSearchParams;
import ca.uhn.fhir.util.FhirTerser;
import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.lang3.StringUtils;
@@ -70,10 +71,13 @@ import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
@@ -94,8 +98,6 @@ public class SearchParamExtractorService {
private PartitionSettings myPartitionSettings;
@Autowired(required = false)
private IResourceLinkResolver myResourceLinkResolver;
- @Autowired
- private IRequestPartitionHelperSvc myPartitionHelperSvc;
@VisibleForTesting
public void setSearchParamExtractor(ISearchParamExtractor theSearchParamExtractor) {
@@ -104,7 +106,7 @@ public class SearchParamExtractorService {
public void extractFromResource(RequestPartitionId theRequestPartitionId, RequestDetails theRequestDetails, ResourceIndexedSearchParams theParams, ResourceTable theEntity, IBaseResource theResource, TransactionDetails theTransactionDetails, boolean theFailOnInvalidReference) {
- extractFromResource(theRequestPartitionId, theRequestDetails, theParams, new ResourceIndexedSearchParams(), theEntity, theResource, theTransactionDetails, theFailOnInvalidReference);
+ extractFromResource(theRequestPartitionId, theRequestDetails, theParams, new ResourceIndexedSearchParams(), theEntity, theResource, theTransactionDetails, theFailOnInvalidReference, ISearchParamExtractor.ALL_PARAMS);
}
/**
@@ -113,11 +115,11 @@ public class SearchParamExtractorService {
* a given resource type, it extracts the associated indexes and populates
* {@literal theParams}.
*/
- public void extractFromResource(RequestPartitionId theRequestPartitionId, RequestDetails theRequestDetails, ResourceIndexedSearchParams theNewParams, ResourceIndexedSearchParams theExistingParams, ResourceTable theEntity, IBaseResource theResource, TransactionDetails theTransactionDetails, boolean theFailOnInvalidReference) {
+ public void extractFromResource(RequestPartitionId theRequestPartitionId, RequestDetails theRequestDetails, ResourceIndexedSearchParams theNewParams, ResourceIndexedSearchParams theExistingParams, ResourceTable theEntity, IBaseResource theResource, TransactionDetails theTransactionDetails, boolean theFailOnInvalidReference, @Nonnull ISearchParamExtractor.ISearchParamFilter theSearchParamFilter) {
// All search parameter types except Reference
ResourceIndexedSearchParams normalParams = new ResourceIndexedSearchParams();
- extractSearchIndexParameters(theRequestDetails, normalParams, theResource, ISearchParamExtractor.ALL_PARAMS);
+ extractSearchIndexParameters(theRequestDetails, normalParams, theResource, theSearchParamFilter);
mergeParams(normalParams, theNewParams);
boolean indexOnContainedResources = myStorageSettings.isIndexOnContainedResources();
@@ -146,9 +148,51 @@ public class SearchParamExtractorService {
extractResourceLinksForContainedResources(theRequestPartitionId, theNewParams, theEntity, theResource, theTransactionDetails, theFailOnInvalidReference, theRequestDetails);
}
+ // Missing (:missing) Indexes - These are indexes to satisfy the :missing
+ // modifier
+ if (myStorageSettings.getIndexMissingFields() == StorageSettings.IndexEnabledEnum.ENABLED) {
+
+ // References
+ Map presenceMap = getReferenceSearchParamPresenceMap(theEntity, theNewParams);
+ presenceMap.forEach((key, value) -> {
+ SearchParamPresentEntity present = new SearchParamPresentEntity();
+ present.setPartitionSettings(myPartitionSettings);
+ present.setResource(theEntity);
+ present.setParamName(key);
+ present.setPresent(value);
+ present.setPartitionId(theEntity.getPartitionId());
+ present.calculateHashes();
+ theNewParams.mySearchParamPresentEntities.add(present);
+ });
+
+ // Everything else
+ ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams(theEntity.getResourceType());
+ theNewParams.findMissingSearchParams(myPartitionSettings, myStorageSettings, theEntity, activeSearchParams);
+ }
+
+ extractSearchParamComboUnique(theEntity, theNewParams);
+
+ extractSearchParamComboNonUnique(theEntity, theNewParams);
+
theNewParams.setUpdatedTime(theTransactionDetails.getTransactionDate());
}
+ @Nonnull
+ private Map getReferenceSearchParamPresenceMap(ResourceTable entity, ResourceIndexedSearchParams newParams) {
+ Map retval = new HashMap<>();
+
+ for (String nextKey : newParams.getPopulatedResourceLinkParameters()) {
+ retval.put(nextKey, Boolean.TRUE);
+ }
+
+ ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams(entity.getResourceType());
+ activeSearchParams
+ .getReferenceSearchParamNames()
+ .forEach(key -> retval.putIfAbsent(key, Boolean.FALSE));
+ return retval;
+ }
+
+
@VisibleForTesting
public void setStorageSettings(StorageSettings theStorageSettings) {
myStorageSettings = theStorageSettings;
@@ -169,8 +213,9 @@ public class SearchParamExtractorService {
// Extract search parameters
IChainedSearchParameterExtractionStrategy strategy = new IChainedSearchParameterExtractionStrategy() {
+ @Nonnull
@Override
- public Set getChainedSearchParametersToIndexForPath(PathAndRef thePathAndRef) {
+ public ISearchParamExtractor.ISearchParamFilter getSearchParamFilter(@Nonnull PathAndRef thePathAndRef) {
// Currently for contained resources we always index all search parameters
// on all contained resources. A potential nice future optimization would
// be to make this configurable, perhaps with an optional extension you could
@@ -179,7 +224,7 @@ public class SearchParamExtractorService {
}
@Override
- public IBaseResource fetchResourceAtPath(PathAndRef thePathAndRef) {
+ public IBaseResource fetchResourceAtPath(@Nonnull PathAndRef thePathAndRef) {
return findContainedResource(containedResources, thePathAndRef.getRef());
}
};
@@ -197,15 +242,23 @@ public class SearchParamExtractorService {
private void extractSearchIndexParametersForUpliftedRefchains(RequestDetails theRequestDetails, ResourceIndexedSearchParams theParams, ResourceTable theEntity, RequestPartitionId theRequestPartitionId, TransactionDetails theTransactionDetails, ISearchParamExtractor.SearchParamSet theIndexedReferences) {
IChainedSearchParameterExtractionStrategy strategy = new IChainedSearchParameterExtractionStrategy() {
+ @Nonnull
@Override
- public Set getChainedSearchParametersToIndexForPath(PathAndRef thePathAndRef) {
+ public ISearchParamExtractor.ISearchParamFilter getSearchParamFilter(@Nonnull PathAndRef thePathAndRef) {
String searchParamName = thePathAndRef.getSearchParamName();
RuntimeSearchParam searchParam = mySearchParamRegistry.getActiveSearchParam(theEntity.getResourceType(), searchParamName);
- return searchParam.getUpliftRefchainCodes();
+ Set upliftRefchainCodes = searchParam.getUpliftRefchainCodes();
+ if (upliftRefchainCodes.isEmpty()) {
+ return ISearchParamExtractor.NO_PARAMS;
+ }
+ return sp -> sp
+ .stream()
+ .filter(t -> upliftRefchainCodes.contains(t.getName()))
+ .collect(Collectors.toList());
}
@Override
- public IBaseResource fetchResourceAtPath(PathAndRef thePathAndRef) {
+ public IBaseResource fetchResourceAtPath(@Nonnull PathAndRef thePathAndRef) {
// The PathAndRef will contain a resource if the SP path was inside a Bundle
// and pointed to a resource (e.g. Bundle.entry.resource) as opposed to
// pointing to a reference (e.g. Observation.subject)
@@ -264,8 +317,8 @@ public class SearchParamExtractorService {
continue;
// 3.1.2 check if this ref actually applies here
- Set searchParamsToIndex = theTargetIndexingStrategy.getChainedSearchParametersToIndexForPath(nextPathAndRef);
- if (searchParamsToIndex.isEmpty()) {
+ ISearchParamExtractor.ISearchParamFilter searchParamsToIndex = theTargetIndexingStrategy.getSearchParamFilter(nextPathAndRef);
+ if (searchParamsToIndex == ISearchParamExtractor.NO_PARAMS) {
continue;
}
@@ -332,42 +385,42 @@ public class SearchParamExtractorService {
theTargetParams.myCompositeParams.addAll(theSrcParams.myCompositeParams);
}
- void extractSearchIndexParameters(RequestDetails theRequestDetails, ResourceIndexedSearchParams theParams, IBaseResource theResource, Set theParamsToIndex) {
+ void extractSearchIndexParameters(RequestDetails theRequestDetails, ResourceIndexedSearchParams theParams, IBaseResource theResource, @Nonnull ISearchParamExtractor.ISearchParamFilter theSearchParamFilter) {
// Strings
- ISearchParamExtractor.SearchParamSet strings = extractSearchParamStrings(theResource, theParamsToIndex);
+ ISearchParamExtractor.SearchParamSet strings = extractSearchParamStrings(theResource, theSearchParamFilter);
handleWarnings(theRequestDetails, myInterceptorBroadcaster, strings);
theParams.myStringParams.addAll(strings);
// Numbers
- ISearchParamExtractor.SearchParamSet numbers = extractSearchParamNumber(theResource, theParamsToIndex);
+ ISearchParamExtractor.SearchParamSet numbers = extractSearchParamNumber(theResource, theSearchParamFilter);
handleWarnings(theRequestDetails, myInterceptorBroadcaster, numbers);
theParams.myNumberParams.addAll(numbers);
// Quantities
- ISearchParamExtractor.SearchParamSet quantities = extractSearchParamQuantity(theResource, theParamsToIndex);
+ ISearchParamExtractor.SearchParamSet quantities = extractSearchParamQuantity(theResource, theSearchParamFilter);
handleWarnings(theRequestDetails, myInterceptorBroadcaster, quantities);
theParams.myQuantityParams.addAll(quantities);
if (myStorageSettings.getNormalizedQuantitySearchLevel().equals(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_STORAGE_SUPPORTED) || myStorageSettings.getNormalizedQuantitySearchLevel().equals(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED)) {
- ISearchParamExtractor.SearchParamSet quantitiesNormalized = extractSearchParamQuantityNormalized(theResource, theParamsToIndex);
+ ISearchParamExtractor.SearchParamSet quantitiesNormalized = extractSearchParamQuantityNormalized(theResource, theSearchParamFilter);
handleWarnings(theRequestDetails, myInterceptorBroadcaster, quantitiesNormalized);
theParams.myQuantityNormalizedParams.addAll(quantitiesNormalized);
}
// Dates
- ISearchParamExtractor.SearchParamSet dates = extractSearchParamDates(theResource, theParamsToIndex);
+ ISearchParamExtractor.SearchParamSet dates = extractSearchParamDates(theResource, theSearchParamFilter);
handleWarnings(theRequestDetails, myInterceptorBroadcaster, dates);
theParams.myDateParams.addAll(dates);
// URIs
- ISearchParamExtractor.SearchParamSet uris = extractSearchParamUri(theResource, theParamsToIndex);
+ ISearchParamExtractor.SearchParamSet uris = extractSearchParamUri(theResource, theSearchParamFilter);
handleWarnings(theRequestDetails, myInterceptorBroadcaster, uris);
theParams.myUriParams.addAll(uris);
// Tokens (can result in both Token and String, as we index the display name for
// the types: Coding, CodeableConcept)
- ISearchParamExtractor.SearchParamSet tokens = extractSearchParamTokens(theResource, theParamsToIndex);
+ ISearchParamExtractor.SearchParamSet tokens = extractSearchParamTokens(theResource, theSearchParamFilter);
for (BaseResourceIndexedSearchParam next : tokens) {
if (next instanceof ResourceIndexedSearchParamToken) {
theParams.myTokenParams.add((ResourceIndexedSearchParamToken) next);
@@ -381,13 +434,13 @@ public class SearchParamExtractorService {
// Composites
// dst2 composites use stuff like value[x] , and we don't support them.
if (myContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3)) {
- ISearchParamExtractor.SearchParamSet composites = extractSearchParamComposites(theResource, theParamsToIndex);
+ ISearchParamExtractor.SearchParamSet composites = extractSearchParamComposites(theResource, theSearchParamFilter);
handleWarnings(theRequestDetails, myInterceptorBroadcaster, composites);
theParams.myCompositeParams.addAll(composites);
}
// Specials
- ISearchParamExtractor.SearchParamSet specials = extractSearchParamSpecial(theResource, theParamsToIndex);
+ ISearchParamExtractor.SearchParamSet specials = extractSearchParamSpecial(theResource, theSearchParamFilter);
for (BaseResourceIndexedSearchParam next : specials) {
if (next instanceof ResourceIndexedSearchParamCoords) {
theParams.myCoordsParams.add((ResourceIndexedSearchParamCoords) next);
@@ -543,7 +596,7 @@ public class SearchParamExtractorService {
*/
myResourceLinkResolver.validateTypeOrThrowException(type);
- /**
+ /*
* We need to obtain a resourceLink out of the provided {@literal thePathAndRef}. In the case
* where we are updating a resource that already has resourceLinks (stored in {@literal theExistingParams.getResourceLinks()}),
* let's try to match thePathAndRef to an already existing resourceLink to avoid the
@@ -664,9 +717,8 @@ public class SearchParamExtractorService {
}
}
+ @SuppressWarnings("unchecked")
private ResourceLink resolveTargetAndCreateResourceLinkOrReturnNull(@Nonnull RequestPartitionId theRequestPartitionId, String theSourceResourceName, PathAndRef thePathAndRef, ResourceTable theEntity, Date theUpdateTime, IIdType theNextId, RequestDetails theRequest, TransactionDetails theTransactionDetails) {
- assert theRequestPartitionId != null;
-
JpaPid resolvedResourceId = (JpaPid) theTransactionDetails.getResolvedResourceId(theNextId);
if (resolvedResourceId != null) {
String targetResourceType = theNextId.getResourceType();
@@ -742,40 +794,40 @@ public class SearchParamExtractorService {
}
}
- private ISearchParamExtractor.SearchParamSet extractSearchParamDates(IBaseResource theResource, Set theParamsToIndex) {
- return mySearchParamExtractor.extractSearchParamDates(theResource, theParamsToIndex);
+ private ISearchParamExtractor.SearchParamSet extractSearchParamDates(IBaseResource theResource, ISearchParamExtractor.ISearchParamFilter theSearchParamFilter) {
+ return mySearchParamExtractor.extractSearchParamDates(theResource, theSearchParamFilter);
}
- private ISearchParamExtractor.SearchParamSet extractSearchParamNumber(IBaseResource theResource, Set theParamsToIndex) {
- return mySearchParamExtractor.extractSearchParamNumber(theResource, theParamsToIndex);
+ private ISearchParamExtractor.SearchParamSet extractSearchParamNumber(IBaseResource theResource, ISearchParamExtractor.ISearchParamFilter theSearchParamFilter) {
+ return mySearchParamExtractor.extractSearchParamNumber(theResource, theSearchParamFilter);
}
- private ISearchParamExtractor.SearchParamSet extractSearchParamQuantity(IBaseResource theResource, Set theParamsToIndex) {
- return mySearchParamExtractor.extractSearchParamQuantity(theResource, theParamsToIndex);
+ private ISearchParamExtractor.SearchParamSet extractSearchParamQuantity(IBaseResource theResource, ISearchParamExtractor.ISearchParamFilter theSearchParamFilter) {
+ return mySearchParamExtractor.extractSearchParamQuantity(theResource, theSearchParamFilter);
}
- private ISearchParamExtractor.SearchParamSet extractSearchParamQuantityNormalized(IBaseResource theResource, Set theParamsToIndex) {
- return mySearchParamExtractor.extractSearchParamQuantityNormalized(theResource, theParamsToIndex);
+ private ISearchParamExtractor.SearchParamSet extractSearchParamQuantityNormalized(IBaseResource theResource, ISearchParamExtractor.ISearchParamFilter theSearchParamFilter) {
+ return mySearchParamExtractor.extractSearchParamQuantityNormalized(theResource, theSearchParamFilter);
}
- private ISearchParamExtractor.SearchParamSet extractSearchParamStrings(IBaseResource theResource, Set theParamsToIndex) {
- return mySearchParamExtractor.extractSearchParamStrings(theResource, theParamsToIndex);
+ private ISearchParamExtractor.SearchParamSet extractSearchParamStrings(IBaseResource theResource, ISearchParamExtractor.ISearchParamFilter theSearchParamFilter) {
+ return mySearchParamExtractor.extractSearchParamStrings(theResource, theSearchParamFilter);
}
- private ISearchParamExtractor.SearchParamSet extractSearchParamTokens(IBaseResource theResource, Set theParamsToIndex) {
- return mySearchParamExtractor.extractSearchParamTokens(theResource, theParamsToIndex);
+ private ISearchParamExtractor.SearchParamSet extractSearchParamTokens(IBaseResource theResource, ISearchParamExtractor.ISearchParamFilter theSearchParamFilter) {
+ return mySearchParamExtractor.extractSearchParamTokens(theResource, theSearchParamFilter);
}
- private ISearchParamExtractor.SearchParamSet extractSearchParamSpecial(IBaseResource theResource, Set theParamsToIndex) {
- return mySearchParamExtractor.extractSearchParamSpecial(theResource, theParamsToIndex);
+ private ISearchParamExtractor.SearchParamSet extractSearchParamSpecial(IBaseResource theResource, ISearchParamExtractor.ISearchParamFilter theSearchParamFilter) {
+ return mySearchParamExtractor.extractSearchParamSpecial(theResource, theSearchParamFilter);
}
- private ISearchParamExtractor.SearchParamSet extractSearchParamUri(IBaseResource theResource, Set theParamsToIndex) {
- return mySearchParamExtractor.extractSearchParamUri(theResource, theParamsToIndex);
+ private ISearchParamExtractor.SearchParamSet extractSearchParamUri(IBaseResource theResource, ISearchParamExtractor.ISearchParamFilter theSearchParamFilter) {
+ return mySearchParamExtractor.extractSearchParamUri(theResource, theSearchParamFilter);
}
- private ISearchParamExtractor.SearchParamSet extractSearchParamComposites(IBaseResource theResource, Set theParamsToIndex) {
- return mySearchParamExtractor.extractSearchParamComposites(theResource, theParamsToIndex);
+ private ISearchParamExtractor.SearchParamSet extractSearchParamComposites(IBaseResource theResource, ISearchParamExtractor.ISearchParamFilter theSearchParamFilter) {
+ return mySearchParamExtractor.extractSearchParamComposites(theResource, theSearchParamFilter);
}
@VisibleForTesting
@@ -812,12 +864,13 @@ public class SearchParamExtractorService {
/**
* Which search parameters should be indexed for the resource target
* at the given path. In other words if thePathAndRef contains
- * "Patient/123", then we could return a Set containing "name" and "gender"
- * if we only want those two parameters to be indexed for the
- * resolved Patient resource with that ID.
+ * "Patient/123", then we could return a filter that only lets the
+ * "name" and "gender" search params through if we only want those
+ * two parameters to be indexed for the resolved Patient resource
+ * with that ID.
*/
@Nonnull
- Set getChainedSearchParametersToIndexForPath(@Nonnull PathAndRef thePathAndRef);
+ ISearchParamExtractor.ISearchParamFilter getSearchParamFilter(@Nonnull PathAndRef thePathAndRef);
/**
* Actually fetch the resource at the given path, or return
diff --git a/hapi-fhir-jpaserver-subscription/pom.xml b/hapi-fhir-jpaserver-subscription/pom.xml
index 769de666558..75251619e01 100644
--- a/hapi-fhir-jpaserver-subscription/pom.xml
+++ b/hapi-fhir-jpaserver-subscription/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.5.11-SNAPSHOT
+ 6.5.12-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-dstu2/pom.xml b/hapi-fhir-jpaserver-test-dstu2/pom.xml
index ed11b71f83d..7f30b4b2f17 100644
--- a/hapi-fhir-jpaserver-test-dstu2/pom.xml
+++ b/hapi-fhir-jpaserver-test-dstu2/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.5.11-SNAPSHOT
+ 6.5.12-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-dstu3/pom.xml b/hapi-fhir-jpaserver-test-dstu3/pom.xml
index af7dac0133b..0060faff615 100644
--- a/hapi-fhir-jpaserver-test-dstu3/pom.xml
+++ b/hapi-fhir-jpaserver-test-dstu3/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.5.11-SNAPSHOT
+ 6.5.12-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-r4/pom.xml b/hapi-fhir-jpaserver-test-r4/pom.xml
index 13e6ff0daaa..a45893bb3b3 100644
--- a/hapi-fhir-jpaserver-test-r4/pom.xml
+++ b/hapi-fhir-jpaserver-test-r4/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.5.11-SNAPSHOT
+ 6.5.12-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ComboNonUniqueParamTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ComboNonUniqueParamTest.java
index 1d9bc6dde35..9e985d8fa04 100644
--- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ComboNonUniqueParamTest.java
+++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ComboNonUniqueParamTest.java
@@ -28,8 +28,10 @@ import java.util.Comparator;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.in;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -167,6 +169,59 @@ public class FhirResourceDaoR4ComboNonUniqueParamTest extends BaseComboParamsR4T
}
+ @Test
+ public void testCreateAndUpdateResource() {
+ createNamesAndGenderSp();
+
+ // Create a resource patching the unique SP
+ myCaptureQueriesListener.clear();
+ IIdType id1 = createPatient1();
+ assertNotNull(id1);
+
+ assertEquals(0, myCaptureQueriesListener.countSelectQueries());
+ assertEquals(12, myCaptureQueriesListener.countInsertQueries());
+ assertEquals(0, myCaptureQueriesListener.countUpdateQueries());
+ assertEquals(0, myCaptureQueriesListener.countDeleteQueries());
+ assertEquals(1, myCaptureQueriesListener.countCommits());
+ assertEquals(0, myCaptureQueriesListener.countRollbacks());
+
+ runInTransaction(()->{
+ List indexes = myResourceIndexedComboTokensNonUniqueDao
+ .findAll()
+ .stream()
+ .map(ResourceIndexedComboTokenNonUnique::getIndexString)
+ .toList();
+ assertThat(indexes.toString(), indexes, contains("Patient?family=FAMILY1%5C%7C&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale&given=GIVEN1"));
+ });
+
+ /*
+ * Now update the resource
+ */
+
+ Patient patient = myPatientDao.read(id1, mySrd);
+ patient.getNameFirstRep().setFamily("Family2");
+
+ myCaptureQueriesListener.clear();
+ myPatientDao.update(patient, mySrd);
+
+ assertEquals(6, myCaptureQueriesListener.countSelectQueries());
+ assertEquals(1, myCaptureQueriesListener.countInsertQueries());
+ assertEquals(5, myCaptureQueriesListener.countUpdateQueries());
+ assertEquals(0, myCaptureQueriesListener.countDeleteQueries());
+ assertEquals(1, myCaptureQueriesListener.countCommits());
+ assertEquals(0, myCaptureQueriesListener.countRollbacks());
+
+ runInTransaction(()->{
+ List indexes = myResourceIndexedComboTokensNonUniqueDao
+ .findAll()
+ .stream()
+ .map(ResourceIndexedComboTokenNonUnique::getIndexString)
+ .toList();
+ assertThat(indexes.toString(), indexes, contains("Patient?family=FAMILY2%5C%7C&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale&given=GIVEN1"));
+ });
+
+ }
+
@Test
public void testSearchWithExtraParameters() {
createNamesAndGenderSp();
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QueryCountTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QueryCountTest.java
index 2f88b3db09e..0db25d40305 100644
--- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QueryCountTest.java
+++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QueryCountTest.java
@@ -4,6 +4,7 @@ import ca.uhn.fhir.context.support.ValidationSupportContext;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.api.model.HistoryCountModeEnum;
+import ca.uhn.fhir.jpa.dao.data.ISearchParamPresentDao;
import ca.uhn.fhir.jpa.entity.TermValueSet;
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
import ca.uhn.fhir.jpa.model.entity.ForcedId;
@@ -54,6 +55,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice;
import org.springframework.util.comparator.ComparableComparator;
@@ -79,9 +81,25 @@ import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
+/**
+ * Note about this test class:
+ *
+ * This entire test class is a regression test - The aim here is to make sure that
+ * changes we make don't inadvertently add additional database operations. The
+ * various test perform different kinds of actions and then check the numbers of
+ * SQL selects, inserts, etc. The various numbers are arbitrary, but the point of
+ * this test is that if you make a change and suddenly one of these tests shows
+ * that a new SQL statement has been added, it is critical that you identify why
+ * that change has happened and work out if it is absolutely necessary. Every
+ * single individual SQL statement adds up when we're doing operations at scale,
+ * so don't ever blindly adjust numbers in this test without figuring out why.
+ */
+@SuppressWarnings("JavadocBlankLines")
@TestMethodOrder(MethodOrderer.MethodName.class)
public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4QueryCountTest.class);
+ @Autowired
+ private ISearchParamPresentDao mySearchParamPresentDao;
@AfterEach
public void afterResetDao() {
@@ -113,7 +131,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
myValidationSupport.fetchAllStructureDefinitions();
}
-
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testUpdateWithNoChanges() {
IIdType id = runInTransaction(() -> {
@@ -137,7 +157,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
}
-
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testUpdateWithChanges() {
IIdType id = runInTransaction(() -> {
@@ -163,6 +185,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testUpdateGroup_withAddedReferences_willSucceed() {
int initialPatientsCount = 30;
@@ -186,6 +211,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testUpdateGroup_NoChangesToReferences() {
List patientList = createPatients(30);
@@ -208,6 +236,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testUpdateWithChangesAndTags() {
myStorageSettings.setTagStorageMode(JpaStorageSettings.TagStorageModeEnum.NON_VERSIONED);
@@ -241,7 +272,83 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
+ @Test
+ public void testUpdateWithIndexMissingFieldsEnabled() {
+ myStorageSettings.setIndexMissingFields(JpaStorageSettings.IndexEnabledEnum.ENABLED);
+ IIdType id = runInTransaction(() -> {
+ Patient p = new Patient();
+ p.addIdentifier().setSystem("urn:system").setValue("2");
+ p.addName().setFamily("FAMILY");
+ myCaptureQueriesListener.clear();
+ return myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
+ });
+ assertEquals(0, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
+ assertEquals(0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size());
+ assertEquals(6, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size());
+ assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
+ assertEquals(1, myCaptureQueriesListener.countCommits());
+ assertEquals(0, myCaptureQueriesListener.countRollbacks());
+
+ runInTransaction(() -> {
+ assertEquals(9, myResourceIndexedSearchParamStringDao.count());
+ assertEquals(9, myResourceIndexedSearchParamTokenDao.count());
+ assertEquals(3, mySearchParamPresentDao.count());
+ });
+
+ // Now update with one additional string index
+
+ runInTransaction(() -> {
+ Patient p = new Patient();
+ p.setId(id);
+ p.addIdentifier().setSystem("urn:system").setValue("2");
+ p.addName().setFamily("FAMILY").addGiven("GIVEN");
+ myCaptureQueriesListener.clear();
+ myPatientDao.update(p, mySrd);
+ });
+ assertEquals(6, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
+ assertEquals(2, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size());
+ assertEquals(2, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size());
+ assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
+ assertEquals(1, myCaptureQueriesListener.countCommits());
+ assertEquals(0, myCaptureQueriesListener.countRollbacks());
+
+ runInTransaction(() -> {
+ assertEquals(11, myResourceIndexedSearchParamStringDao.count());
+ assertEquals(9, myResourceIndexedSearchParamTokenDao.count());
+ assertEquals(3, mySearchParamPresentDao.count());
+ });
+
+ // Now update with no changes
+
+ runInTransaction(() -> {
+ Patient p = new Patient();
+ p.setId(id);
+ p.addIdentifier().setSystem("urn:system").setValue("2");
+ p.addName().setFamily("FAMILY").addGiven("GIVEN");
+ myCaptureQueriesListener.clear();
+ myPatientDao.update(p, mySrd);
+ });
+ assertEquals(5, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
+ assertEquals(0, myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size());
+ assertEquals(0, myCaptureQueriesListener.getInsertQueriesForCurrentThread().size());
+ assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
+ assertEquals(1, myCaptureQueriesListener.countCommits());
+ assertEquals(0, myCaptureQueriesListener.countRollbacks());
+
+ runInTransaction(() -> {
+ assertEquals(11, myResourceIndexedSearchParamStringDao.count());
+ assertEquals(9, myResourceIndexedSearchParamTokenDao.count());
+ assertEquals(3, mySearchParamPresentDao.count());
+ });
+ }
+
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testUpdate_DeletesSearchUrlOnlyWhenPresent() {
@@ -273,6 +380,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testUpdate_DeletesSearchUrlOnlyWhenPresent_NonConditional() {
@@ -304,6 +414,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testRead() {
IIdType id = runInTransaction(() -> {
@@ -327,6 +440,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testValidate() {
@@ -379,6 +495,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testVRead() {
IIdType id = runInTransaction(() -> {
@@ -402,6 +521,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testCreateWithClientAssignedId() {
myStorageSettings.setIndexMissingFields(JpaStorageSettings.IndexEnabledEnum.DISABLED);
@@ -439,6 +561,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testCreateWithServerAssignedId_AnyClientAssignedIdStrategy() {
myStorageSettings.setResourceClientIdStrategy(JpaStorageSettings.ClientIdStrategyEnum.ANY);
@@ -470,10 +595,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
List resources = myResourceTableDao.findAll();
- String versions = "Resource Versions:\n * " + resources
- .stream()
- .map(t -> "Resource " + t.getIdDt() + " has version: " + t.getVersion())
- .collect(Collectors.joining("\n * "));
+ String versions = "Resource Versions:\n * " + resources.stream().map(t -> "Resource " + t.getIdDt() + " has version: " + t.getVersion()).collect(Collectors.joining("\n * "));
for (ResourceTable next : resources) {
assertEquals(1, next.getVersion(), versions);
@@ -490,6 +612,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testCreateWithClientAssignedId_AnyClientAssignedIdStrategy() {
myStorageSettings.setResourceClientIdStrategy(JpaStorageSettings.ClientIdStrategyEnum.ANY);
@@ -535,10 +660,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
List resources = myResourceTableDao.findAll();
- String versions = "Resource Versions:\n * " + resources
- .stream()
- .map(t -> "Resource " + t.getIdDt() + " has version: " + t.getVersion())
- .collect(Collectors.joining("\n * "));
+ String versions = "Resource Versions:\n * " + resources.stream().map(t -> "Resource " + t.getIdDt() + " has version: " + t.getVersion()).collect(Collectors.joining("\n * "));
for (ResourceTable next : resources) {
assertEquals(1, next.getVersion(), versions);
@@ -554,6 +676,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testCreateWithClientAssignedId_CheckDisabledMode() {
when(mySrd.getHeader(eq(JpaConstants.HEADER_UPSERT_EXISTENCE_CHECK))).thenReturn(JpaConstants.HEADER_UPSERT_EXISTENCE_CHECK_DISABLED);
@@ -576,6 +701,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testUpdateWithClientAssignedId_DeletesDisabled() {
myStorageSettings.setIndexMissingFields(JpaStorageSettings.IndexEnabledEnum.DISABLED);
@@ -629,6 +757,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testReferenceToForcedId() {
myStorageSettings.setIndexMissingFields(JpaStorageSettings.IndexEnabledEnum.DISABLED);
@@ -675,6 +806,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testReferenceToForcedId_DeletesDisabled() {
myStorageSettings.setIndexMissingFields(JpaStorageSettings.IndexEnabledEnum.DISABLED);
@@ -730,6 +864,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testHistory_Server() {
myStorageSettings.setHistoryCountMode(HistoryCountModeEnum.COUNT_ACCURATE);
@@ -788,6 +925,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
* This could definitely stand to be optimized some, since we load tags individually
* for each resource
*/
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testHistory_Server_WithTags() {
myStorageSettings.setHistoryCountMode(HistoryCountModeEnum.COUNT_ACCURATE);
@@ -847,6 +987,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testSearchAndPageThroughResults_SmallChunksOnSameBundleProvider() {
List ids = create150Patients();
@@ -871,6 +1014,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
assertEquals(0, myCaptureQueriesListener.getRollbackCount());
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testSearchAndPageThroughResults_LargeChunksOnIndependentBundleProvider() {
List ids = create150Patients();
@@ -893,6 +1039,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
assertEquals(0, myCaptureQueriesListener.getRollbackCount());
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testSearchAndPageThroughResults_LargeChunksOnSameBundleProvider_Synchronous() {
List ids = create150Patients();
@@ -930,6 +1079,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testSearchUsingOffsetMode_Explicit() {
for (int i = 0; i < 10; i++) {
@@ -943,17 +1095,8 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
// First page
myCaptureQueriesListener.clear();
- Bundle outcome = myClient
- .search()
- .forResource("Patient")
- .where(Patient.ACTIVE.exactly().code("true"))
- .offset(0)
- .count(5)
- .returnBundle(Bundle.class)
- .execute();
- assertThat(toUnqualifiedVersionlessIdValues(outcome).toString(), toUnqualifiedVersionlessIdValues(outcome), containsInAnyOrder(
- "Patient/A0", "Patient/A1", "Patient/A2", "Patient/A3", "Patient/A4"
- ));
+ Bundle outcome = myClient.search().forResource("Patient").where(Patient.ACTIVE.exactly().code("true")).offset(0).count(5).returnBundle(Bundle.class).execute();
+ assertThat(toUnqualifiedVersionlessIdValues(outcome).toString(), toUnqualifiedVersionlessIdValues(outcome), containsInAnyOrder("Patient/A0", "Patient/A1", "Patient/A2", "Patient/A3", "Patient/A4"));
myCaptureQueriesListener.logSelectQueries();
assertEquals(2, myCaptureQueriesListener.countSelectQueries());
assertThat(myCaptureQueriesListener.getSelectQueries().get(0).getSql(true, false), containsString("SELECT t0.RES_ID FROM HFJ_SPIDX_TOKEN t0"));
@@ -968,17 +1111,8 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
// Second page
myCaptureQueriesListener.clear();
- outcome = myClient
- .search()
- .forResource("Patient")
- .where(Patient.ACTIVE.exactly().code("true"))
- .offset(5)
- .count(5)
- .returnBundle(Bundle.class)
- .execute();
- assertThat(toUnqualifiedVersionlessIdValues(outcome).toString(), toUnqualifiedVersionlessIdValues(outcome), containsInAnyOrder(
- "Patient/A5", "Patient/A6", "Patient/A7", "Patient/A8", "Patient/A9"
- ));
+ outcome = myClient.search().forResource("Patient").where(Patient.ACTIVE.exactly().code("true")).offset(5).count(5).returnBundle(Bundle.class).execute();
+ assertThat(toUnqualifiedVersionlessIdValues(outcome).toString(), toUnqualifiedVersionlessIdValues(outcome), containsInAnyOrder("Patient/A5", "Patient/A6", "Patient/A7", "Patient/A8", "Patient/A9"));
myCaptureQueriesListener.logSelectQueries();
assertEquals(2, myCaptureQueriesListener.countSelectQueries());
assertThat(myCaptureQueriesListener.getSelectQueries().get(0).getSql(true, false), containsString("SELECT t0.RES_ID FROM HFJ_SPIDX_TOKEN t0"));
@@ -995,14 +1129,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
// Third page (no results)
myCaptureQueriesListener.clear();
- outcome = myClient
- .search()
- .forResource("Patient")
- .where(Patient.ACTIVE.exactly().code("true"))
- .offset(10)
- .count(5)
- .returnBundle(Bundle.class)
- .execute();
+ outcome = myClient.search().forResource("Patient").where(Patient.ACTIVE.exactly().code("true")).offset(10).count(5).returnBundle(Bundle.class).execute();
assertThat(toUnqualifiedVersionlessIdValues(outcome).toString(), toUnqualifiedVersionlessIdValues(outcome), empty());
myCaptureQueriesListener.logSelectQueries();
assertEquals(1, myCaptureQueriesListener.countSelectQueries());
@@ -1016,6 +1143,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testSearchUsingForcedIdReference() {
@@ -1056,6 +1186,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testSearchUsingForcedIdReference_DeletedDisabled() {
myStorageSettings.setDeleteEnabled(false);
@@ -1097,6 +1230,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testSearchOnChainedToken() {
Patient patient = new Patient();
@@ -1125,6 +1261,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testSearchOnReverseInclude() {
Patient patient = new Patient();
@@ -1153,18 +1292,12 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
myCareTeamDao.update(ct);
}
- SearchParameterMap map = SearchParameterMap
- .newSynchronous()
- .addRevInclude(CareTeam.INCLUDE_SUBJECT)
- .setSort(new SortSpec(Patient.SP_NAME));
+ SearchParameterMap map = SearchParameterMap.newSynchronous().addRevInclude(CareTeam.INCLUDE_SUBJECT).setSort(new SortSpec(Patient.SP_NAME));
myCaptureQueriesListener.clear();
IBundleProvider outcome = myPatientDao.search(map);
assertEquals(SimpleBundleProvider.class, outcome.getClass());
- assertThat(toUnqualifiedVersionlessIdValues(outcome), containsInAnyOrder(
- "Patient/P1", "CareTeam/CT1-0", "CareTeam/CT1-1", "CareTeam/CT1-2",
- "Patient/P2", "CareTeam/CT2-0", "CareTeam/CT2-1", "CareTeam/CT2-2"
- ));
+ assertThat(toUnqualifiedVersionlessIdValues(outcome), containsInAnyOrder("Patient/P1", "CareTeam/CT1-0", "CareTeam/CT1-1", "CareTeam/CT1-2", "Patient/P2", "CareTeam/CT2-0", "CareTeam/CT2-1", "CareTeam/CT2-2"));
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
assertEquals(4, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
@@ -1174,6 +1307,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testSearchWithMultipleIncludes_Async() {
// Setup
@@ -1205,6 +1341,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
});
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testSearchWithMultipleIncludesRecurse_Async() {
// Setup
@@ -1230,6 +1369,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testSearchWithMultipleIncludes_Sync() {
// Setup
@@ -1256,6 +1398,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testSearchWithMultipleIncludesRecurse_Sync() {
// Setup
@@ -1282,6 +1427,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
assertEquals(0, myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithMultipleCreates() {
myStorageSettings.setMassIngestionMode(true);
@@ -1348,6 +1496,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
return (Bundle) bb.getBundle();
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithMultipleCreates_PreExistingMatchUrl() {
myStorageSettings.setMassIngestionMode(true);
@@ -1398,6 +1549,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithTwoCreates() {
@@ -1431,6 +1585,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
runInTransaction(() -> assertEquals(2, myResourceTableDao.count()));
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithMultipleUpdates() {
@@ -1508,6 +1665,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithMultipleUpdates_ResourcesHaveTags() {
@@ -1591,6 +1751,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithMultipleInlineMatchUrls() {
myStorageSettings.setDeleteEnabled(false);
@@ -1637,6 +1800,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithMultipleInlineMatchUrlsWithAuthentication() {
myStorageSettings.setDeleteEnabled(false);
@@ -1688,6 +1854,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithMultipleForcedIdReferences() {
myStorageSettings.setDeleteEnabled(false);
@@ -1742,6 +1911,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithMultipleNumericIdReferences() {
myStorageSettings.setDeleteEnabled(false);
@@ -1794,6 +1966,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithMultipleConditionalUpdates() {
@@ -1904,6 +2079,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithConditionalCreate_MatchUrlCacheEnabled() {
myStorageSettings.setMatchUrlCacheEnabled(true);
@@ -1967,6 +2145,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithConditionalCreate_MatchUrlCacheNotEnabled() {
@@ -2034,6 +2215,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithCreateClientAssignedIdAndReference() {
myStorageSettings.setDeleteEnabled(false);
@@ -2043,22 +2227,12 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
Patient patient = new Patient();
patient.setId("Patient/A");
patient.setActive(true);
- input.addEntry()
- .setFullUrl(patient.getId())
- .setResource(patient)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.PUT)
- .setUrl("Patient/A");
+ input.addEntry().setFullUrl(patient.getId()).setResource(patient).getRequest().setMethod(Bundle.HTTPVerb.PUT).setUrl("Patient/A");
Observation observation = new Observation();
observation.setId(IdType.newRandomUuid());
observation.addReferenceRange().setText("A");
- input.addEntry()
- .setFullUrl(observation.getId())
- .setResource(observation)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("Observation");
+ input.addEntry().setFullUrl(observation.getId()).setResource(observation).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("Observation");
myCaptureQueriesListener.clear();
Bundle output = mySystemDao.transaction(mySrd, input);
@@ -2079,22 +2253,12 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
patient = new Patient();
patient.setId("Patient/A");
patient.setActive(true);
- input.addEntry()
- .setFullUrl(patient.getId())
- .setResource(patient)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.PUT)
- .setUrl("Patient/A");
+ input.addEntry().setFullUrl(patient.getId()).setResource(patient).getRequest().setMethod(Bundle.HTTPVerb.PUT).setUrl("Patient/A");
observation = new Observation();
observation.setId(IdType.newRandomUuid());
observation.addReferenceRange().setText("A");
- input.addEntry()
- .setFullUrl(observation.getId())
- .setResource(observation)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("Observation");
+ input.addEntry().setFullUrl(observation.getId()).setResource(observation).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("Observation");
myCaptureQueriesListener.clear();
output = mySystemDao.transaction(mySrd, input);
@@ -2112,6 +2276,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithMultipleReferences() {
Bundle input = new Bundle();
@@ -2119,22 +2286,12 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
Patient patient = new Patient();
patient.setId(IdType.newRandomUuid());
patient.setActive(true);
- input.addEntry()
- .setFullUrl(patient.getId())
- .setResource(patient)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("Patient");
+ input.addEntry().setFullUrl(patient.getId()).setResource(patient).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("Patient");
Practitioner practitioner = new Practitioner();
practitioner.setId(IdType.newRandomUuid());
practitioner.setActive(true);
- input.addEntry()
- .setFullUrl(practitioner.getId())
- .setResource(practitioner)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("Practitioner");
+ input.addEntry().setFullUrl(practitioner.getId()).setResource(practitioner).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("Practitioner");
ServiceRequest sr = new ServiceRequest();
sr.getSubject().setReference(patient.getId());
@@ -2143,12 +2300,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
sr.addPerformer().setReference(practitioner.getId());
sr.addPerformer().setReference(practitioner.getId());
sr.addPerformer().setReference(practitioner.getId());
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
sr = new ServiceRequest();
sr.getSubject().setReference(patient.getId());
@@ -2157,12 +2309,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
sr.addPerformer().setReference(practitioner.getId());
sr.addPerformer().setReference(practitioner.getId());
sr.addPerformer().setReference(practitioner.getId());
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
myCaptureQueriesListener.clear();
Bundle output = mySystemDao.transaction(mySrd, input);
@@ -2179,6 +2326,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithMultiplePreExistingReferences_ForcedId() {
myStorageSettings.setDeleteEnabled(true);
@@ -2201,23 +2351,13 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
sr.getSubject().setReference(patient.getId());
sr.addPerformer().setReference(practitioner.getId());
sr.addPerformer().setReference(practitioner.getId());
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
sr = new ServiceRequest();
sr.getSubject().setReference(patient.getId());
sr.addPerformer().setReference(practitioner.getId());
sr.addPerformer().setReference(practitioner.getId());
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
myCaptureQueriesListener.clear();
Bundle output = mySystemDao.transaction(mySrd, input);
@@ -2239,23 +2379,13 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
sr.getSubject().setReference(patient.getId());
sr.addPerformer().setReference(practitioner.getId());
sr.addPerformer().setReference(practitioner.getId());
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
sr = new ServiceRequest();
sr.getSubject().setReference(patient.getId());
sr.addPerformer().setReference(practitioner.getId());
sr.addPerformer().setReference(practitioner.getId());
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
myCaptureQueriesListener.clear();
output = mySystemDao.transaction(mySrd, input);
@@ -2270,6 +2400,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithMultiplePreExistingReferences_Numeric() {
myStorageSettings.setDeleteEnabled(true);
@@ -2289,23 +2422,13 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
sr.getSubject().setReferenceElement(patientId);
sr.addPerformer().setReferenceElement(practitionerId);
sr.addPerformer().setReferenceElement(practitionerId);
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
sr = new ServiceRequest();
sr.getSubject().setReferenceElement(patientId);
sr.addPerformer().setReferenceElement(practitionerId);
sr.addPerformer().setReferenceElement(practitionerId);
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
myCaptureQueriesListener.clear();
Bundle output = mySystemDao.transaction(mySrd, input);
@@ -2328,23 +2451,13 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
sr.getSubject().setReferenceElement(patientId);
sr.addPerformer().setReferenceElement(practitionerId);
sr.addPerformer().setReferenceElement(practitionerId);
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
sr = new ServiceRequest();
sr.getSubject().setReferenceElement(patientId);
sr.addPerformer().setReferenceElement(practitionerId);
sr.addPerformer().setReferenceElement(practitionerId);
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
myCaptureQueriesListener.clear();
output = mySystemDao.transaction(mySrd, input);
@@ -2359,6 +2472,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithMultiplePreExistingReferences_ForcedId_DeletesDisabled() {
myStorageSettings.setDeleteEnabled(false);
@@ -2381,23 +2497,13 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
sr.getSubject().setReference(patient.getId());
sr.addPerformer().setReference(practitioner.getId());
sr.addPerformer().setReference(practitioner.getId());
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
sr = new ServiceRequest();
sr.getSubject().setReference(patient.getId());
sr.addPerformer().setReference(practitioner.getId());
sr.addPerformer().setReference(practitioner.getId());
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
myCaptureQueriesListener.clear();
Bundle output = mySystemDao.transaction(mySrd, input);
@@ -2419,23 +2525,13 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
sr.getSubject().setReference(patient.getId());
sr.addPerformer().setReference(practitioner.getId());
sr.addPerformer().setReference(practitioner.getId());
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
sr = new ServiceRequest();
sr.getSubject().setReference(patient.getId());
sr.addPerformer().setReference(practitioner.getId());
sr.addPerformer().setReference(practitioner.getId());
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
myCaptureQueriesListener.clear();
output = mySystemDao.transaction(mySrd, input);
@@ -2450,6 +2546,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithMultiplePreExistingReferences_Numeric_DeletesDisabled() {
myStorageSettings.setDeleteEnabled(false);
@@ -2469,23 +2568,13 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
sr.getSubject().setReferenceElement(patientId);
sr.addPerformer().setReferenceElement(practitionerId);
sr.addPerformer().setReferenceElement(practitionerId);
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
sr = new ServiceRequest();
sr.getSubject().setReferenceElement(patientId);
sr.addPerformer().setReferenceElement(practitionerId);
sr.addPerformer().setReferenceElement(practitionerId);
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
myCaptureQueriesListener.clear();
Bundle output = mySystemDao.transaction(mySrd, input);
@@ -2507,23 +2596,13 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
sr.getSubject().setReferenceElement(patientId);
sr.addPerformer().setReferenceElement(practitionerId);
sr.addPerformer().setReferenceElement(practitionerId);
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
sr = new ServiceRequest();
sr.getSubject().setReferenceElement(patientId);
sr.addPerformer().setReferenceElement(practitionerId);
sr.addPerformer().setReferenceElement(practitionerId);
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
myCaptureQueriesListener.clear();
output = mySystemDao.transaction(mySrd, input);
@@ -2538,6 +2617,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithMultiplePreExistingReferences_IfNoneExist() {
myStorageSettings.setDeleteEnabled(true);
@@ -2559,46 +2641,24 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
patient = new Patient();
patient.setId(IdType.newRandomUuid());
patient.setActive(true);
- input.addEntry()
- .setFullUrl(patient.getId())
- .setResource(patient)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("Patient")
- .setIfNoneExist("Patient?active=true");
+ input.addEntry().setFullUrl(patient.getId()).setResource(patient).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("Patient").setIfNoneExist("Patient?active=true");
practitioner = new Practitioner();
practitioner.setId(IdType.newRandomUuid());
practitioner.setActive(true);
- input.addEntry()
- .setFullUrl(practitioner.getId())
- .setResource(practitioner)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("Practitioner")
- .setIfNoneExist("Practitioner?active=true");
+ input.addEntry().setFullUrl(practitioner.getId()).setResource(practitioner).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("Practitioner").setIfNoneExist("Practitioner?active=true");
ServiceRequest sr = new ServiceRequest();
sr.getSubject().setReference(patient.getId());
sr.addPerformer().setReference(practitioner.getId());
sr.addPerformer().setReference(practitioner.getId());
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
sr = new ServiceRequest();
sr.getSubject().setReference(patient.getId());
sr.addPerformer().setReference(practitioner.getId());
sr.addPerformer().setReference(practitioner.getId());
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
myCaptureQueriesListener.clear();
Bundle output = mySystemDao.transaction(mySrd, input);
@@ -2618,46 +2678,24 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
patient = new Patient();
patient.setId(IdType.newRandomUuid());
patient.setActive(true);
- input.addEntry()
- .setFullUrl(patient.getId())
- .setResource(patient)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("Patient")
- .setIfNoneExist("Patient?active=true");
+ input.addEntry().setFullUrl(patient.getId()).setResource(patient).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("Patient").setIfNoneExist("Patient?active=true");
practitioner = new Practitioner();
practitioner.setId(IdType.newRandomUuid());
practitioner.setActive(true);
- input.addEntry()
- .setFullUrl(practitioner.getId())
- .setResource(practitioner)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("Practitioner")
- .setIfNoneExist("Practitioner?active=true");
+ input.addEntry().setFullUrl(practitioner.getId()).setResource(practitioner).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("Practitioner").setIfNoneExist("Practitioner?active=true");
sr = new ServiceRequest();
sr.getSubject().setReference(patient.getId());
sr.addPerformer().setReference(practitioner.getId());
sr.addPerformer().setReference(practitioner.getId());
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
sr = new ServiceRequest();
sr.getSubject().setReference(patient.getId());
sr.addPerformer().setReference(practitioner.getId());
sr.addPerformer().setReference(practitioner.getId());
- input.addEntry()
- .setFullUrl(sr.getId())
- .setResource(sr)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("ServiceRequest");
+ input.addEntry().setFullUrl(sr.getId()).setResource(sr).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("ServiceRequest");
myCaptureQueriesListener.clear();
output = mySystemDao.transaction(mySrd, input);
@@ -2672,6 +2710,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithMultipleProfiles() {
myStorageSettings.setDeleteEnabled(true);
@@ -2685,11 +2726,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
patient.getMeta().addProfile("http://example.com/profile");
patient.getMeta().addTag().setSystem("http://example.com/tags").setCode("tag-1");
patient.getMeta().addTag().setSystem("http://example.com/tags").setCode("tag-2");
- input.addEntry()
- .setResource(patient)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("Patient");
+ input.addEntry().setResource(patient).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("Patient");
}
myCaptureQueriesListener.clear();
@@ -2709,11 +2746,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
patient.getMeta().addProfile("http://example.com/profile");
patient.getMeta().addTag().setSystem("http://example.com/tags").setCode("tag-1");
patient.getMeta().addTag().setSystem("http://example.com/tags").setCode("tag-2");
- input.addEntry()
- .setResource(patient)
- .getRequest()
- .setMethod(Bundle.HTTPVerb.POST)
- .setUrl("Patient");
+ input.addEntry().setResource(patient).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("Patient");
}
myCaptureQueriesListener.clear();
@@ -2733,6 +2766,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
* need to be resolved (ie SQL SELECT) in order to proceed with the transaction. Prior
* to the optimization that introduced this test, we had 140 SELECTs, now it's 17.
*/
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithManyInlineMatchUrls() throws IOException {
myStorageSettings.setAutoCreatePlaceholderReferenceTargets(true);
@@ -2752,13 +2788,16 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
assertEquals(input.getEntry().size(), output.getEntry().size());
- runInTransaction(()->{
+ runInTransaction(() -> {
assertEquals(437, myResourceTableDao.count());
assertEquals(437, myResourceHistoryTableDao.count());
});
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testTransactionWithClientAssignedId() {
BundleBuilder bb = new BundleBuilder(myFhirContext);
@@ -2781,6 +2820,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testValueSetExpand_NotPreExpanded_UseHibernateSearch() {
createLocalCsAndVs();
@@ -2819,6 +2861,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
assertEquals(0, myCaptureQueriesListener.countRollbacks());
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testValueSetExpand_NotPreExpanded_DontUseHibernateSearch() {
TermReadSvcImpl.setForceDisableHibernateSearchForUnitTest(true);
@@ -2859,6 +2904,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
assertEquals(0, myCaptureQueriesListener.countRollbacks());
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testValueSetExpand_PreExpanded_UseHibernateSearch() {
createLocalCsAndVs();
@@ -2903,6 +2951,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
assertEquals(0, myCaptureQueriesListener.countRollbacks());
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testMassIngestionMode_TransactionWithChanges() {
myStorageSettings.setDeleteEnabled(false);
@@ -2910,10 +2961,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
myStorageSettings.setMassIngestionMode(true);
myFhirContext.getParserOptions().setStripVersionsFromReferences(false);
myStorageSettings.setRespectVersionsForSearchIncludes(true);
- myStorageSettings.setAutoVersionReferenceAtPaths(
- "ExplanationOfBenefit.patient",
- "ExplanationOfBenefit.insurance.coverage"
- );
+ myStorageSettings.setAutoVersionReferenceAtPaths("ExplanationOfBenefit.patient", "ExplanationOfBenefit.insurance.coverage");
Patient warmUpPt = new Patient();
warmUpPt.getMeta().addProfile("http://foo");
@@ -2967,6 +3015,9 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testMassIngestionMode_TransactionWithChanges_2() throws IOException {
myStorageSettings.setDeleteEnabled(false);
@@ -2975,10 +3026,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
myFhirContext.getParserOptions().setStripVersionsFromReferences(false);
myStorageSettings.setRespectVersionsForSearchIncludes(true);
myStorageSettings.setTagStorageMode(JpaStorageSettings.TagStorageModeEnum.NON_VERSIONED);
- myStorageSettings.setAutoVersionReferenceAtPaths(
- "ExplanationOfBenefit.patient",
- "ExplanationOfBenefit.insurance.coverage"
- );
+ myStorageSettings.setAutoVersionReferenceAtPaths("ExplanationOfBenefit.patient", "ExplanationOfBenefit.insurance.coverage");
// Pre-cache tag definitions
Patient patient = new Patient();
@@ -3010,15 +3058,15 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
+ /**
+ * See the class javadoc before changing the counts in this test!
+ */
@Test
public void testDeleteResource_WithMassIngestionMode_enabled() {
myStorageSettings.setMassIngestionMode(true);
// given
- Observation observation = new Observation()
- .setStatus(Observation.ObservationStatus.FINAL)
- .addCategory(new CodeableConcept().addCoding(new Coding("http://category-type", "12345", null)))
- .setCode(new CodeableConcept().addCoding(new Coding("http://coverage-type", "12345", null)));
+ Observation observation = new Observation().setStatus(Observation.ObservationStatus.FINAL).addCategory(new CodeableConcept().addCoding(new Coding("http://category-type", "12345", null))).setCode(new CodeableConcept().addCoding(new Coding("http://coverage-type", "12345", null)));
IIdType idDt = myObservationDao.create(observation, mySrd).getEntity().getIdDt();
@@ -3030,15 +3078,6 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
assertQueryCount(3, 1, 1, 2);
}
- private void printQueryCount() {
-
- ourLog.info("\tselect: {}", myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
- ourLog.info("\tupdate: {}", myCaptureQueriesListener.getUpdateQueriesForCurrentThread().size());
- ourLog.info("\tinsert: {}", myCaptureQueriesListener.getInsertQueriesForCurrentThread().size());
- ourLog.info("\tdelete: {}", myCaptureQueriesListener.getDeleteQueriesForCurrentThread().size());
-
- }
-
private void assertQueryCount(int theExpectedSelectCount, int theExpectedUpdateCount, int theExpectedInsertCount, int theExpectedDeleteCount) {
assertEquals(theExpectedSelectCount, myCaptureQueriesListener.getSelectQueriesForCurrentThread().size());
@@ -3064,9 +3103,7 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
theGroup.addMember(aGroupMemberComponent);
}
- Group retVal = runInTransaction(() -> (Group) myGroupDao.update(theGroup, mySrd).getResource());
-
- return retVal;
+ return runInTransaction(() -> (Group) myGroupDao.update(theGroup, mySrd).getResource());
}
@@ -3080,14 +3117,13 @@ public class FhirResourceDaoR4QueryCountTest extends BaseResourceProviderR4Test
}
private IIdType createAPatient() {
- IIdType retVal = runInTransaction(() -> {
+
+ return runInTransaction(() -> {
Patient p = new Patient();
p.getMeta().addTag("http://system", "foo", "display");
p.addIdentifier().setSystem("urn:system").setValue("2");
return myPatientDao.create(p).getId().toUnqualified();
});
-
- return retVal;
}
}
diff --git a/hapi-fhir-jpaserver-test-r4b/pom.xml b/hapi-fhir-jpaserver-test-r4b/pom.xml
index acbeb94438a..15e8a848032 100644
--- a/hapi-fhir-jpaserver-test-r4b/pom.xml
+++ b/hapi-fhir-jpaserver-test-r4b/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.5.11-SNAPSHOT
+ 6.5.12-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-r5/pom.xml b/hapi-fhir-jpaserver-test-r5/pom.xml
index 86fa3e3fa66..7db7243efee 100644
--- a/hapi-fhir-jpaserver-test-r5/pom.xml
+++ b/hapi-fhir-jpaserver-test-r5/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.5.11-SNAPSHOT
+ 6.5.12-SNAPSHOT
../hapi-deployable-pom/pom.xml
@@ -28,6 +28,12 @@
${project.version}
test
+
+ net.sourceforge.htmlunit
+ htmlunit
+ test
+
+
diff --git a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/BaseJpaR5Test.java b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/BaseJpaR5Test.java
index bbf7b0ece51..b14c4150aa9 100644
--- a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/BaseJpaR5Test.java
+++ b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/BaseJpaR5Test.java
@@ -453,7 +453,6 @@ public abstract class BaseJpaR5Test extends BaseJpaTest implements ITestDataBuil
purgeHibernateSearch(myEntityManager);
myStorageSettings.setSchedulingDisabled(true);
- myStorageSettings.setIndexMissingFields(JpaStorageSettings.IndexEnabledEnum.ENABLED);
}
@BeforeEach
diff --git a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/search/reindex/InstanceReindexServiceImplNarrativeR5Test.java b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/search/reindex/InstanceReindexServiceImplNarrativeR5Test.java
new file mode 100644
index 00000000000..94c7d260602
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/search/reindex/InstanceReindexServiceImplNarrativeR5Test.java
@@ -0,0 +1,312 @@
+package ca.uhn.fhir.jpa.search.reindex;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
+import ca.uhn.fhir.jpa.model.config.PartitionSettings;
+import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboStringUnique;
+import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboTokenNonUnique;
+import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
+import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
+import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantityNormalized;
+import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
+import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
+import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
+import ca.uhn.fhir.jpa.model.entity.ResourceLink;
+import ca.uhn.fhir.jpa.model.entity.ResourceTable;
+import ca.uhn.fhir.jpa.model.entity.SearchParamPresentEntity;
+import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams;
+import ca.uhn.fhir.test.utilities.HtmlUtil;
+import com.gargoylesoftware.htmlunit.html.HtmlPage;
+import com.gargoylesoftware.htmlunit.html.HtmlTable;
+import org.hl7.fhir.r4.model.IdType;
+import org.hl7.fhir.r4.model.Parameters;
+import org.hl7.fhir.r4.model.StringType;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.Nonnull;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.Date;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Tests the narrative generation in {@link InstanceReindexServiceImpl}. This is a separate test
+ * from {@literal ReindexDryRunServiceImplTest} because this test doesn't need the JPA
+ * infrastructure.
+ */
+@SuppressWarnings({"unchecked", "SqlDialectInspection"})
+public class InstanceReindexServiceImplNarrativeR5Test {
+ private static final Logger ourLog = LoggerFactory.getLogger(InstanceReindexServiceImplNarrativeR5Test.class);
+ private final FhirContext myCtx = FhirContext.forR4Cached();
+ private final InstanceReindexServiceImpl mySvc = new InstanceReindexServiceImpl();
+ private final PartitionSettings myPartitionSettings = new PartitionSettings();
+ private final JpaStorageSettings myStorageSettings = new JpaStorageSettings();
+ private final ResourceTable myEntity = new ResourceTable();
+
+ @Test
+ public void testIndexComboNonUnique() throws IOException {
+ // Setup
+ ResourceIndexedSearchParams newParams = newParams();
+ newParams.myComboTokenNonUnique.add(new ResourceIndexedComboTokenNonUnique(myPartitionSettings, myEntity, "Patient?identifier=123"));
+
+ // Test
+ Parameters outcome = mySvc.buildIndexResponse(newParams(), newParams, true);
+ ourLog.info("Output:\n{}", myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ // Verify
+ HtmlPage narrativeHtml = extractNarrative(outcome);
+ HtmlTable table = (HtmlTable) narrativeHtml.getElementById("NonUniqueIndexesTable");
+ assertEquals("ADD", getBodyCellValue(table, 0, 0));
+ assertEquals("ComboTokenNonUnique", getBodyCellValue(table, 0, 1));
+ assertEquals("Patient?identifier=123", getBodyCellValue(table, 0, 2));
+ }
+
+ @Test
+ public void testIndexComboUnique() throws IOException {
+ // Setup
+ ResourceIndexedSearchParams newParams = newParams();
+ newParams.myComboStringUniques.add(new ResourceIndexedComboStringUnique(myEntity, "Patient?identifier=123", new IdType("Parameter/foo")));
+
+ // Test
+ Parameters outcome = mySvc.buildIndexResponse(newParams(), newParams, true);
+ ourLog.info("Output:\n{}", myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ // Verify
+ HtmlPage narrativeHtml = extractNarrative(outcome);
+ HtmlTable table = (HtmlTable) narrativeHtml.getElementById("UniqueIndexesTable");
+ assertEquals("ADD", getBodyCellValue(table, 0, 0));
+ assertEquals("ComboStringUnique", getBodyCellValue(table, 0, 1));
+ assertEquals("Patient?identifier=123", getBodyCellValue(table, 0, 2));
+ }
+
+ @Test
+ public void testIndexMissing() throws IOException {
+ // Setup
+ ResourceIndexedSearchParams newParams = newParams();
+ newParams.myTokenParams.add(new ResourceIndexedSearchParamToken(myPartitionSettings, "Observation", "identifier", true));
+ SearchParamPresentEntity subject = new SearchParamPresentEntity("subject", false);
+ subject.setResource(new ResourceTable());
+ subject.setPartitionSettings(myPartitionSettings);
+ subject.calculateHashes();
+ newParams.mySearchParamPresentEntities.add(subject);
+
+ // Test
+ Parameters outcome = mySvc.buildIndexResponse(newParams(), newParams, true);
+ ourLog.info("Output:\n{}", myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ // Verify
+ HtmlPage narrativeHtml = extractNarrative(outcome);
+ HtmlTable table = (HtmlTable) narrativeHtml.getElementById("MissingIndexesTable");
+ assertEquals("identifier", getBodyCellValue(table, 0, 0));
+ assertEquals("ADD", getBodyCellValue(table, 0, 1));
+ assertEquals("Token", getBodyCellValue(table, 0, 2));
+ assertEquals("true", getBodyCellValue(table, 0, 3));
+ assertEquals("subject", getBodyCellValue(table, 1, 0));
+ assertEquals("ADD", getBodyCellValue(table, 1, 1));
+ assertEquals("Reference", getBodyCellValue(table, 1, 2));
+ assertEquals("true", getBodyCellValue(table, 1, 3));
+ }
+
+ @Test
+ public void testIndexNumber() throws IOException {
+ // Setup
+ ResourceIndexedSearchParams newParams = newParams();
+ newParams.myNumberParams.add(new ResourceIndexedSearchParamNumber(myPartitionSettings, "Immunization", "dose", BigDecimal.ONE));
+
+ // Test
+ Parameters outcome = mySvc.buildIndexResponse(newParams(), newParams, true);
+ ourLog.info("Output:\n{}", myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ // Verify
+ HtmlPage narrativeHtml = extractNarrative(outcome);
+ HtmlTable table = (HtmlTable) narrativeHtml.getElementById("NumberIndexesTable");
+ assertEquals("dose", getBodyCellValue(table, 0, 0));
+ assertEquals("ADD", getBodyCellValue(table, 0, 1));
+ assertEquals("Number", getBodyCellValue(table, 0, 2));
+ assertEquals("1", getBodyCellValue(table, 0, 3));
+ }
+
+ @Test
+ public void testIndexResourceLink() throws IOException {
+ // Setup
+ ResourceIndexedSearchParams newParams = newParams();
+ newParams.myLinks.add(ResourceLink.forLocalReference("Observation.subject", myEntity, "Patient", 123L, "123", new Date(), 555L));
+
+ // Test
+ Parameters outcome = mySvc.buildIndexResponse(newParams(), newParams, true);
+ ourLog.info("Output:\n{}", myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ // Verify
+ HtmlPage narrativeHtml = extractNarrative(outcome);
+ HtmlTable table = (HtmlTable) narrativeHtml.getElementById("ResourceLinksTable");
+ assertEquals("Observation.subject", getBodyCellValue(table, 0, 0));
+ assertEquals("ADD", getBodyCellValue(table, 0, 1));
+ assertEquals("Reference", getBodyCellValue(table, 0, 2));
+ assertEquals("Patient/123", getBodyCellValue(table, 0, 3));
+ assertEquals("555", getBodyCellValue(table, 0, 4));
+ }
+
+ @Test
+ public void testIndexResourceLinkLogical() throws IOException {
+ // Setup
+ ResourceIndexedSearchParams newParams = newParams();
+ newParams.myLinks.add(ResourceLink.forLogicalReference("Observation.subject", myEntity, "http://foo/base/Patient/456", new Date()));
+
+ // Test
+ Parameters outcome = mySvc.buildIndexResponse(newParams(), newParams, true);
+ ourLog.info("Output:\n{}", myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ // Verify
+ HtmlPage narrativeHtml = extractNarrative(outcome);
+ HtmlTable table = (HtmlTable) narrativeHtml.getElementById("ResourceLinksTable");
+ assertEquals("Observation.subject", getBodyCellValue(table, 0, 0));
+ assertEquals("ADD", getBodyCellValue(table, 0, 1));
+ assertEquals("Reference", getBodyCellValue(table, 0, 2));
+ assertEquals("", getBodyCellValue(table, 0, 3));
+ assertEquals("", getBodyCellValue(table, 0, 4));
+ assertEquals("http://foo/base/Patient/456", getBodyCellValue(table, 0, 5));
+ }
+
+ @Test
+ public void testIndexResourceLinkAbsolute() throws IOException {
+ // Setup
+ ResourceIndexedSearchParams newParams = newParams();
+ newParams.myLinks.add(ResourceLink.forAbsoluteReference("Observation.subject", myEntity, new IdType("http://foo/base/Patient/123"), new Date()));
+
+ // Test
+ Parameters outcome = mySvc.buildIndexResponse(newParams(), newParams, true);
+ ourLog.info("Output:\n{}", myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ // Verify
+ HtmlPage narrativeHtml = extractNarrative(outcome);
+ HtmlTable table = (HtmlTable) narrativeHtml.getElementById("ResourceLinksTable");
+ assertEquals("Observation.subject", getBodyCellValue(table, 0, 0));
+ assertEquals("ADD", getBodyCellValue(table, 0, 1));
+ assertEquals("Reference", getBodyCellValue(table, 0, 2));
+ assertEquals("", getBodyCellValue(table, 0, 3));
+ assertEquals("", getBodyCellValue(table, 0, 4));
+ assertEquals("http://foo/base/Patient/123", getBodyCellValue(table, 0, 5));
+ }
+
+ @Test
+ public void testIndexQuantity() throws IOException {
+ // Setup
+ ResourceIndexedSearchParams newParams = newParams();
+ newParams.myQuantityParams.add(new ResourceIndexedSearchParamQuantity(myPartitionSettings, "Observation", "value-quantity", BigDecimal.valueOf(123), "http://unitsofmeasure.org", "kg"));
+
+ // Test
+ Parameters outcome = mySvc.buildIndexResponse(newParams(), newParams, true);
+ ourLog.info("Output:\n{}", myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ // Verify
+ HtmlPage narrativeHtml = extractNarrative(outcome);
+ HtmlTable table = (HtmlTable) narrativeHtml.getElementById("QuantityIndexesTable");
+ assertEquals("value-quantity", getBodyCellValue(table, 0, 0));
+ assertEquals("ADD", getBodyCellValue(table, 0, 1));
+ assertEquals("Quantity", getBodyCellValue(table, 0, 2));
+ assertEquals("123", getBodyCellValue(table, 0, 3));
+ assertEquals("http://unitsofmeasure.org", getBodyCellValue(table, 0, 4));
+ assertEquals("kg", getBodyCellValue(table, 0, 5));
+ }
+
+ @Test
+ public void testIndexQuantityNormalized() throws IOException {
+ // Setup
+ ResourceIndexedSearchParams newParams = newParams();
+ newParams.myQuantityNormalizedParams.add(new ResourceIndexedSearchParamQuantityNormalized(myPartitionSettings, "Observation", "value-quantity", 123.0, "http://unitsofmeasure.org", "kg"));
+
+ // Test
+ Parameters outcome = mySvc.buildIndexResponse(newParams(), newParams, true);
+ ourLog.info("Output:\n{}", myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ // Verify
+ HtmlPage narrativeHtml = extractNarrative(outcome);
+ HtmlTable table = (HtmlTable) narrativeHtml.getElementById("QuantityIndexesTable");
+ assertEquals("value-quantity", getBodyCellValue(table, 0, 0));
+ assertEquals("ADD", getBodyCellValue(table, 0, 1));
+ assertEquals("QuantityNormalized", getBodyCellValue(table, 0, 2));
+ assertEquals("123.0", getBodyCellValue(table, 0, 3));
+ assertEquals("http://unitsofmeasure.org", getBodyCellValue(table, 0, 4));
+ assertEquals("kg", getBodyCellValue(table, 0, 5));
+ }
+
+ @Test
+ public void testIndexString() throws IOException {
+ // Setup
+ ResourceIndexedSearchParams newParams = newParams();
+ newParams.myStringParams.add(new ResourceIndexedSearchParamString(myPartitionSettings, myStorageSettings, "Patient", "family", "Simpson", "SIMPSON"));
+
+ // Test
+ Parameters outcome = mySvc.buildIndexResponse(newParams(), newParams, true);
+ ourLog.info("Output:\n{}", myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ // Verify
+ HtmlPage narrativeHtml = extractNarrative(outcome);
+ HtmlTable table = (HtmlTable) narrativeHtml.getElementById("StringIndexesTable");
+ assertEquals("family", getBodyCellValue(table, 0, 0));
+ assertEquals("ADD", getBodyCellValue(table, 0, 1));
+ assertEquals("String", getBodyCellValue(table, 0, 2));
+ assertEquals("Simpson", getBodyCellValue(table, 0, 3));
+ assertEquals("SIMPSON", getBodyCellValue(table, 0, 4));
+ }
+
+ @Test
+ public void testIndexToken() throws IOException {
+ // Setup
+ ResourceIndexedSearchParams newParams = newParams();
+ newParams.myTokenParams.add(new ResourceIndexedSearchParamToken(myPartitionSettings, "Observation", "identifier", "http://id-system", "id-value"));
+
+ // Test
+ Parameters outcome = mySvc.buildIndexResponse(newParams(), newParams, true);
+ ourLog.info("Output:\n{}", myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ // Verify
+ HtmlPage narrativeHtml = extractNarrative(outcome);
+ HtmlTable table = (HtmlTable) narrativeHtml.getElementById("TokenIndexesTable");
+ assertEquals("identifier", getBodyCellValue(table, 0, 0));
+ assertEquals("ADD", getBodyCellValue(table, 0, 1));
+ assertEquals("Token", getBodyCellValue(table, 0, 2));
+ assertEquals("http://id-system", getBodyCellValue(table, 0, 3));
+ assertEquals("id-value", getBodyCellValue(table, 0, 4));
+ }
+
+ @Test
+ public void testIndexUrl() throws IOException {
+ // Setup
+ ResourceIndexedSearchParams newParams = newParams();
+ newParams.myUriParams.add(new ResourceIndexedSearchParamUri(myPartitionSettings, "CodeSystem", "uri", "http://some-codesystem"));
+
+ // Test
+ Parameters outcome = mySvc.buildIndexResponse(newParams(), newParams, true);
+ ourLog.info("Output:\n{}", myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ // Verify
+ HtmlPage narrativeHtml = extractNarrative(outcome);
+ HtmlTable table = (HtmlTable) narrativeHtml.getElementById("UriIndexesTable");
+ assertEquals("uri", getBodyCellValue(table, 0, 0));
+ assertEquals("ADD", getBodyCellValue(table, 0, 1));
+ assertEquals("Uri", getBodyCellValue(table, 0, 2));
+ assertEquals("http://some-codesystem", getBodyCellValue(table, 0, 3));
+ }
+
+ @Nonnull
+ private static HtmlPage extractNarrative(Parameters outcome) throws IOException {
+ StringType narrative = (StringType) outcome.getParameter().get(0).getValue();
+ HtmlPage narrativeHtml = HtmlUtil.parseAsHtml(narrative.getValueAsString());
+ ourLog.info("Narrative:\n{}", narrativeHtml.asXml());
+ return narrativeHtml;
+ }
+
+ private static String getBodyCellValue(HtmlTable table, int theRow, int theCol) {
+ return table.getBodies().get(0).getRows().get(theRow).getCell(theCol).asNormalizedText();
+ }
+
+ @Nonnull
+ private static ResourceIndexedSearchParams newParams() {
+ return new ResourceIndexedSearchParams();
+ }
+
+}
diff --git a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/search/reindex/InstanceReindexServiceImplR5Test.java b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/search/reindex/InstanceReindexServiceImplR5Test.java
new file mode 100644
index 00000000000..a2b0797e6db
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/search/reindex/InstanceReindexServiceImplR5Test.java
@@ -0,0 +1,398 @@
+package ca.uhn.fhir.jpa.search.reindex;
+
+import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
+import ca.uhn.fhir.jpa.dao.r5.BaseJpaR5Test;
+import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
+import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
+import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
+import ca.uhn.fhir.rest.param.StringParam;
+import ca.uhn.fhir.util.HapiExtensions;
+import org.hl7.fhir.instance.model.api.IIdType;
+import org.hl7.fhir.instance.model.api.IPrimitiveType;
+import org.hl7.fhir.r5.model.BooleanType;
+import org.hl7.fhir.r5.model.Enumerations;
+import org.hl7.fhir.r5.model.Parameters;
+import org.hl7.fhir.r5.model.Patient;
+import org.hl7.fhir.r5.model.ResearchStudy;
+import org.hl7.fhir.r5.model.SearchParameter;
+import org.hl7.fhir.r5.model.StringType;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import javax.annotation.Nonnull;
+import java.util.List;
+import java.util.Set;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@SuppressWarnings({"unchecked", "SqlDialectInspection"})
+public class InstanceReindexServiceImplR5Test extends BaseJpaR5Test {
+
+ @Autowired
+ private IInstanceReindexService mySvc;
+
+ @Override
+ @BeforeEach
+ public void beforeResetConfig() {
+ super.beforeResetConfig();
+
+ myStorageSettings.setIndexMissingFields(JpaStorageSettings.IndexEnabledEnum.DISABLED);
+ }
+
+ @Override
+ public void afterCleanupDao() {
+ super.afterCleanupDao();
+
+ JpaStorageSettings defaults = new JpaStorageSettings();
+ myStorageSettings.setIndexMissingFields(defaults.getIndexMissingFields());
+ myStorageSettings.setNormalizedQuantitySearchLevel(defaults.getNormalizedQuantitySearchLevel());
+ }
+
+
+ @Test
+ public void testDryRunMissing() {
+ myStorageSettings.setIndexMissingFields(JpaStorageSettings.IndexEnabledEnum.ENABLED);
+
+ IIdType id = createPatient(withFamily("Simpson"), withGiven("Homer"));
+
+ Parameters outcome = (Parameters) mySvc.reindexDryRun(new SystemRequestDetails(), id, null);
+ ourLog.info("Output:{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ List sections = outcome.getParameters("MissingIndexes");
+ assertEquals(1, sections.size());
+
+ List indexInstances = sections
+ .get(0)
+ .getPart()
+ .stream()
+ .map(t -> t.getName() + " " + getPartValue("Action", t) + " " + getPartValue("Type", t) + " " + getPartValue("Missing", t))
+ .sorted()
+ .toList();
+ assertThat(indexInstances.toString(), indexInstances, contains(
+ "_profile NO_CHANGE Reference true",
+ "active NO_CHANGE Token true",
+ "address NO_CHANGE String true",
+ "address-city NO_CHANGE String true",
+ "address-country NO_CHANGE String true",
+ "address-postalcode NO_CHANGE String true",
+ "address-state NO_CHANGE String true",
+ "address-use NO_CHANGE Token true",
+ "age NO_CHANGE Number true",
+ "birthOrderBoolean NO_CHANGE Token true",
+ "birthdate NO_CHANGE Date true",
+ "death-date NO_CHANGE Date true",
+ "email NO_CHANGE Token true",
+ "gender NO_CHANGE Token true",
+ "general-practitioner NO_CHANGE Reference true",
+ "identifier NO_CHANGE Token true",
+ "language NO_CHANGE Token true",
+ "link NO_CHANGE Reference true",
+ "mothersMaidenName NO_CHANGE String true",
+ "organization NO_CHANGE Reference true",
+ "part-agree NO_CHANGE Reference true",
+ "phone NO_CHANGE Token true",
+ "telecom NO_CHANGE Token true"
+ ));
+ }
+
+
+ @Test
+ public void testDryRunTypes_ComboNonUniqueSearchParam() {
+ createNamesAndGenderSp(false);
+
+ IIdType id = createPatient(withFamily("Simpson"), withGiven("Homer"));
+
+ runInTransaction(this::logAllNonUniqueIndexes);
+
+ Parameters outcome = (Parameters) mySvc.reindexDryRun(new SystemRequestDetails(), id, null);
+ ourLog.info("Output:{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ Parameters.ParametersParameterComponent index = findSingleIndex(outcome, "Patient?family=SIMPSON%5C%7C&given=HOMER", "NonUniqueIndexes");
+ assertEquals("NO_CHANGE", getPartValue("Action", index));
+ }
+
+ @Test
+ public void testDryRunTypes_ComboUniqueSearchParam() {
+ createNamesAndGenderSp(true);
+
+ IIdType id = createPatient(withFamily("Simpson"), withGiven("Homer"));
+
+ Parameters outcome = (Parameters) mySvc.reindexDryRun(new SystemRequestDetails(), id, null);
+ ourLog.info("Output:{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ Parameters.ParametersParameterComponent index = findIndexes(outcome, "Patient?family=Simpson%5C%7C&given=Homer", 1, "UniqueIndexes").get(0);
+ assertEquals("NO_CHANGE", getPartValue("Action", index));
+ }
+
+ @Test
+ public void testDryRunTypes_Number() {
+ IIdType id = createResource("ResearchStudy", withPrimitiveAttribute("recruitment.targetNumber", "3"));
+
+ logAllNumberIndexes();
+
+ Parameters outcome = (Parameters) mySvc.reindexDryRun(new SystemRequestDetails(), id, null);
+ ourLog.info("Output:{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ Parameters.ParametersParameterComponent index = findSingleIndex(outcome, ResearchStudy.SP_RECRUITMENTTARGET, "NumberIndexes");
+ assertEquals("NO_CHANGE", getPartValue("Action", index));
+ assertEquals("Number", getPartValue("Type", index));
+ assertEquals("3", getPartValue("Value", index));
+ }
+
+ @Test
+ public void testDryRunTypes_Quantity() {
+ myStorageSettings.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
+
+ IIdType id = createObservation(withQuantityAtPath("valueQuantity", 1.2, "http://unitsofmeasure.org", "kg"));
+
+ Parameters outcome = (Parameters) mySvc.reindexDryRun(new SystemRequestDetails(), id, null);
+ ourLog.info("Output:{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ Parameters.ParametersParameterComponent index = findSingleIndex(outcome, "value-quantity", "QuantityIndexes");
+ assertEquals("NO_CHANGE", getPartValue("Action", index));
+ assertEquals("Quantity", getPartValue("Type", index));
+ assertEquals("http://unitsofmeasure.org", getPartValue("System", index));
+ assertEquals("kg", getPartValue("Units", index));
+ assertEquals(1.2d, getPartValueDecimal(index), 0.001d);
+ }
+
+ @Test
+ public void testDryRunTypes_QuantityNormalized() {
+ myStorageSettings.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
+
+ IIdType id = createObservation(withQuantityAtPath("valueQuantity", 1.2, "http://unitsofmeasure.org", "mg"));
+
+ Parameters outcome = (Parameters) mySvc.reindexDryRun(new SystemRequestDetails(), id, null);
+ ourLog.info("Output:{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ Parameters.ParametersParameterComponent index;
+
+ index = findIndexes(outcome, "value-quantity", 2, "QuantityIndexes").get(0);
+ assertEquals("NO_CHANGE", getPartValue("Action", index));
+ assertEquals("Quantity", getPartValue("Type", index));
+ assertEquals("http://unitsofmeasure.org", getPartValue("System", index));
+ assertEquals("mg", getPartValue("Units", index));
+ assertEquals(1.2d, getPartValueDecimal(index), 0.001d);
+
+ index = findIndexes(outcome, "value-quantity", 2, "QuantityIndexes").get(1);
+ assertEquals("NO_CHANGE", getPartValue("Action", index));
+ assertEquals("QuantityNormalized", getPartValue("Type", index));
+ assertEquals("http://unitsofmeasure.org", getPartValue("System", index));
+ assertEquals("g", getPartValue("Units", index));
+ assertEquals(0.0012d, getPartValueDecimal(index), 0.001d);
+ }
+
+ @Test
+ public void testDryRunTypes_ResourceLink() {
+ createPatient(withId("A"), withActiveTrue());
+ IIdType id = createObservation(withSubject("Patient/A"));
+
+ Parameters outcome = (Parameters) mySvc.reindexDryRun(new SystemRequestDetails(), id, null);
+ ourLog.info("Output:{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ Parameters.ParametersParameterComponent index = findSingleIndex(outcome, "Observation.subject", "ResourceLinks");
+ assertEquals("NO_CHANGE", getPartValue("Action", index));
+ assertEquals("Reference", getPartValue("Type", index));
+ assertEquals("Patient/A", getPartValue("TargetId", index));
+ }
+
+ @Test
+ public void testDryRunTypes_ResourceLink_WithUrl() {
+ createPatient(withId("A"), withActiveTrue());
+ IIdType id = createObservation(withSubject("Patient/A"));
+
+ runInTransaction(() -> {
+ assertEquals(2, myEntityManager.createNativeQuery("update HFJ_RES_LINK set TARGET_RESOURCE_ID = null").executeUpdate());
+ assertEquals(2, myEntityManager.createNativeQuery("update HFJ_RES_LINK set TARGET_RESOURCE_URL = 'http://foo'").executeUpdate());
+ assertEquals(2, myEntityManager.createNativeQuery("update HFJ_RES_LINK set TARGET_RESOURCE_VERSION = 1").executeUpdate());
+ });
+
+ Parameters outcome = (Parameters) mySvc.reindexDryRun(new SystemRequestDetails(), id, null);
+ ourLog.info("Output:{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ List indexes = findIndexes(outcome, "Observation.subject", 2, "ResourceLinks");
+ Parameters.ParametersParameterComponent index;
+ index = indexes.get(0);
+ assertEquals("ADD", getPartValue("Action", index));
+ assertEquals("Reference", getPartValue("Type", index));
+ assertEquals("Patient/A", getPartValue("TargetId", index));
+ index = indexes.get(1);
+ assertEquals("REMOVE", getPartValue("Action", index));
+ assertEquals("Reference", getPartValue("Type", index));
+ assertEquals("http://foo", getPartValue("TargetUrl", index));
+ assertEquals("1", getPartValue("TargetVersion", index));
+ }
+
+ @Test
+ public void testDryRunTypes_String() {
+ IIdType id = createPatient(withIdentifier("http://identifiers", "123"), withFamily("Smith"));
+
+ Parameters outcome = (Parameters) mySvc.reindexDryRun(new SystemRequestDetails(), id, null);
+ ourLog.info("Output:{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ Parameters.ParametersParameterComponent index = findSingleIndex(outcome, "family", "StringIndexes");
+ assertEquals("NO_CHANGE", getPartValue("Action", index));
+ assertEquals("String", getPartValue("Type", index));
+ assertEquals("SMITH", getPartValue("ValueNormalized", index));
+ assertEquals("Smith", getPartValue("ValueExact", index));
+ }
+
+ @Test
+ public void testDryRunTypes_String_SpecificParameter() {
+ IIdType id = createPatient(withIdentifier("http://identifiers", "123"), withFamily("Simpson"), withGiven("Homer"));
+
+ Parameters outcome = (Parameters) mySvc.reindexDryRun(new SystemRequestDetails(), id, Set.of("family"));
+ ourLog.info("Output:{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ Parameters.ParametersParameterComponent index = findSingleIndex(outcome, "family", "StringIndexes");
+ assertEquals("UNKNOWN", getPartValue("Action", index));
+ assertEquals("String", getPartValue("Type", index));
+ assertEquals("SIMPSON", getPartValue("ValueNormalized", index));
+ assertEquals("Simpson", getPartValue("ValueExact", index));
+
+ findIndexes(outcome, "family", 1, "StringIndexes");
+ findIndexes(outcome, "given", 0, "StringIndexes");
+ }
+
+ @Test
+ public void testDryRunTypes_Token() {
+ IIdType id = createPatient(withIdentifier("http://identifiers", "123"), withFamily("Smith"));
+
+ Parameters outcome = (Parameters) mySvc.reindexDryRun(new SystemRequestDetails(), id, null);
+ ourLog.info("Output:{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ Parameters.ParametersParameterComponent index = findSingleIndex(outcome, "identifier", "TokenIndexes");
+ assertEquals("NO_CHANGE", getPartValue("Action", index));
+ assertEquals("Token", getPartValue("Type", index));
+ assertEquals("http://identifiers", getPartValue("System", index));
+ assertEquals("123", getPartValue("Value", index));
+ }
+
+ @Test
+ public void testDryRunTypes_Uri() {
+ IIdType id = createResource("CodeSystem", withPrimitiveAttribute("url", "http://foo"));
+
+ Parameters outcome = (Parameters) mySvc.reindexDryRun(new SystemRequestDetails(), id, null);
+ ourLog.info("Output:{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ Parameters.ParametersParameterComponent index = findSingleIndex(outcome, "system", "UriIndexes");
+ assertEquals("NO_CHANGE", getPartValue("Action", index));
+ assertEquals("Uri", getPartValue("Type", index));
+ assertEquals("http://foo", getPartValue("Value", index));
+ }
+
+ @Test
+ public void testReindexInstance() {
+ Patient p1 = new Patient();
+ p1.setActive(true);
+ p1.addExtension()
+ .setUrl("http://acme.org/eyecolour")
+ .setValue(new StringType("Gold"));
+ IIdType p1id = myPatientDao.create(p1, mySrd).getId().toUnqualifiedVersionless();
+
+ SearchParameter eyeColourSp = new SearchParameter();
+ eyeColourSp.addBase("Patient");
+ eyeColourSp.setCode("eyecolour");
+ eyeColourSp.setType(Enumerations.SearchParamType.STRING);
+ eyeColourSp.setTitle("Eye Colour");
+ eyeColourSp.setExpression("Patient.extension('http://acme.org/eyecolour')");
+ eyeColourSp.setStatus(Enumerations.PublicationStatus.ACTIVE);
+ mySearchParameterDao.create(eyeColourSp, mySrd);
+ mySearchParamRegistry.forceRefresh();
+
+ SearchParameterMap map = SearchParameterMap.newSynchronous("eyecolour", new StringParam("GOLD"));
+ assertEquals(0, myPatientDao.search(map, mySrd).size());
+
+ Parameters outcome = (Parameters) mySvc.reindex(mySrd, p1id);
+ ourLog.info("Output:{}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome));
+
+ Parameters.ParametersParameterComponent index = findSingleIndex(outcome, "eyecolour", "StringIndexes");
+ assertEquals("ADD", getPartValue("Action", index));
+ assertEquals("String", getPartValue("Type", index));
+ assertEquals("GOLD", getPartValue("ValueNormalized", index));
+ assertEquals("Gold", getPartValue("ValueExact", index));
+
+ assertEquals(1, myPatientDao.search(map, mySrd).size());
+ }
+
+
+ private void createNamesAndGenderSp(boolean theUnique) {
+ SearchParameter sp = new SearchParameter();
+ sp.setId("SearchParameter/patient-family");
+ sp.setType(Enumerations.SearchParamType.STRING);
+ sp.setCode("family");
+ sp.setExpression("Patient.name.family + '|'");
+ sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
+ sp.addBase("Patient");
+ mySearchParameterDao.update(sp, mySrd);
+
+ sp = new SearchParameter();
+ sp.setId("SearchParameter/patient-given");
+ sp.setType(Enumerations.SearchParamType.STRING);
+ sp.setCode("given");
+ sp.setExpression("Patient.name.given");
+ sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
+ sp.addBase("Patient");
+ mySearchParameterDao.update(sp, mySrd);
+
+ sp = new SearchParameter();
+ sp.setId("SearchParameter/patient-names-and-gender");
+ sp.setType(Enumerations.SearchParamType.COMPOSITE);
+ sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
+ sp.addBase("Patient");
+ sp.addComponent()
+ .setExpression("Patient")
+ .setDefinition("SearchParameter/patient-family");
+ sp.addComponent()
+ .setExpression("Patient")
+ .setDefinition("SearchParameter/patient-given");
+ sp.addExtension()
+ .setUrl(HapiExtensions.EXT_SP_UNIQUE)
+ .setValue(new BooleanType(theUnique));
+ mySearchParameterDao.update(sp, mySrd);
+
+ mySearchParamRegistry.forceRefresh();
+
+ }
+
+ private double getPartValueDecimal(Parameters.ParametersParameterComponent theParent) {
+ return Double.parseDouble(getPartValue("Value", theParent));
+ }
+
+ private static Parameters.ParametersParameterComponent findSingleIndex(Parameters theResponse, String theParamName, String theSectionName) {
+ List indexInstances = findIndexes(theResponse, theParamName, 1, theSectionName);
+ return indexInstances.get(0);
+ }
+
+ @Nonnull
+ private static List findIndexes(Parameters theResponse, String theParamName, int theExpectedSize, String theSectionName) {
+ List indexes = theResponse.getParameters(theSectionName);
+ assertEquals(1, indexes.size());
+
+ List