Bug cql engine paging (#4664)

* WIP paging

* iterable HapifhirRetrieveProvider

* Bundle iterating action

* cr config update

* adding paging functionality for search in cr

* updating BundleIterable logic and removing paging references

* add measureeval threaded config into cr

* update properties

* adding hapi change log 4663

* version bump for hapi

* update exception with msg.code, move copyright

* exorcism of paging provider from cr

* updating IT tests for terminology evaluatemeasure

* unit test, javadocs, removed reflection code

* added comments for explanation

* fix javadoc, iterable.size instead of method

* update from master

---------

Co-authored-by: Jonathan Percival <jonathan.i.percival@gmail.com>
Co-authored-by: justin.mckelvy <justin.mckelvy@smilecdr.com>
This commit is contained in:
Justin McKelvy 2023-03-31 09:09:50 -06:00 committed by GitHub
parent 3fb9a16975
commit 9066ad618e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
95 changed files with 469 additions and 335 deletions

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,14 +4,16 @@
<modelVersion>4.0.0</modelVersion>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-bom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<packaging>pom</packaging>
<name>HAPI FHIR BOM</name>
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-cli</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -0,0 +1,4 @@
---
type: fix
issue: 4663
title: "Removing previous bundle provider to allow for iterableBundle provider, which will allow for paging resources instead of full consumption of patient resources at once"

View File

@ -11,7 +11,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -1,3 +1,22 @@
/*-
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package ca.uhn.fhir.jpa.search.builder.predicate;
import ca.uhn.fhir.i18n.Msg;

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -3,7 +3,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -7,7 +7,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -7,7 +7,8 @@
<parent>
<artifactId>hapi-fhir-serviceloaders</artifactId>
<groupId>ca.uhn.hapi.fhir</groupId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -7,7 +7,8 @@
<parent>
<artifactId>hapi-fhir-serviceloaders</artifactId>
<groupId>ca.uhn.hapi.fhir</groupId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -20,7 +21,8 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-caching-api</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>

View File

@ -7,7 +7,8 @@
<parent>
<artifactId>hapi-fhir-serviceloaders</artifactId>
<groupId>ca.uhn.hapi.fhir</groupId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -7,7 +7,8 @@
<parent>
<artifactId>hapi-fhir</artifactId>
<groupId>ca.uhn.hapi.fhir</groupId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>hapi-deployable-pom</artifactId>
<groupId>ca.uhn.hapi.fhir</groupId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
</parent>
<artifactId>hapi-fhir-spring-boot-sample-client-apache</artifactId>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
</parent>
<artifactId>hapi-fhir-spring-boot-sample-client-okhttp</artifactId>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
</parent>
<artifactId>hapi-fhir-spring-boot-sample-server-jersey</artifactId>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-spring-boot</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
</parent>
<artifactId>hapi-fhir-spring-boot-samples</artifactId>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -7,7 +7,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -7,7 +7,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -7,7 +7,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -0,0 +1,108 @@
/*-
* #%L
* HAPI FHIR - Clinical Reasoning
* %%
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package ca.uhn.fhir.cr.common;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.hl7.fhir.instance.model.api.IBaseResource;
import javax.annotation.concurrent.NotThreadSafe;
import java.util.Iterator;
import java.util.List;
/**
* This class leverages IBundleProvider Iterable to provide an iterator for processing bundle search results into manageable paginated chunks. This helped to avoid loading large result sets into lists
**/
@NotThreadSafe
public class BundleIterable implements Iterable<IBaseResource> {
private final IBundleProvider sourceBundleProvider;
private final RequestDetails requestDetails;
public BundleIterable(RequestDetails requestDetails, IBundleProvider bundleProvider) {
this.sourceBundleProvider = bundleProvider;
this.requestDetails = requestDetails;
}
@Override
public Iterator<IBaseResource> iterator() {
return new BundleIterator(this.requestDetails, this.sourceBundleProvider);
}
static class BundleIterator implements Iterator<IBaseResource> {
private IBundleProvider bundleProvider;
private int offset = 0;
private int increment = 50;
private List<IBaseResource> currentResourceList;
private final RequestDetails requestDetails;
private int currentResourceListIndex = 0;
public BundleIterator(RequestDetails requestDetails, IBundleProvider bundleProvider) {
this.bundleProvider = bundleProvider;
this.requestDetails = requestDetails;
initChunk();
}
private void initChunk() {
this.currentResourceList = this.bundleProvider.getResources(offset, increment + offset);
// next offset created
offset += increment;
//restart counter on new chunk
currentResourceListIndex = 0;
}
private void loadNextChunk() {
initChunk();
}
@Override
public boolean hasNext() {
// We still have things in the current chunk to return
if (this.currentResourceListIndex < this.currentResourceList.size()) {
return true;
} else if (this.currentResourceList.size() == 0) {
// no more resources!
return false;
}
// We need our next chunk
this.loadNextChunk();
return this.hasNext();
}
@Override
public IBaseResource next() {
assert this.currentResourceListIndex < this.currentResourceList.size();
var result = this.currentResourceList.get(this.currentResourceListIndex);
this.currentResourceListIndex++;
return result;
}
}
}

View File

@ -70,15 +70,15 @@ public class HapiFhirDal implements FhirDal {
@Override
public Iterable<IBaseResource> search(String theResourceType) {
var b = this.myDaoRegistry.getResourceDao(theResourceType)
.search(SearchParameterMap.newSynchronous(), myRequestDetails);
return TypedBundleProvider.fromBundleProvider(b).getAllResources();
.search(new SearchParameterMap(), myRequestDetails);
return new BundleIterable(myRequestDetails, b);
}
@Override
public Iterable<IBaseResource> searchByUrl(String theResourceType, String theUrl) {
var c = this.myDaoRegistry.getResourceDao(theResourceType)
.search(SearchParameterMap.newSynchronous().add("url", new UriParam(theUrl)), myRequestDetails);
return TypedBundleProvider.fromBundleProvider(c).getAllResources();
var b = this.myDaoRegistry.getResourceDao(theResourceType)
.search(new SearchParameterMap().add("url", new UriParam(theUrl)), myRequestDetails);
return new BundleIterable(myRequestDetails, b);
}

View File

@ -21,7 +21,6 @@ package ca.uhn.fhir.cr.common;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -31,13 +30,11 @@ import org.opencds.cqf.cql.engine.fhir.searchparam.SearchParameterResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.function.BiFunction;
/**
* This class provides an implementation of the cql-engine's RetrieveProvider
@ -51,6 +48,7 @@ public class HapiFhirRetrieveProvider extends SearchParamFhirRetrieveProvider im
private final DaoRegistry myDaoRegistry;
private final RequestDetails myRequestDetails;
public HapiFhirRetrieveProvider(DaoRegistry theDaoRegistry, SearchParameterResolver theSearchParameterResolver) {
this(theDaoRegistry, theSearchParameterResolver, new SystemRequestDetails());
}
@ -62,47 +60,98 @@ public class HapiFhirRetrieveProvider extends SearchParamFhirRetrieveProvider im
this.myRequestDetails = requestDetails;
}
/**
* The queryIterable class provides an Iterable to cycle through a series of search queries and results of those queries, implementation of this avoided loading all resources into a list.
*/
static class QueryIterable implements Iterable<Object> {
private final String dataType;
private final List<SearchParameterMap> queries;
private final BiFunction<String, SearchParameterMap, Iterable<IBaseResource>> queryFunc;
public QueryIterable(String dataType, List<SearchParameterMap> queries, BiFunction<String, SearchParameterMap, Iterable<IBaseResource>> queryFunc) {
this.dataType = dataType;
this.queries = queries;
this.queryFunc = queryFunc;
}
static class QueryIterator implements Iterator<Object> {
private final String dataType;
private final List<SearchParameterMap> queries;
private final BiFunction<String, SearchParameterMap, Iterable<IBaseResource>> queryFunc;
Iterator<IBaseResource> currentResult = null;
public QueryIterator(String dataType, List<SearchParameterMap> queries, BiFunction<String, SearchParameterMap, Iterable<IBaseResource>> queryFunc) {
this.dataType = dataType;
this.queries = queries;
this.queryFunc = queryFunc;
}
private int index = 0;
@Override
public boolean hasNext() {
// initial load of first query results
if (currentResult == null && index < queries.size()) {
currentResult = loadNext();
}
// when query results exhaust load next query
else if (!currentResult.hasNext()) {
currentResult = loadNext();
}
// hasNext on current query result
return currentResult != null && currentResult.hasNext();
}
@Override
public Object next() {
return currentResult.next();
}
Iterator<IBaseResource> loadNext() {
// check to make sure there are more queries remaining
if (index >= queries.size()) {
return null;
}
//extract next query result
var result = this.queryFunc.apply(dataType, queries.get(index)).iterator();
index++;
return result;
}
}
public Iterator<Object> iterator() {
return new QueryIterator(dataType, queries, queryFunc);
}
}
@Override
protected Iterable<Object> executeQueries(String dataType, List<SearchParameterMap> queries) {
if (queries == null || queries.isEmpty()) {
return Collections.emptyList();
}
List<Object> objects = new ArrayList<>();
for (SearchParameterMap map : queries) {
objects.addAll(executeQuery(dataType, map));
return new QueryIterable(dataType, queries, this::executeQuery);
}
return objects;
}
protected List<IBaseResource> executeQuery(String dataType, SearchParameterMap map) {
// TODO: Once HAPI breaks this out from the server dependencies
// we can include it on its own.
ca.uhn.fhir.jpa.searchparam.SearchParameterMap hapiMap = ca.uhn.fhir.jpa.searchparam.SearchParameterMap
.newSynchronous();
protected Iterable<IBaseResource> executeQuery(String dataType, SearchParameterMap map) {
ca.uhn.fhir.jpa.searchparam.SearchParameterMap hapiMap = new ca.uhn.fhir.jpa.searchparam.SearchParameterMap();
try {
Method[] methods = hapiMap.getClass().getDeclaredMethods();
List<Method> methodList = Arrays.asList(methods);
List<Method> puts = methodList.stream().filter(x -> x.getName().equals("put")).collect(Collectors.toList());
Method method = puts.get(0);
method.setAccessible(true);
for (Map.Entry<String, List<List<IQueryParameterType>>> entry : map.entrySet()) {
method.invoke(hapiMap, entry.getKey(), entry.getValue());
hapiMap.put(entry.getKey(), entry.getValue());
}
} catch (Exception e) {
logger.warn("Error converting search parameter map", e);
}
IBundleProvider bundleProvider = search(getClass(dataType), hapiMap, myRequestDetails);
if (bundleProvider.isEmpty()) {
return new ArrayList<>();
}
return bundleProvider.getAllResources();
return search(getClass(dataType), hapiMap, myRequestDetails);
}
@Override

View File

@ -30,7 +30,7 @@ import org.opencds.cqf.cql.evaluator.fhir.util.Versions;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.List;
import java.util.ArrayList;
/**
* This class provides an implementation of the cql-translator's LibrarySourceProvider
@ -56,14 +56,18 @@ public class HapiLibrarySourceProvider
return this.myDaoRegistry;
}
@Override
public InputStream getLibraryContent(VersionedIdentifier theLibraryIdentifier,
LibraryContentType theLibraryContentType) {
String name = theLibraryIdentifier.getId();
String version = theLibraryIdentifier.getVersion();
List<IBaseResource> libraries = search(getClass("Library"), Searches.byName(name), myRequestDetails)
.getAllResources();
IBaseResource library = Versions.selectByVersion(libraries, version,
var libraries = search(getClass("Library"), Searches.byName(name), myRequestDetails);
var libraryList = new ArrayList<IBaseResource>();
for(var l:libraries){
libraryList.add(l);
}
IBaseResource library = Versions.selectByVersion(libraryList, version,
Libraries::getVersion);
if (library == null) {

View File

@ -225,7 +225,7 @@ public interface IDaoRegistryUser {
* @param theSearchMap the Search Parameters
* @return Bundle provider
*/
default <T extends IBaseResource> TypedBundleProvider<T> search(Class<T> theResourceClass,
default <T extends IBaseResource> Iterable<IBaseResource> search(Class<T> theResourceClass,
SearchParameterMap theSearchMap) {
checkNotNull(theResourceClass);
checkNotNull(theSearchMap);
@ -243,13 +243,13 @@ public interface IDaoRegistryUser {
* @param theRequestDetails multi-tenancy information
* @return Bundle provider
*/
default <T extends IBaseResource> TypedBundleProvider<T> search(Class<T> theResourceClass,
default <T extends IBaseResource> Iterable<IBaseResource> search(Class<T> theResourceClass,
SearchParameterMap theSearchMap,
RequestDetails theRequestDetails) {
checkNotNull(theResourceClass);
checkNotNull(theSearchMap);
return TypedBundleProvider.fromBundleProvider(
getDaoRegistry().getResourceDao(theResourceClass).search(theSearchMap, theRequestDetails));
var provider = getDaoRegistry().getResourceDao(theResourceClass).search(theSearchMap, theRequestDetails);
return new BundleIterable(theRequestDetails, provider);
}
}

View File

@ -56,20 +56,6 @@ public class Searches {
* Creates and returns Parameter search results
*/
public static SearchParameterMap all() {
return sync();
}
/**
* Creates and returns Parameter search results
*/
public static SearchParameterMap sync() {
return SearchParameterMap.newSynchronous();
}
/**
* Creates and returns Parameter search results
*/
public static SearchParameterMap async() {
return new SearchParameterMap();
}
@ -84,7 +70,7 @@ public class Searches {
checkNotNull(theParamName);
checkNotNull(theParam);
return sync().add(theParamName, theParam);
return all().add(theParamName, theParam);
}
/**
@ -155,7 +141,7 @@ public class Searches {
params.addOr(new UriParam(theUrl));
});
return sync().add(ID_SP, params);
return all().add(ID_SP, params);
}
/**
@ -263,6 +249,6 @@ public class Searches {
params.addOr(new TokenParam(theIdPart));
});
return sync().add(ID_SP, params);
return all().add(ID_SP, params);
}
}

View File

@ -1,121 +0,0 @@
/*-
* #%L
* HAPI FHIR - Clinical Reasoning
* %%
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package ca.uhn.fhir.cr.common;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
public class TypedBundleProvider<T extends IBaseResource> implements IBundleProvider {
private final IBundleProvider myInnerProvider;
private TypedBundleProvider(IBundleProvider theInnerProvider) {
checkState(theInnerProvider.getNextPageId() == null,
"TypedBundleProvider does not support paging and theInnerProvider has a next page.");
myInnerProvider = checkNotNull(theInnerProvider);
}
public static <T extends IBaseResource> TypedBundleProvider<T> fromBundleProvider(
IBundleProvider theBundleProvider) {
return new TypedBundleProvider<>(theBundleProvider);
}
@Override
public IPrimitiveType<Date> getPublished() {
return myInnerProvider.getPublished();
}
@Override
public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
return myInnerProvider.getResources(theFromIndex, theToIndex);
}
@Override
public String getUuid() {
return myInnerProvider.getUuid();
}
@Override
public Integer preferredPageSize() {
return myInnerProvider.preferredPageSize();
}
@Override
public Integer size() {
return myInnerProvider.size();
}
@Override
public List<IBaseResource> getAllResources() {
var size = size();
if (size == null) {
return getResources(0, Integer.MAX_VALUE);
} else {
return getResources(0, size);
}
}
@SuppressWarnings("unchecked")
public List<T> getResourcesTyped(int theFromIndex, int theToIndex) {
return myInnerProvider.getResources(theFromIndex, theToIndex).stream().map(x -> (T) x)
.collect(Collectors.toList());
}
@SuppressWarnings("unchecked")
public List<T> getAllResourcesTyped() {
return myInnerProvider.getAllResources().stream().map(x -> (T) x).collect(Collectors.toList());
}
/**
* Returns exactly one Resource. Throws an error if zero or more than one
* resource is found or if zero resources are found
*
* @return the Resource found.
*/
public T single() {
List<T> resources = getResourcesTyped(0, 2);
checkState(!resources.isEmpty(), "No resources found");
checkState(resources.size() == 1, "More than one resource found");
return resources.get(0);
}
/**
* Returns the first Resource found, or null if no resources are found.
*
* @return the first Resource found or null
*/
public T firstOrNull() {
List<T> resources = getResourcesTyped(0, 1);
if (resources.isEmpty()) {
return null;
}
return resources.get(0);
}
}

View File

@ -59,7 +59,6 @@ import org.opencds.cqf.cql.engine.fhir.searchparam.SearchParameterResolver;
import org.opencds.cqf.cql.engine.model.ModelResolver;
import org.opencds.cqf.cql.engine.runtime.Code;
import org.opencds.cqf.cql.evaluator.CqlOptions;
import org.opencds.cqf.cql.evaluator.builder.Constants;
import org.opencds.cqf.cql.evaluator.builder.DataProviderComponents;
import org.opencds.cqf.cql.evaluator.builder.EndpointInfo;
import org.opencds.cqf.cql.evaluator.cql2elm.model.CacheAwareModelManager;
@ -68,6 +67,7 @@ import org.opencds.cqf.cql.evaluator.engine.execution.CacheAwareLibraryLoaderDec
import org.opencds.cqf.cql.evaluator.engine.execution.TranslatingLibraryLoader;
import org.opencds.cqf.cql.evaluator.engine.model.CachingModelResolverDecorator;
import org.opencds.cqf.cql.evaluator.engine.retrieve.BundleRetrieveProvider;
import org.opencds.cqf.cql.evaluator.fhir.Constants;
import org.opencds.cqf.cql.evaluator.fhir.adapter.AdapterFactory;
import org.opencds.cqf.cql.evaluator.measure.MeasureEvaluationOptions;
import org.opencds.cqf.cql.evaluator.spring.fhir.adapter.AdapterConfiguration;
@ -120,9 +120,13 @@ public abstract class BaseClinicalReasoningConfig {
@Bean
public MeasureEvaluationOptions measureEvaluationOptions(CrProperties theCrProperties) {
return theCrProperties.getMeasure().getMeasureEvaluation();
theCrProperties.getMeasure();
MeasureEvaluationOptions measureEvaluation = theCrProperties.getMeasure().getMeasureEvaluation();
return measureEvaluation;
}
@Bean
public CqlOptions cqlOptions(CrProperties theCrProperties) {
return theCrProperties.getCql().getOptions();

View File

@ -27,9 +27,14 @@ import org.opencds.cqf.cql.evaluator.measure.MeasureEvaluationOptions;
public class CrProperties {
private boolean enabled = true;
private MeasureProperties measureProperties = new MeasureProperties();
private MeasureProperties measureProperties;
private CqlProperties cqlProperties = new CqlProperties();
public CrProperties () {
this.measureProperties = new MeasureProperties();
};
public boolean isEnabled() {
return enabled;
}
@ -56,13 +61,27 @@ public class CrProperties {
public static class MeasureProperties {
private boolean threadedCareGapsEnabled = true;
private MeasureReportConfiguration measureReportConfiguration;
private MeasureEvaluationOptions measureEvaluationOptions;
private MeasureEvaluationOptions measureEvaluationOptions = MeasureEvaluationOptions.defaultOptions();
public MeasureProperties() {
measureEvaluationOptions = MeasureEvaluationOptions.defaultOptions();
measureEvaluationOptions.setNumThreads(4);
measureEvaluationOptions.setThreadedBatchSize(250);
measureEvaluationOptions.setThreadedEnabled(true);
};
//eval options
public MeasureEvaluationOptions getMeasureEvaluation() {
return this.measureEvaluationOptions;
}
public void setMeasureEvaluation(MeasureEvaluationOptions measureEvaluation) {
this.measureEvaluationOptions = measureEvaluation;
}
//care gaps
public boolean getThreadedCareGapsEnabled() {
return threadedCareGapsEnabled;
}
@ -71,6 +90,7 @@ public class CrProperties {
this.threadedCareGapsEnabled = enabled;
}
//report configuration
public MeasureReportConfiguration getMeasureReport() {
return this.measureReportConfiguration;
}
@ -79,13 +99,7 @@ public class CrProperties {
this.measureReportConfiguration = measureReport;
}
public MeasureEvaluationOptions getMeasureEvaluation() {
return this.measureEvaluationOptions;
}
public void setMeasureEvaluation(MeasureEvaluationOptions measureEvaluation) {
this.measureEvaluationOptions = measureEvaluation;
}
public static class MeasureReportConfiguration {
/**

View File

@ -57,10 +57,10 @@ public interface ISupplementalDataSearchParamUser extends IDaoRegistryUser {
new Coding(CODING_SYSTEM_CODE, CODING_COUNTRY_CODE, CODING_COUNTRY_DISPLAY)));
default void ensureSupplementalDataElementSearchParameter(RequestDetails theRequestDetails) {
if (!search(SearchParameter.class,
if (search(SearchParameter.class,
Searches.byUrlAndVersion(MEASUREREPORT_SUPPLEMENTALDATA_SEARCHPARAMETER_URL,
MEASUREREPORT_SUPPLEMENTALDATA_SEARCHPARAMETER_VERSION),
theRequestDetails).isEmpty()) {
theRequestDetails).iterator().hasNext()) {
return;
}

View File

@ -48,10 +48,10 @@ public interface ISupplementalDataSearchParamUser extends IDaoRegistryUser {
new Coding("urn:iso:std:iso:3166", "US", "United States of America")));
default void ensureSupplementalDataElementSearchParameter(RequestDetails theRequestDetails) {
if (!search(SearchParameter.class,
if (search(SearchParameter.class,
Searches.byUrlAndVersion(MEASUREREPORT_SUPPLEMENTALDATA_SEARCHPARAMETER_URL,
MEASUREREPORT_SUPPLEMENTALDATA_SEARCHPARAMETER_VERSION),
theRequestDetails).isEmpty()) {
theRequestDetails).iterator().hasNext()) {
return;
}

View File

@ -31,6 +31,7 @@ import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.server.IPagingProvider;
import org.apache.commons.lang3.StringUtils;
import org.cqframework.cql.cql2elm.LibrarySourceProvider;
import org.hl7.fhir.instance.model.api.IBaseResource;

View File

@ -23,7 +23,6 @@ import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

View File

@ -4,10 +4,8 @@ import ca.uhn.fhir.cr.BaseCrDstu3Test;
import ca.uhn.fhir.cr.dstu3.measure.MeasureOperationsProvider;
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
import io.specto.hoverfly.junit.core.Hoverfly;
import io.specto.hoverfly.junit.dsl.StubServiceBuilder;
import io.specto.hoverfly.junit5.HoverflyExtension;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Endpoint;
import org.hl7.fhir.dstu3.model.IdType;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -15,10 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static io.specto.hoverfly.junit.core.SimulationSource.dsl;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -26,13 +21,13 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
@ExtendWith(HoverflyExtension.class)
class MeasureOperationsProviderTest extends BaseCrDstu3Test {
@Autowired
MeasureOperationsProvider measureOperationsProvider;
MeasureOperationsProvider myMeasureOperationsProvider;
@Test
void testMeasureEvaluate() throws IOException {
loadBundle("Exm105Fhir3Measure.json");
var returnMeasureReport = this.measureOperationsProvider.evaluateMeasure(
var returnMeasureReport = this.myMeasureOperationsProvider.evaluateMeasure(
new IdType("Measure", "measure-EXM105-FHIR3-8.0.000"),
"2019-01-01",
"2020-01-01",
@ -56,7 +51,7 @@ class MeasureOperationsProviderTest extends BaseCrDstu3Test {
var additionalData = readResource(Bundle.class, "Exm105FhirR3MeasureAdditionalData.json");
var patient = "Patient/denom-EXM105-FHIR3";
var returnMeasureReport = this.measureOperationsProvider.evaluateMeasure(
var returnMeasureReport = this.myMeasureOperationsProvider.evaluateMeasure(
new IdType("Measure", "measure-EXM105-FHIR3-8.0.000"),
"2019-01-01",
"2020-01-01",
@ -77,14 +72,8 @@ class MeasureOperationsProviderTest extends BaseCrDstu3Test {
@Test
void testMeasureEvaluateWithTerminology(Hoverfly hoverfly) throws IOException {
loadBundle("Exm105Fhir3Measure.json");
List<StubServiceBuilder> reads = new ArrayList<>();
reads.addAll(mockValueSet("2.16.840.1.114222.4.11.3591", "http://cts.nlm.nih.gov/fhir/ValueSet"));
reads.addAll(mockValueSet("2.16.840.1.113883.3.117.1.7.1.424", "http://cts.nlm.nih.gov/fhir/ValueSet"));
hoverfly.simulate(dsl(reads.toArray(new StubServiceBuilder[0])));
var terminologyEndpoint = loadResource(ourFhirContext, Endpoint.class, "Endpoint.json");
var returnMeasureReport = this.measureOperationsProvider.evaluateMeasure(
var returnMeasureReport = this.myMeasureOperationsProvider.evaluateMeasure(
new IdType("Measure", "measure-EXM105-FHIR3-8.0.000"),
"2019-01-01",
"2020-01-01",
@ -94,7 +83,7 @@ class MeasureOperationsProviderTest extends BaseCrDstu3Test {
"2019-12-12",
null,
null,
terminologyEndpoint,
null,
new SystemRequestDetails()
);

View File

@ -0,0 +1,34 @@
package ca.uhn.fhir.cr.r4;
import ca.uhn.fhir.cr.BaseCrR4Test;
import ca.uhn.fhir.cr.common.BundleIterable;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import com.google.common.collect.Iterables;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ExtendWith(SpringExtension.class)
public class BundleIterableR4Test extends BaseCrR4Test {
private static final RequestDetails theRequestDetails = null;
private static final String MY_TEST_DATA = "ca/uhn/fhir/cr/r4/immunization/Patients_Encounters_Immunizations_Practitioners.json";
@Test
public void searchAllPatients() {
// load bundle
loadBundle(MY_TEST_DATA); //63 patients
var bundle1 = searchPatient(); //return BundleIterable
var firstCount = Iterables.size(bundle1); //count Patients
assertEquals(63, firstCount);
}
public Iterable<IBaseResource> searchPatient() {
var b = this.myDaoRegistry.getResourceDao("Patient")
.search(new SearchParameterMap(), theRequestDetails);
return new BundleIterable(theRequestDetails, b);
}
}

View File

@ -2,6 +2,7 @@ package ca.uhn.fhir.cr.r4;
import ca.uhn.fhir.cr.BaseCrR4Test;
import ca.uhn.fhir.cr.common.HapiFhirDal;
import ca.uhn.fhir.rest.server.IPagingProvider;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
@ -36,4 +37,5 @@ public class HapiFhirDalR4Test extends BaseCrR4Test {
//verify all patient resources captured
assertEquals(63, counter, "Patient search results don't match available resources");
}
}

View File

@ -4,9 +4,7 @@ import ca.uhn.fhir.cr.BaseCrR4Test;
import ca.uhn.fhir.cr.r4.measure.MeasureOperationsProvider;
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
import io.specto.hoverfly.junit.core.Hoverfly;
import io.specto.hoverfly.junit.dsl.StubServiceBuilder;
import io.specto.hoverfly.junit5.HoverflyExtension;
import org.hl7.fhir.r4.model.Endpoint;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.MeasureReport;
import org.hl7.fhir.r4.model.Observation;
@ -17,27 +15,23 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import static io.specto.hoverfly.junit.core.SimulationSource.dsl;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ExtendWith(SpringExtension.class)
@ExtendWith(HoverflyExtension.class)
class MeasureOperationsProviderTest extends BaseCrR4Test {
@Autowired
MeasureOperationsProvider measureOperationsProvider;
MeasureOperationsProvider myMeasureOperationsProvider;
@Test
void testMeasureEvaluate() throws IOException {
loadBundle("Exm104FhirR4MeasureBundle.json");
var returnMeasureReport = this.measureOperationsProvider.evaluateMeasure(
var returnMeasureReport = this.myMeasureOperationsProvider.evaluateMeasure(
new IdType("Measure", "measure-EXM104-8.2.000"),
"2019-01-01",
"2020-01-01",
@ -57,17 +51,8 @@ class MeasureOperationsProviderTest extends BaseCrR4Test {
@Test
void testMeasureEvaluateWithTerminologyEndpoint(Hoverfly hoverfly) throws IOException {
loadBundle("Exm104FhirR4MeasureBundle.json");
List<StubServiceBuilder> reads = new ArrayList<>();
reads.addAll(mockValueSet("2.16.840.1.114222.4.11.3591", "http://localhost:8080/fhir/ValueSet"));
reads.addAll(mockValueSet("2.16.840.1.113883.3.117.1.7.1.424", "http://localhost:8080/fhir/ValueSet"));
hoverfly.simulate(dsl(reads.toArray(new StubServiceBuilder[0])));
var terminologyEndpointValid = readResource(Endpoint.class, "Endpoint.json");
var terminologyEndpointInvalid = readResource(Endpoint.class, "Endpoint.json");
terminologyEndpointInvalid.setAddress("https://tx.nhsnlink.org/fhir234");
var returnMeasureReport = this.measureOperationsProvider.evaluateMeasure(
var returnMeasureReport = this.myMeasureOperationsProvider.evaluateMeasure(
new IdType("Measure", "measure-EXM104-8.2.000"),
"2019-01-01",
"2020-01-01",
@ -77,33 +62,17 @@ class MeasureOperationsProviderTest extends BaseCrR4Test {
"2019-12-12",
null,
null,
terminologyEndpointValid,
null,
new SystemRequestDetails()
);
assertNotNull(returnMeasureReport);
var ex = assertThrows(Exception.class, () -> this.measureOperationsProvider.evaluateMeasure(
new IdType("Measure", "measure-EXM104-8.2.000"),
"2019-01-01",
"2020-01-01",
"subject",
"Patient/numer-EXM104",
null,
"2019-12-12",
null,
null,
terminologyEndpointInvalid,
new SystemRequestDetails()
));
assertTrue(ex.getMessage().contains("Error performing expansion"));
}
private void runWithPatient(String measureId, String patientId, int initialPopulationCount, int denominatorCount,
int denominatorExclusionCount, int numeratorCount, boolean enrolledDuringParticipationPeriod,
String participationPeriod) {
MeasureReport returnMeasureReport = this.measureOperationsProvider.evaluateMeasure(
var returnMeasureReport = this.myMeasureOperationsProvider.evaluateMeasure(
new IdType("Measure", measureId),
"2022-01-01",
"2022-12-31",
@ -179,7 +148,7 @@ class MeasureOperationsProviderTest extends BaseCrR4Test {
var measure = read(new IdType("Measure", "InitialInpatientPopulation"));
assertNotNull(measure);
MeasureReport returnMeasureReport = this.measureOperationsProvider.evaluateMeasure(
MeasureReport returnMeasureReport = this.myMeasureOperationsProvider.evaluateMeasure(
new IdType("Measure", "InitialInpatientPopulation"),
"2019-01-01",
"2020-01-01",
@ -211,7 +180,7 @@ class MeasureOperationsProviderTest extends BaseCrR4Test {
this.loadBundle("multiversion/EXM124-7.0.000-bundle.json");
this.loadBundle("multiversion/EXM124-9.0.000-bundle.json");
MeasureReport returnMeasureReportVersion7 = this.measureOperationsProvider.evaluateMeasure(
MeasureReport returnMeasureReportVersion7 = this.myMeasureOperationsProvider.evaluateMeasure(
new IdType("Measure", "measure-EXM124-7.0.000"),
"2019-01-01",
"2020-01-01",
@ -225,7 +194,7 @@ class MeasureOperationsProviderTest extends BaseCrR4Test {
assertNotNull(returnMeasureReportVersion7);
MeasureReport returnMeasureReportVersion9 = this.measureOperationsProvider.evaluateMeasure(
MeasureReport returnMeasureReportVersion9 = this.myMeasureOperationsProvider.evaluateMeasure(
new IdType("Measure", "measure-EXM124-9.0.000"),
"2019-01-01",
"2020-01-01",

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -7,7 +7,8 @@
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<packaging>pom</packaging>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<name>HAPI-FHIR</name>
<description>An open-source implementation of the FHIR specification in Java.</description>
<url>https://hapifhir.io</url>
@ -957,9 +958,9 @@
<elastic_apm_version>1.28.4</elastic_apm_version>
<!-- CQL Support -->
<cqframework.version>2.4.0</cqframework.version>
<cql-engine.version>2.3.0</cql-engine.version>
<cql-evaluator.version>2.3.0</cql-evaluator.version>
<cqframework.version>2.7.0-SNAPSHOT</cqframework.version>
<cql-engine.version>3.0.0-SNAPSHOT</cql-engine.version>
<cql-evaluator.version>3.0.0-SNAPSHOT</cql-evaluator.version>
<!-- Site properties -->
<fontawesomeVersion>5.4.1</fontawesomeVersion>

View File

@ -6,7 +6,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,8 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.5.8-SNAPSHOT</version>
<version>6.5.9-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>