add partition support to $evaluate-measure (#2736)

* Finished adding partition support to $evaluate-measure

* review feedback
This commit is contained in:
Ken Stevens 2021-06-18 14:22:57 -04:00 committed by GitHub
parent 5d246bcca8
commit 097a2f70b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 592 additions and 362 deletions

View File

@ -0,0 +1,4 @@
---
type: add
issue: 2735
title: "The $evaluate-measure now works on a partitioned server."

View File

@ -345,8 +345,8 @@ public class RequestPartitionHelperSvc implements IRequestPartitionHelperSvc {
}
private void validateRequestPartitionNotNull(RequestPartitionId theTheRequestPartitionId, Pointcut theThePointcut) {
if (theTheRequestPartitionId == null) {
private void validateRequestPartitionNotNull(RequestPartitionId theRequestPartitionId, Pointcut theThePointcut) {
if (theRequestPartitionId == null) {
throw new InternalErrorException("No interceptor provided a value for pointcut: " + theThePointcut);
}
}

View File

@ -20,18 +20,19 @@ package ca.uhn.fhir.cql.common.provider;
* #L%
*/
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.opencds.cqf.cql.engine.data.DataProvider;
import org.opencds.cqf.cql.engine.terminology.TerminologyProvider;
// TODO: This interface is a partial duplicate of the provider factory interface
// in the cql service layer. We need another round of refactoring to consolidate that.
public interface EvaluationProviderFactory {
public DataProvider createDataProvider(String model, String version);
DataProvider createDataProvider(String model, String version, RequestDetails theRequestDetails);
public DataProvider createDataProvider(String model, String version, String url, String user, String pass);
DataProvider createDataProvider(String model, String version, String url, String user, String pass, RequestDetails theRequestDetails);
public DataProvider createDataProvider(String model, String version, TerminologyProvider terminologyProvider);
DataProvider createDataProvider(String model, String version, TerminologyProvider terminologyProvider, RequestDetails theRequestDetails);
public TerminologyProvider createTerminologyProvider(String model, String version, String url, String user,
String pass);
TerminologyProvider createTerminologyProvider(String model, String version, String url, String user,
String pass);
}

View File

@ -20,51 +20,12 @@ package ca.uhn.fhir.cql.common.provider;
* #L%
*/
import ca.uhn.fhir.rest.api.server.RequestDetails;
import java.util.function.Function;
public interface LibraryResolutionProvider<LibraryType> {
public LibraryType resolveLibraryById(String libraryId);
public LibraryType resolveLibraryByName(String libraryName, String libraryVersion);
public LibraryType resolveLibraryByCanonicalUrl(String libraryUrl);
// Hmmm... Probably need to think through this use case a bit more.
// Should we throw an exception? Should this be a different interface?
public void update(LibraryType library);
// This function assumes that you're selecting from a set of libraries with the same name.
// It returns the closest matching version, or the max version if no version is specified.
static <LibraryType> LibraryType selectFromList(Iterable<LibraryType> libraries, String libraryVersion, Function<LibraryType, String> getVersion) {
LibraryType library = null;
LibraryType maxVersion = null;
for (LibraryType l : libraries) {
String currentVersion = getVersion.apply(l);
if ((libraryVersion != null && currentVersion.equals(libraryVersion)) ||
(libraryVersion == null && currentVersion == null))
{
library = l;
}
if (maxVersion == null || compareVersions(
getVersion.apply(maxVersion),
getVersion.apply(l) ) < 0){
maxVersion = l;
}
}
// If we were not given a version, return the highest found
if (libraryVersion == null && maxVersion != null) {
return maxVersion;
}
return library;
}
public static int compareVersions(String version1, String version2)
{
static int compareVersions(String version1, String version2) {
// Treat null as MAX VERSION
if (version1 == null && version2 == null) {
return 0;
@ -94,8 +55,7 @@ public interface LibraryResolutionProvider<LibraryType> {
return 1;
}
//Making sure Version1 smaller than version2
else if(v1 < v2)
{
else if (v1 < v2) {
return -1;
}
}
@ -103,4 +63,42 @@ public interface LibraryResolutionProvider<LibraryType> {
//Both are equal
return 0;
}
LibraryType resolveLibraryById(String libraryId, RequestDetails theRequestDetails);
LibraryType resolveLibraryByName(String libraryName, String libraryVersion);
LibraryType resolveLibraryByCanonicalUrl(String libraryUrl, RequestDetails theRequestDetails);
// This function assumes that you're selecting from a set of libraries with the same name.
// It returns the closest matching version, or the max version if no version is specified.
static <LibraryType> LibraryType selectFromList(Iterable<LibraryType> libraries, String libraryVersion, Function<LibraryType, String> getVersion) {
LibraryType library = null;
LibraryType maxVersion = null;
for (LibraryType l : libraries) {
String currentVersion = getVersion.apply(l);
if ((libraryVersion != null && currentVersion.equals(libraryVersion)) ||
(libraryVersion == null && currentVersion == null)) {
library = l;
}
if (maxVersion == null || compareVersions(
getVersion.apply(maxVersion),
getVersion.apply(l)) < 0) {
maxVersion = l;
}
}
// If we were not given a version, return the highest found
if (libraryVersion == null && maxVersion != null) {
return maxVersion;
}
return library;
}
// Hmmm... Probably need to think through this use case a bit more.
// Should we throw an exception? Should this be a different interface?
void update(LibraryType library);
}

View File

@ -24,6 +24,7 @@ import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.model.api.IQueryParameterType;
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 org.opencds.cqf.cql.engine.fhir.retrieve.SearchParamFhirRetrieveProvider;
import org.opencds.cqf.cql.engine.fhir.searchparam.SearchParameterMap;
@ -45,21 +46,23 @@ import java.util.stream.Collectors;
@Component
public class JpaFhirRetrieveProvider extends SearchParamFhirRetrieveProvider {
private static final Logger logger = LoggerFactory.getLogger(JpaFhirRetrieveProvider.class);
private static final Logger logger = LoggerFactory.getLogger(JpaFhirRetrieveProvider.class);
DaoRegistry registry;
private final DaoRegistry registry;
private final RequestDetails myRequestDetails;
@Autowired
public JpaFhirRetrieveProvider(DaoRegistry registry, SearchParameterResolver searchParameterResolver) {
super(searchParameterResolver);
this.registry = registry;
}
@Autowired
public JpaFhirRetrieveProvider(DaoRegistry registry, SearchParameterResolver searchParameterResolver, RequestDetails theRequestDetails) {
super(searchParameterResolver);
this.registry = registry;
myRequestDetails = theRequestDetails;
}
@Override
protected Iterable<Object> executeQueries(String dataType, List<SearchParameterMap> queries) {
if (queries == null || queries.isEmpty()) {
return Collections.emptyList();
}
@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) {
@ -91,7 +94,7 @@ public class JpaFhirRetrieveProvider extends SearchParamFhirRetrieveProvider {
IFhirResourceDao<?> dao = this.registry.getResourceDao(dataType);
IBundleProvider bundleProvider = dao.search(hapiMap);
IBundleProvider bundleProvider = dao.search(hapiMap, myRequestDetails);
if (bundleProvider.size() == null) {
return resolveResourceList(bundleProvider.getResources(0, 10000));
}

View File

@ -26,6 +26,7 @@ import ca.uhn.fhir.cql.dstu3.builder.MeasureReportBuilder;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.ReferenceParam;
import org.cqframework.cql.elm.execution.ExpressionDef;
import org.cqframework.cql.elm.execution.FunctionDef;
@ -74,17 +75,17 @@ public class MeasureEvaluation {
this.measurementPeriod = measurementPeriod;
}
public MeasureReport evaluatePatientMeasure(Measure measure, Context context, String patientId) {
public MeasureReport evaluatePatientMeasure(Measure measure, Context context, String patientId, RequestDetails theRequestDetails) {
logger.info("Generating individual report");
if (patientId == null) {
return evaluatePopulationMeasure(measure, context);
}
return evaluatePopulationMeasure(measure, context, theRequestDetails);
}
Patient patient = registry.getResourceDao(Patient.class).read(new IdType(patientId));
// Iterable<Object> patientRetrieve = provider.retrieve("Patient", "id",
// patientId, "Patient", null, null, null, null, null, null, null, null);
// Patient patient = null;
Patient patient = registry.getResourceDao(Patient.class).read(new IdType(patientId), theRequestDetails);
// Iterable<Object> patientRetrieve = provider.retrieve("Patient", "id",
// patientId, "Patient", null, null, null, null, null, null, null, null);
// Patient patient = null;
// if (patientRetrieve.iterator().hasNext()) {
// patient = (Patient) patientRetrieve.iterator().next();
// }
@ -92,45 +93,47 @@ public class MeasureEvaluation {
boolean isSingle = true;
return evaluate(measure, context,
return evaluate(measure, context,
patient == null ? Collections.emptyList() : Collections.singletonList(patient),
MeasureReport.MeasureReportType.INDIVIDUAL, isSingle);
}
public MeasureReport evaluatePatientListMeasure(Measure measure, Context context, String practitionerRef) {
logger.info("Generating patient-list report");
public MeasureReport evaluatePatientListMeasure(Measure measure, Context context, String practitionerRef, RequestDetails theRequestDetails) {
logger.info("Generating patient-list report");
List<Patient> patients = practitionerRef == null ? getAllPatients() : getPractitionerPatients(practitionerRef);
boolean isSingle = false;
return evaluate(measure, context, patients, MeasureReport.MeasureReportType.PATIENTLIST, isSingle);
}
List<Patient> patients = practitionerRef == null ? getAllPatients(theRequestDetails) : getPractitionerPatients(practitionerRef, theRequestDetails);
boolean isSingle = false;
return evaluate(measure, context, patients, MeasureReport.MeasureReportType.PATIENTLIST, isSingle);
}
private List<Patient> getPractitionerPatients(String practitionerRef) {
SearchParameterMap map = SearchParameterMap.newSynchronous();
map.add("general-practitioner", new ReferenceParam(
practitionerRef.startsWith("Practitioner/") ? practitionerRef : "Practitioner/" + practitionerRef));
private List<Patient> getPractitionerPatients(String practitionerRef, RequestDetails theRequestDetails) {
SearchParameterMap map = SearchParameterMap.newSynchronous();
map.add("general-practitioner", new ReferenceParam(
practitionerRef.startsWith("Practitioner/") ? practitionerRef : "Practitioner/" + practitionerRef));
List<Patient> patients = new ArrayList<>();
IBundleProvider patientProvider = registry.getResourceDao("Patient").search(map);
List<IBaseResource> patientList = patientProvider.getAllResources();
patientList.forEach(x -> patients.add((Patient) x));
return patients;
}
List<Patient> patients = new ArrayList<>();
IBundleProvider patientProvider = registry.getResourceDao("Patient").search(map, theRequestDetails);
List<IBaseResource> patientList = patientProvider.getAllResources();
patientList.forEach(x -> patients.add((Patient) x));
return patients;
}
private List<Patient> getAllPatients() {
List<Patient> patients = new ArrayList<>();
IBundleProvider patientProvider = registry.getResourceDao("Patient").search(SearchParameterMap.newSynchronous());
List<IBaseResource> patientList = patientProvider.getAllResources();
patientList.forEach(x -> patients.add((Patient) x));
return patients;
}
private List<Patient> getAllPatients(RequestDetails theRequestDetails) {
List<Patient> patients = new ArrayList<>();
IBundleProvider patientProvider = registry.getResourceDao("Patient").search(SearchParameterMap.newSynchronous(), theRequestDetails);
List<IBaseResource> patientList = patientProvider.getAllResources();
patientList.forEach(x -> patients.add((Patient) x));
return patients;
}
public MeasureReport evaluatePopulationMeasure(Measure measure, Context context) {
logger.info("Generating summary report");
public MeasureReport evaluatePopulationMeasure(Measure measure, Context context, RequestDetails theRequestDetails) {
logger.info("Generating summary report");
boolean isSingle = false;
return evaluate(measure, context, getAllPatients(), MeasureReport.MeasureReportType.SUMMARY, isSingle);
}
boolean isSingle = false;
return evaluate(measure, context, getAllPatients(theRequestDetails), MeasureReport.MeasureReportType.SUMMARY, isSingle);
}
@SuppressWarnings("unchecked")
private void clearExpressionCache(Context context) {

View File

@ -25,6 +25,7 @@ import ca.uhn.fhir.cql.common.helper.UsingHelper;
import ca.uhn.fhir.cql.common.provider.EvaluationProviderFactory;
import ca.uhn.fhir.cql.common.provider.LibraryResolutionProvider;
import ca.uhn.fhir.cql.dstu3.helper.LibraryHelper;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.apache.commons.lang3.tuple.Triple;
import org.cqframework.cql.elm.execution.Library;
import org.hl7.fhir.dstu3.model.Measure;
@ -74,13 +75,13 @@ public class MeasureEvaluationSeed {
}
public void setup(Measure measure, String periodStart, String periodEnd, String productLine, String source,
String user, String pass) {
String user, String pass, RequestDetails theRequestDetails) {
this.measure = measure;
this.libraryHelper.loadLibraries(measure, this.libraryLoader, this.libraryResourceProvider);
this.libraryHelper.loadLibraries(measure, this.libraryLoader, this.libraryResourceProvider, theRequestDetails);
// resolve primary library
Library library = this.libraryHelper.resolvePrimaryLibrary(measure, libraryLoader, this.libraryResourceProvider);
Library library = this.libraryHelper.resolvePrimaryLibrary(measure, libraryLoader, this.libraryResourceProvider, theRequestDetails);
// resolve execution context
context = new Context(library);
@ -90,7 +91,7 @@ public class MeasureEvaluationSeed {
if (usingDefs.size() > 1) {
throw new IllegalArgumentException(
"Evaluation of Measure using multiple Models is not supported at this time.");
"Evaluation of Measure using multiple Models is not supported at this time.");
}
// If there are no Usings, there is probably not any place the Terminology
@ -108,7 +109,7 @@ public class MeasureEvaluationSeed {
for (Triple<String, String, String> def : usingDefs) {
this.dataProvider = this.providerFactory.createDataProvider(def.getLeft(), def.getMiddle(),
terminologyProvider);
terminologyProvider, theRequestDetails);
context.registerDataProvider(def.getRight(), dataProvider);
}

View File

@ -24,6 +24,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.cql.common.provider.EvaluationProviderFactory;
import ca.uhn.fhir.cql.common.retrieve.JpaFhirRetrieveProvider;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.opencds.cqf.cql.engine.data.CompositeDataProvider;
import org.opencds.cqf.cql.engine.data.DataProvider;
import org.opencds.cqf.cql.engine.fhir.searchparam.SearchParameterResolver;
@ -38,40 +39,40 @@ import org.springframework.stereotype.Component;
@Component
public class ProviderFactory implements EvaluationProviderFactory {
DaoRegistry registry;
TerminologyProvider defaultTerminologyProvider;
FhirContext fhirContext;
ModelResolver fhirModelResolver;
private final DaoRegistry registry;
private final TerminologyProvider defaultTerminologyProvider;
private final FhirContext fhirContext;
private final ModelResolver fhirModelResolver;
@Autowired
public ProviderFactory(FhirContext fhirContext, DaoRegistry registry,
TerminologyProvider defaultTerminologyProvider, ModelResolver fhirModelResolver) {
this.defaultTerminologyProvider = defaultTerminologyProvider;
this.registry = registry;
this.fhirContext = fhirContext;
this.fhirModelResolver = fhirModelResolver;
TerminologyProvider defaultTerminologyProvider, ModelResolver fhirModelResolver) {
this.defaultTerminologyProvider = defaultTerminologyProvider;
this.registry = registry;
this.fhirContext = fhirContext;
this.fhirModelResolver = fhirModelResolver;
}
public DataProvider createDataProvider(String model, String version) {
return this.createDataProvider(model, version, null, null, null);
}
public DataProvider createDataProvider(String model, String version, RequestDetails theRequestDetails) {
return this.createDataProvider(model, version, null, null, null, theRequestDetails);
}
public DataProvider createDataProvider(String model, String version, String url, String user, String pass) {
TerminologyProvider terminologyProvider = this.createTerminologyProvider(model, version, url, user, pass);
return this.createDataProvider(model, version, terminologyProvider);
}
public DataProvider createDataProvider(String model, String version, String url, String user, String pass, RequestDetails theRequestDetails) {
TerminologyProvider terminologyProvider = this.createTerminologyProvider(model, version, url, user, pass);
return this.createDataProvider(model, version, terminologyProvider, theRequestDetails);
}
public DataProvider createDataProvider(String model, String version, TerminologyProvider terminologyProvider) {
if (model.equals("FHIR") && version.startsWith("3")) {
JpaFhirRetrieveProvider retrieveProvider = new JpaFhirRetrieveProvider(this.registry,
new SearchParameterResolver(this.fhirContext));
retrieveProvider.setTerminologyProvider(terminologyProvider);
retrieveProvider.setExpandValueSets(true);
public DataProvider createDataProvider(String model, String version, TerminologyProvider terminologyProvider, RequestDetails theRequestDetails) {
if (model.equals("FHIR") && version.startsWith("3")) {
JpaFhirRetrieveProvider retrieveProvider = new JpaFhirRetrieveProvider(this.registry,
new SearchParameterResolver(this.fhirContext), theRequestDetails);
retrieveProvider.setTerminologyProvider(terminologyProvider);
retrieveProvider.setExpandValueSets(true);
return new CompositeDataProvider(this.fhirModelResolver, retrieveProvider);
}
return new CompositeDataProvider(this.fhirModelResolver, retrieveProvider);
}
throw new IllegalArgumentException(
throw new IllegalArgumentException(
String.format("Can't construct a data provider for model %s version %s", model, version));
}

View File

@ -20,11 +20,10 @@ package ca.uhn.fhir.cql.dstu3.helper;
* #L%
*/
import ca.uhn.fhir.cql.common.provider.LibraryResolutionProvider;
import org.apache.commons.lang3.StringUtils;
import org.cqframework.cql.cql2elm.LibraryManager;
import ca.uhn.fhir.cql.common.provider.LibraryContentProvider;
import ca.uhn.fhir.cql.common.provider.LibraryResolutionProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.apache.commons.lang3.StringUtils;
import org.cqframework.cql.cql2elm.CqlTranslatorOptions;
import org.cqframework.cql.cql2elm.ModelManager;
import org.cqframework.cql.cql2elm.model.Model;
@ -36,11 +35,12 @@ import org.hl7.fhir.dstu3.model.Measure;
import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.dstu3.model.RelatedArtifact;
import org.hl7.fhir.dstu3.model.Resource;
import org.opencds.cqf.cql.engine.execution.LibraryLoader;
import org.opencds.cqf.cql.evaluator.cql2elm.model.CacheAwareModelManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.opencds.cqf.cql.evaluator.engine.execution.CacheAwareLibraryLoaderDecorator;
import org.opencds.cqf.cql.evaluator.engine.execution.TranslatingLibraryLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
@ -51,8 +51,8 @@ public class LibraryHelper {
private static final Logger ourLog = LoggerFactory.getLogger(LibraryHelper.class);
private final Map<org.hl7.elm.r1.VersionedIdentifier, Model> modelCache;
private Map<VersionedIdentifier, Library> libraryCache;
private CqlTranslatorOptions translatorOptions;
private final Map<VersionedIdentifier, Library> libraryCache;
private final CqlTranslatorOptions translatorOptions;
public LibraryHelper(Map<org.hl7.elm.r1.VersionedIdentifier, Model> modelCache, Map<VersionedIdentifier, Library> libraryCache, CqlTranslatorOptions translatorOptions) {
@ -72,8 +72,8 @@ public class LibraryHelper {
}
public List<Library> loadLibraries(Measure measure,
org.opencds.cqf.cql.engine.execution.LibraryLoader libraryLoader,
LibraryResolutionProvider<org.hl7.fhir.dstu3.model.Library> libraryResourceProvider) {
LibraryLoader libraryLoader,
LibraryResolutionProvider<org.hl7.fhir.dstu3.model.Library> libraryResourceProvider, RequestDetails theRequestDetails) {
List<org.cqframework.cql.elm.execution.Library> libraries = new ArrayList<Library>();
List<String> messages = new ArrayList<>();
@ -96,7 +96,7 @@ public class LibraryHelper {
id = id.substring(1);
}
org.hl7.fhir.dstu3.model.Library library = libraryResourceProvider.resolveLibraryById(id);
org.hl7.fhir.dstu3.model.Library library = libraryResourceProvider.resolveLibraryById(id, theRequestDetails);
if (library != null) {
if (isLogicLibrary(library)) {
libraries.add(libraryLoader
@ -119,11 +119,11 @@ public class LibraryHelper {
for (RelatedArtifact artifact : primaryLibrary.getRelatedArtifact()) {
if (artifact.hasType() && artifact.getType().equals(RelatedArtifact.RelatedArtifactType.DEPENDSON) && artifact.hasResource() && artifact.getResource().hasReference()) {
if (artifact.getResource().getReferenceElement().getResourceType().equals("Library")) {
org.hl7.fhir.dstu3.model.Library library = libraryResourceProvider.resolveLibraryById(artifact.getResource().getReferenceElement().getIdPart());
org.hl7.fhir.dstu3.model.Library library = libraryResourceProvider.resolveLibraryById(artifact.getResource().getReferenceElement().getIdPart(), theRequestDetails);
if (library != null) {
if (isLogicLibrary(library)) {
libraries.add(libraryLoader
.load(new VersionedIdentifier().withId(library.getName()).withVersion(library.getVersion())));
.load(new VersionedIdentifier().withId(library.getName()).withVersion(library.getVersion())));
} else {
ourLog.warn("Library {} not included as part of evaluation context. Only Libraries with the 'logic-library' type are included.", library.getId());
}
@ -169,22 +169,22 @@ public class LibraryHelper {
}
public Library resolveLibraryById(String libraryId,
org.opencds.cqf.cql.engine.execution.LibraryLoader libraryLoader,
LibraryResolutionProvider<org.hl7.fhir.dstu3.model.Library> libraryResourceProvider) {
LibraryLoader libraryLoader,
LibraryResolutionProvider<org.hl7.fhir.dstu3.model.Library> libraryResourceProvider, RequestDetails theRequestDetails) {
// Library library = null;
org.hl7.fhir.dstu3.model.Library fhirLibrary = libraryResourceProvider.resolveLibraryById(libraryId);
org.hl7.fhir.dstu3.model.Library fhirLibrary = libraryResourceProvider.resolveLibraryById(libraryId, theRequestDetails);
return libraryLoader
.load(new VersionedIdentifier().withId(fhirLibrary.getName()).withVersion(fhirLibrary.getVersion()));
}
public Library resolvePrimaryLibrary(Measure measure,
org.opencds.cqf.cql.engine.execution.LibraryLoader libraryLoader,
LibraryResolutionProvider<org.hl7.fhir.dstu3.model.Library> libraryResourceProvider) {
LibraryLoader libraryLoader,
LibraryResolutionProvider<org.hl7.fhir.dstu3.model.Library> libraryResourceProvider, RequestDetails theRequestDetails) {
// default is the first library reference
String id = measure.getLibraryFirstRep().getReferenceElement().getIdPart();
Library library = resolveLibraryById(id, libraryLoader, libraryResourceProvider);
Library library = resolveLibraryById(id, libraryLoader, libraryResourceProvider, theRequestDetails);
if (library == null) {
throw new IllegalArgumentException(String.format("Could not resolve primary library for Measure/%s.",

View File

@ -22,7 +22,9 @@ package ca.uhn.fhir.cql.dstu3.provider;
import ca.uhn.fhir.cql.common.provider.LibraryResolutionProvider;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.UriParam;
@ -48,16 +50,16 @@ public class LibraryResolutionProviderImpl implements LibraryResolutionProvider<
}
@Override
public Library resolveLibraryById(String libraryId) {
public Library resolveLibraryById(String libraryId, RequestDetails theRequestDetails) {
try {
return myLibraryDao.read(new IdType(libraryId));
return myLibraryDao.read(new IdType(libraryId), theRequestDetails);
} catch (Exception e) {
throw new IllegalArgumentException(String.format("Could not resolve library id %s", libraryId));
}
}
@Override
public Library resolveLibraryByCanonicalUrl(String url) {
public Library resolveLibraryByCanonicalUrl(String url, RequestDetails theRequestDetails) {
Objects.requireNonNull(url, "url must not be null");
String[] parts = url.split("\\|");
@ -73,7 +75,7 @@ public class LibraryResolutionProviderImpl implements LibraryResolutionProvider<
map.add("version", new TokenParam(version));
}
ca.uhn.fhir.rest.api.server.IBundleProvider bundleProvider = myLibraryDao.search(map);
ca.uhn.fhir.rest.api.server.IBundleProvider bundleProvider = myLibraryDao.search(map, theRequestDetails);
if (bundleProvider.size() == null || bundleProvider.size() == 0) {
return null;
@ -99,7 +101,7 @@ public class LibraryResolutionProviderImpl implements LibraryResolutionProvider<
// Search for libraries by name
SearchParameterMap map = SearchParameterMap.newSynchronous();
map.add("name", new StringParam(name, true));
ca.uhn.fhir.rest.api.server.IBundleProvider bundleProvider = myLibraryDao.search(map);
ca.uhn.fhir.rest.api.server.IBundleProvider bundleProvider = myLibraryDao.search(map, new SystemRequestDetails());
if (bundleProvider.size() == null || bundleProvider.size() == 0) {
return new ArrayList<>();

View File

@ -30,6 +30,7 @@ import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
import org.hl7.fhir.dstu3.model.Extension;
@ -81,17 +82,18 @@ public class MeasureOperationsProvider {
@OperationParam(name = "lastReceivedOn") String lastReceivedOn,
@OperationParam(name = "source") String source,
@OperationParam(name = "user") String user,
@OperationParam(name = "pass") String pass) throws InternalErrorException, FHIRException {
@OperationParam(name = "pass") String pass,
RequestDetails theRequestDetails) throws InternalErrorException, FHIRException {
LibraryLoader libraryLoader = this.libraryHelper.createLibraryLoader(this.libraryResolutionProvider);
MeasureEvaluationSeed seed = new MeasureEvaluationSeed(this.factory, libraryLoader,
this.libraryResolutionProvider, this.libraryHelper);
Measure measure = myMeasureDao.read(theId);
Measure measure = myMeasureDao.read(theId, theRequestDetails);
if (measure == null) {
throw new RuntimeException("Could not find Measure/" + theId.getIdPart());
}
seed.setup(measure, periodStart, periodEnd, productLine, source, user, pass);
seed.setup(measure, periodStart, periodEnd, productLine, source, user, pass, theRequestDetails);
// resolve report type
MeasureEvaluation evaluator = new MeasureEvaluation(this.registry,
@ -99,18 +101,18 @@ public class MeasureOperationsProvider {
if (reportType != null) {
switch (reportType) {
case "patient":
return evaluator.evaluatePatientMeasure(seed.getMeasure(), seed.getContext(), patientRef);
return evaluator.evaluatePatientMeasure(seed.getMeasure(), seed.getContext(), patientRef, theRequestDetails);
case "patient-list":
return evaluator.evaluatePatientListMeasure(seed.getMeasure(), seed.getContext(), practitionerRef);
return evaluator.evaluatePatientListMeasure(seed.getMeasure(), seed.getContext(), practitionerRef, theRequestDetails);
case "population":
return evaluator.evaluatePopulationMeasure(seed.getMeasure(), seed.getContext());
return evaluator.evaluatePopulationMeasure(seed.getMeasure(), seed.getContext(), theRequestDetails);
default:
throw new IllegalArgumentException("Invalid report type: " + reportType);
}
}
// default report type is patient
MeasureReport report = evaluator.evaluatePatientMeasure(seed.getMeasure(), seed.getContext(), patientRef);
MeasureReport report = evaluator.evaluatePatientMeasure(seed.getMeasure(), seed.getContext(), patientRef, theRequestDetails);
if (productLine != null) {
Extension ext = new Extension();
ext.setUrl("http://hl7.org/fhir/us/cqframework/cqfmeasures/StructureDefinition/cqfm-productLine");

View File

@ -26,6 +26,7 @@ import ca.uhn.fhir.cql.r4.builder.MeasureReportBuilder;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.ReferenceParam;
import org.cqframework.cql.elm.execution.ExpressionDef;
import org.cqframework.cql.elm.execution.FunctionDef;
@ -77,15 +78,15 @@ public class MeasureEvaluation {
this.measurementPeriod = measurementPeriod;
}
public MeasureReport evaluatePatientMeasure(Measure measure, Context context, String patientId) {
public MeasureReport evaluatePatientMeasure(Measure measure, Context context, String patientId, RequestDetails theRequestDetails) {
logger.info("Generating individual report");
if (patientId == null) {
return evaluatePopulationMeasure(measure, context);
return evaluatePopulationMeasure(measure, context, theRequestDetails);
}
Iterable<Object> patientRetrieve = provider.retrieve("Patient", "id", patientId, "Patient", null, null, null,
null, null, null, null, null);
null, null, null, null, null);
Patient patient = null;
if (patientRetrieve.iterator().hasNext()) {
patient = (Patient) patientRetrieve.iterator().next();
@ -93,42 +94,42 @@ public class MeasureEvaluation {
boolean isSingle = true;
return evaluate(measure, context, patient == null ? Collections.emptyList() : Collections.singletonList(patient),
MeasureReport.MeasureReportType.INDIVIDUAL, isSingle);
MeasureReport.MeasureReportType.INDIVIDUAL, isSingle);
}
public MeasureReport evaluateSubjectListMeasure(Measure measure, Context context, String practitionerRef) {
public MeasureReport evaluateSubjectListMeasure(Measure measure, Context context, String practitionerRef, RequestDetails theRequestDetails) {
logger.info("Generating patient-list report");
List<Patient> patients = practitionerRef == null ? getAllPatients() : getPractitionerPatients(practitionerRef);
List<Patient> patients = practitionerRef == null ? getAllPatients(theRequestDetails) : getPractitionerPatients(practitionerRef, theRequestDetails);
boolean isSingle = false;
return evaluate(measure, context, patients, MeasureReport.MeasureReportType.SUBJECTLIST, isSingle);
}
private List<Patient> getPractitionerPatients(String practitionerRef) {
private List<Patient> getPractitionerPatients(String practitionerRef, RequestDetails theRequestDetails) {
SearchParameterMap map = SearchParameterMap.newSynchronous();
map.add("general-practitioner", new ReferenceParam(
practitionerRef.startsWith("Practitioner/") ? practitionerRef : "Practitioner/" + practitionerRef));
List<Patient> patients = new ArrayList<>();
IBundleProvider patientProvider = registry.getResourceDao("Patient").search(map);
IBundleProvider patientProvider = registry.getResourceDao("Patient").search(map, theRequestDetails);
List<IBaseResource> patientList = patientProvider.getAllResources();
patientList.forEach(x -> patients.add((Patient) x));
return patients;
}
private List<Patient> getAllPatients() {
private List<Patient> getAllPatients(RequestDetails theRequestDetails) {
List<Patient> patients = new ArrayList<>();
IBundleProvider patientProvider = registry.getResourceDao("Patient").search(SearchParameterMap.newSynchronous());
IBundleProvider patientProvider = registry.getResourceDao("Patient").search(SearchParameterMap.newSynchronous(), theRequestDetails);
List<IBaseResource> patientList = patientProvider.getAllResources();
patientList.forEach(x -> patients.add((Patient) x));
return patients;
}
public MeasureReport evaluatePopulationMeasure(Measure measure, Context context) {
public MeasureReport evaluatePopulationMeasure(Measure measure, Context context, RequestDetails theRequestDetails) {
logger.info("Generating summary report");
boolean isSingle = false;
return evaluate(measure, context, getAllPatients(), MeasureReport.MeasureReportType.SUMMARY, isSingle);
return evaluate(measure, context, getAllPatients(theRequestDetails), MeasureReport.MeasureReportType.SUMMARY, isSingle);
}
@SuppressWarnings("unchecked")

View File

@ -25,6 +25,7 @@ import ca.uhn.fhir.cql.common.helper.UsingHelper;
import ca.uhn.fhir.cql.common.provider.EvaluationProviderFactory;
import ca.uhn.fhir.cql.common.provider.LibraryResolutionProvider;
import ca.uhn.fhir.cql.r4.helper.LibraryHelper;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.apache.commons.lang3.tuple.Triple;
import org.cqframework.cql.elm.execution.Library;
import org.hl7.fhir.r4.model.Measure;
@ -74,13 +75,13 @@ public class MeasureEvaluationSeed {
}
public void setup(Measure measure, String periodStart, String periodEnd, String productLine, String source,
String user, String pass) {
String user, String pass, RequestDetails theRequestDetails) {
this.measure = measure;
this.libraryHelper.loadLibraries(measure, this.libraryLoader, this.libraryResourceProvider);
this.libraryHelper.loadLibraries(measure, this.libraryLoader, this.libraryResourceProvider, theRequestDetails);
// resolve primary library
Library library = this.libraryHelper.resolvePrimaryLibrary(measure, libraryLoader, this.libraryResourceProvider);
Library library = this.libraryHelper.resolvePrimaryLibrary(measure, libraryLoader, this.libraryResourceProvider, theRequestDetails);
// resolve execution context
@ -109,7 +110,7 @@ public class MeasureEvaluationSeed {
for (Triple<String, String, String> def : usingDefs) {
this.dataProvider = this.providerFactory.createDataProvider(def.getLeft(), def.getMiddle(),
terminologyProvider);
terminologyProvider, theRequestDetails);
context.registerDataProvider(def.getRight(), dataProvider);
}

View File

@ -24,6 +24,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.cql.common.provider.EvaluationProviderFactory;
import ca.uhn.fhir.cql.common.retrieve.JpaFhirRetrieveProvider;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.opencds.cqf.cql.engine.data.CompositeDataProvider;
import org.opencds.cqf.cql.engine.data.DataProvider;
import org.opencds.cqf.cql.engine.fhir.searchparam.SearchParameterResolver;
@ -51,19 +52,19 @@ public class ProviderFactory implements EvaluationProviderFactory {
myModelResolver = theFhirModelResolver;
}
public DataProvider createDataProvider(String model, String version) {
return this.createDataProvider(model, version, null, null, null);
public DataProvider createDataProvider(String model, String version, RequestDetails theRequestDetails) {
return this.createDataProvider(model, version, null, null, null, theRequestDetails);
}
public DataProvider createDataProvider(String model, String version, String url, String user, String pass) {
public DataProvider createDataProvider(String model, String version, String url, String user, String pass, RequestDetails theRequestDetails) {
TerminologyProvider terminologyProvider = this.createTerminologyProvider(model, version, url, user, pass);
return this.createDataProvider(model, version, terminologyProvider);
return this.createDataProvider(model, version, terminologyProvider, theRequestDetails);
}
public DataProvider createDataProvider(String model, String version, TerminologyProvider terminologyProvider) {
public DataProvider createDataProvider(String model, String version, TerminologyProvider terminologyProvider, RequestDetails theRequestDetails) {
if (model.equals("FHIR") && version.startsWith("4")) {
JpaFhirRetrieveProvider retrieveProvider = new JpaFhirRetrieveProvider(myDaoRegistry,
new SearchParameterResolver(myFhirContext));
new SearchParameterResolver(myFhirContext), theRequestDetails);
retrieveProvider.setTerminologyProvider(terminologyProvider);
retrieveProvider.setExpandValueSets(true);

View File

@ -20,10 +20,9 @@ package ca.uhn.fhir.cql.r4.helper;
* #L%
*/
import ca.uhn.fhir.cql.common.provider.LibraryResolutionProvider;
import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.cql.common.provider.LibraryContentProvider;
import ca.uhn.fhir.cql.common.provider.LibraryResolutionProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.cqframework.cql.cql2elm.CqlTranslatorOptions;
import org.cqframework.cql.cql2elm.LibraryManager;
import org.cqframework.cql.cql2elm.ModelManager;
@ -37,11 +36,13 @@ import org.hl7.fhir.r4.model.Measure;
import org.hl7.fhir.r4.model.PlanDefinition;
import org.hl7.fhir.r4.model.RelatedArtifact;
import org.hl7.fhir.r4.model.Resource;
import org.opencds.cqf.cql.engine.execution.LibraryLoader;
import org.opencds.cqf.cql.evaluator.cql2elm.model.CacheAwareModelManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.opencds.cqf.cql.evaluator.engine.execution.CacheAwareLibraryLoaderDecorator;
import org.opencds.cqf.cql.evaluator.engine.execution.TranslatingLibraryLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -54,18 +55,18 @@ public class LibraryHelper {
private static final Logger ourLog = LoggerFactory.getLogger(LibraryHelper.class);
private final Map<org.hl7.elm.r1.VersionedIdentifier, Model> modelCache;
private Map<VersionedIdentifier, Library> libraryCache;
private CqlTranslatorOptions translatorOptions;
private final Map<VersionedIdentifier, Library> libraryCache;
private final CqlTranslatorOptions translatorOptions;
public LibraryHelper(Map<org.hl7.elm.r1.VersionedIdentifier, Model> modelCache,
Map<VersionedIdentifier, Library> libraryCache, CqlTranslatorOptions translatorOptions) {
Map<VersionedIdentifier, Library> libraryCache, CqlTranslatorOptions translatorOptions) {
this.modelCache = modelCache;
this.libraryCache = libraryCache;
this.translatorOptions = translatorOptions;
}
public org.opencds.cqf.cql.engine.execution.LibraryLoader createLibraryLoader(
LibraryResolutionProvider<org.hl7.fhir.r4.model.Library> provider) {
LibraryResolutionProvider<org.hl7.fhir.r4.model.Library> provider) {
ModelManager modelManager = new CacheAwareModelManager(this.modelCache);
LibraryManager libraryManager = new LibraryManager(modelManager);
libraryManager.getLibrarySourceLoader().clearProviders();
@ -90,22 +91,22 @@ public class LibraryHelper {
}
public org.hl7.fhir.r4.model.Library resolveLibraryReference(
LibraryResolutionProvider<org.hl7.fhir.r4.model.Library> libraryResourceProvider, String reference) {
LibraryResolutionProvider<org.hl7.fhir.r4.model.Library> libraryResourceProvider, String reference, RequestDetails theRequestDetails) {
// Raw references to Library/libraryId or libraryId
if (reference.startsWith("Library/") || !reference.contains("/")) {
return libraryResourceProvider.resolveLibraryById(reference.replace("Library/", ""));
return libraryResourceProvider.resolveLibraryById(reference.replace("Library/", ""), theRequestDetails);
}
// Full url (e.g. http://hl7.org/fhir/us/Library/FHIRHelpers)
else if (reference.contains(("/Library/"))) {
return libraryResourceProvider.resolveLibraryByCanonicalUrl(reference);
return libraryResourceProvider.resolveLibraryByCanonicalUrl(reference, theRequestDetails);
}
return null;
}
public List<org.cqframework.cql.elm.execution.Library> loadLibraries(Measure measure,
org.opencds.cqf.cql.engine.execution.LibraryLoader libraryLoader,
LibraryResolutionProvider<org.hl7.fhir.r4.model.Library> libraryResourceProvider) {
LibraryLoader libraryLoader,
LibraryResolutionProvider<org.hl7.fhir.r4.model.Library> libraryResourceProvider, RequestDetails theRequestDetails) {
List<org.cqframework.cql.elm.execution.Library> libraries = new ArrayList<org.cqframework.cql.elm.execution.Library>();
// load libraries
@ -118,21 +119,21 @@ public class LibraryHelper {
id = id.substring(1);
for (Resource resource : measure.getContained()) {
if (resource instanceof org.hl7.fhir.r4.model.Library
&& resource.getIdElement().getIdPart().equals(id)) {
&& resource.getIdElement().getIdPart().equals(id)) {
libraryResourceProvider.update((org.hl7.fhir.r4.model.Library) resource);
}
}
}
// We just loaded it into the server so we can access it by Id
org.hl7.fhir.r4.model.Library library = resolveLibraryReference(libraryResourceProvider, id);
org.hl7.fhir.r4.model.Library library = resolveLibraryReference(libraryResourceProvider, id, theRequestDetails);
if (primaryLibrary == null) {
primaryLibrary = library;
}
if (library != null && isLogicLibrary(library)) {
libraries.add(libraryLoader
.load(new VersionedIdentifier().withId(library.getName()).withVersion(library.getVersion())));
.load(new VersionedIdentifier().withId(library.getName()).withVersion(library.getVersion())));
}
}
@ -145,12 +146,12 @@ public class LibraryHelper {
if (artifact.hasType() && artifact.getType().equals(RelatedArtifact.RelatedArtifactType.DEPENDSON)
&& artifact.hasResource()) {
org.hl7.fhir.r4.model.Library library = null;
library = resolveLibraryReference(libraryResourceProvider, artifact.getResource());
library = resolveLibraryReference(libraryResourceProvider, artifact.getResource(), theRequestDetails);
if (library != null) {
if (isLogicLibrary(library)) {
libraries.add(libraryLoader
.load(new VersionedIdentifier().withId(library.getName()).withVersion(library.getVersion())));
.load(new VersionedIdentifier().withId(library.getName()).withVersion(library.getVersion())));
} else {
ourLog.warn("Library {} not included as part of evaluation context. Only Libraries with the 'logic-library' type are included.", library.getId());
}
@ -187,7 +188,7 @@ public class LibraryHelper {
for (Coding c : library.getType().getCoding()) {
if (c.hasSystem() && c.getSystem().equals("http://terminology.hl7.org/CodeSystem/library-type") && c.hasCode()
&& c.getCode().equals("logic-library")) {
&& c.getCode().equals("logic-library")) {
return true;
}
}
@ -195,40 +196,40 @@ public class LibraryHelper {
return false;
}
public Library resolveLibraryById(String libraryId, org.opencds.cqf.cql.engine.execution.LibraryLoader libraryLoader,
LibraryResolutionProvider<org.hl7.fhir.r4.model.Library> libraryResourceProvider) {
public Library resolveLibraryById(String libraryId, LibraryLoader libraryLoader,
LibraryResolutionProvider<org.hl7.fhir.r4.model.Library> libraryResourceProvider, RequestDetails theRequestDetails) {
org.hl7.fhir.r4.model.Library fhirLibrary = libraryResourceProvider.resolveLibraryById(libraryId);
org.hl7.fhir.r4.model.Library fhirLibrary = libraryResourceProvider.resolveLibraryById(libraryId, theRequestDetails);
return libraryLoader
.load(new VersionedIdentifier().withId(fhirLibrary.getName()).withVersion(fhirLibrary.getVersion()));
.load(new VersionedIdentifier().withId(fhirLibrary.getName()).withVersion(fhirLibrary.getVersion()));
}
public Library resolvePrimaryLibrary(Measure measure,
org.opencds.cqf.cql.engine.execution.LibraryLoader libraryLoader,
LibraryResolutionProvider<org.hl7.fhir.r4.model.Library> libraryResourceProvider) {
LibraryLoader libraryLoader,
LibraryResolutionProvider<org.hl7.fhir.r4.model.Library> libraryResourceProvider, RequestDetails theRequestDetails) {
// default is the first library reference
String id = CanonicalHelper.getId(measure.getLibrary().get(0));
Library library = resolveLibraryById(id, libraryLoader, libraryResourceProvider);
Library library = resolveLibraryById(id, libraryLoader, libraryResourceProvider, theRequestDetails);
if (library == null) {
throw new IllegalArgumentException(
String.format("Could not resolve primary library for Measure/%s.", measure.getIdElement().getIdPart()));
String.format("Could not resolve primary library for Measure/%s.", measure.getIdElement().getIdPart()));
}
return library;
}
public Library resolvePrimaryLibrary(PlanDefinition planDefinition,
org.opencds.cqf.cql.engine.execution.LibraryLoader libraryLoader,
LibraryResolutionProvider<org.hl7.fhir.r4.model.Library> libraryResourceProvider) {
LibraryLoader libraryLoader,
LibraryResolutionProvider<org.hl7.fhir.r4.model.Library> libraryResourceProvider, RequestDetails theRequestDetails) {
String id = CanonicalHelper.getId(planDefinition.getLibrary().get(0));
Library library = resolveLibraryById(id, libraryLoader, libraryResourceProvider);
Library library = resolveLibraryById(id, libraryLoader, libraryResourceProvider, theRequestDetails);
if (library == null) {
throw new IllegalArgumentException(String.format("Could not resolve primary library for PlanDefinition/%s",
planDefinition.getIdElement().getIdPart()));
planDefinition.getIdElement().getIdPart()));
}
return library;

View File

@ -23,7 +23,9 @@ package ca.uhn.fhir.cql.r4.provider;
import ca.uhn.fhir.cql.common.provider.LibraryResolutionProvider;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.UriParam;
@ -54,9 +56,9 @@ public class LibraryResolutionProviderImpl implements LibraryResolutionProvider<
}
@Override
public Library resolveLibraryById(String libraryId) {
public Library resolveLibraryById(String libraryId, RequestDetails theRequestDetails) {
try {
return myLibraryDao.read(new IdType(libraryId));
return myLibraryDao.read(new IdType(libraryId), theRequestDetails);
} catch (Exception e) {
throw new IllegalArgumentException(String.format("Could not resolve library id %s", libraryId));
}
@ -64,7 +66,7 @@ public class LibraryResolutionProviderImpl implements LibraryResolutionProvider<
@Override
public Library resolveLibraryByName(String libraryName, String libraryVersion) {
Iterable<org.hl7.fhir.r4.model.Library> libraries = getLibrariesByName(libraryName);
Iterable<org.hl7.fhir.r4.model.Library> libraries = getLibrariesByName(libraryName, new SystemRequestDetails());
org.hl7.fhir.r4.model.Library library = LibraryResolutionProvider.selectFromList(libraries, libraryVersion,
x -> x.getVersion());
@ -76,7 +78,7 @@ public class LibraryResolutionProviderImpl implements LibraryResolutionProvider<
}
@Override
public Library resolveLibraryByCanonicalUrl(String url) {
public Library resolveLibraryByCanonicalUrl(String url, RequestDetails theRequestDetails) {
Objects.requireNonNull(url, "url must not be null");
String[] parts = url.split("\\|");
@ -92,7 +94,7 @@ public class LibraryResolutionProviderImpl implements LibraryResolutionProvider<
map.add("version", new TokenParam(version));
}
ca.uhn.fhir.rest.api.server.IBundleProvider bundleProvider = myLibraryDao.search(map);
ca.uhn.fhir.rest.api.server.IBundleProvider bundleProvider = myLibraryDao.search(map, theRequestDetails);
if (bundleProvider.size() == null || bundleProvider.size() == 0) {
return null;
@ -101,11 +103,11 @@ public class LibraryResolutionProviderImpl implements LibraryResolutionProvider<
return LibraryResolutionProvider.selectFromList(resolveLibraries(resourceList), version, x -> x.getVersion());
}
private Iterable<org.hl7.fhir.r4.model.Library> getLibrariesByName(String name) {
private Iterable<org.hl7.fhir.r4.model.Library> getLibrariesByName(String name, RequestDetails theRequestDetails) {
// Search for libraries by name
SearchParameterMap map = SearchParameterMap.newSynchronous();
map.add("name", new StringParam(name, true));
ca.uhn.fhir.rest.api.server.IBundleProvider bundleProvider = myLibraryDao.search(map);
ca.uhn.fhir.rest.api.server.IBundleProvider bundleProvider = myLibraryDao.search(map, theRequestDetails);
if (bundleProvider.size() == null || bundleProvider.size() == 0) {
return new ArrayList<>();

View File

@ -30,6 +30,7 @@ import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
import org.hl7.fhir.exceptions.FHIRException;
@ -82,36 +83,38 @@ public class MeasureOperationsProvider {
@OperationParam(name = "lastReceivedOn") String lastReceivedOn,
@OperationParam(name = "source") String source,
@OperationParam(name = "user") String user,
@OperationParam(name = "pass") String pass) throws InternalErrorException, FHIRException {
@OperationParam(name = "pass") String pass,
RequestDetails theRequestDetails) throws InternalErrorException, FHIRException {
LibraryLoader libraryLoader = this.libraryHelper.createLibraryLoader(this.libraryResolutionProvider);
MeasureEvaluationSeed seed = new MeasureEvaluationSeed(this.factory, libraryLoader,
this.libraryResolutionProvider, this.libraryHelper);
Measure measure = myMeasureDao.read(theId);
this.libraryResolutionProvider, this.libraryHelper);
Measure measure = myMeasureDao.read(theId, theRequestDetails);
if (measure == null) {
throw new RuntimeException("Could not find Measure/" + theId.getIdPart());
}
seed.setup(measure, periodStart, periodEnd, productLine, source, user, pass);
seed.setup(measure, periodStart, periodEnd, productLine, source, user, pass, theRequestDetails);
// resolve report type
MeasureEvaluation evaluator = new MeasureEvaluation(seed.getDataProvider(), this.registry,
seed.getMeasurementPeriod());
seed.getMeasurementPeriod());
if (reportType != null) {
switch (reportType) {
case "patient":
return evaluator.evaluatePatientMeasure(seed.getMeasure(), seed.getContext(), patientRef);
return evaluator.evaluatePatientMeasure(seed.getMeasure(), seed.getContext(), patientRef, theRequestDetails);
case "patient-list":
return evaluator.evaluateSubjectListMeasure(seed.getMeasure(), seed.getContext(), practitionerRef);
return evaluator.evaluateSubjectListMeasure(seed.getMeasure(), seed.getContext(), practitionerRef, theRequestDetails);
case "population":
return evaluator.evaluatePopulationMeasure(seed.getMeasure(), seed.getContext());
return evaluator.evaluatePopulationMeasure(seed.getMeasure(), seed.getContext(), theRequestDetails);
default:
throw new IllegalArgumentException("Invalid report type: " + reportType);
}
}
// default report type is patient
MeasureReport report = evaluator.evaluatePatientMeasure(seed.getMeasure(), seed.getContext(), patientRef);
MeasureReport report = evaluator.evaluatePatientMeasure(seed.getMeasure(), seed.getContext(), patientRef, theRequestDetails);
if (productLine != null) {
Extension ext = new Extension();
ext.setUrl("http://hl7.org/fhir/us/cqframework/cqfmeasures/StructureDefinition/cqfm-productLine");

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.cql;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.cql.common.helper.PartitionHelper;
import ca.uhn.fhir.cql.common.provider.CqlProviderTestBase;
import ca.uhn.fhir.cql.config.CqlDstu3Config;
import ca.uhn.fhir.cql.config.TestCqlConfig;
@ -8,12 +9,17 @@ import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.subscription.match.config.SubscriptionProcessorConfig;
import ca.uhn.fhir.jpa.test.BaseJpaDstu3Test;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.test.utilities.RequestDetailsHelper;
import org.apache.commons.io.FileUtils;
import org.hl7.fhir.dstu3.model.Bundle;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ -23,10 +29,11 @@ import java.io.IOException;
import java.util.Collection;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {TestCqlConfig.class, SubscriptionProcessorConfig.class, CqlDstu3Config.class})
@ContextConfiguration(classes = {TestCqlConfig.class, SubscriptionProcessorConfig.class, CqlDstu3Config.class, BaseCqlDstu3Test.Config.class})
public class BaseCqlDstu3Test extends BaseJpaDstu3Test implements CqlProviderTestBase {
Logger ourLog = LoggerFactory.getLogger(BaseCqlDstu3Test.class);
public static Logger ourLog = LoggerFactory.getLogger(BaseCqlDstu3Test.class);
protected final RequestDetails myRequestDetails = RequestDetailsHelper.newServletRequestDetails();
@Autowired
protected
DaoRegistry myDaoRegistry;
@ -35,17 +42,9 @@ public class BaseCqlDstu3Test extends BaseJpaDstu3Test implements CqlProviderTes
FhirContext myFhirContext;
@Autowired
IFhirSystemDao mySystemDao;
@Override
public FhirContext getFhirContext() {
return myFhirContext;
}
@Override
public DaoRegistry getDaoRegistry() {
return myDaoRegistry;
}
@Autowired
@RegisterExtension
protected PartitionHelper myPartitionHelper;
protected int loadDataFromDirectory(String theDirectoryName) throws IOException {
int count = 0;
@ -63,7 +62,7 @@ public class BaseCqlDstu3Test extends BaseJpaDstu3Test implements CqlProviderTes
if (filename.contains("bundle")) {
loadBundle(filename);
} else {
loadResource(filename);
loadResource(filename, myRequestDetails);
}
count++;
} else {
@ -73,18 +72,38 @@ public class BaseCqlDstu3Test extends BaseJpaDstu3Test implements CqlProviderTes
return count;
}
protected Bundle parseBundle(String theLocation) throws IOException {
@Override
public FhirContext getFhirContext() {
return myFhirContext;
}
@Override
public DaoRegistry getDaoRegistry() {
return myDaoRegistry;
}
protected Bundle loadBundle(Bundle bundle) {
return (Bundle) mySystemDao.transaction(myRequestDetails, bundle);
}
protected Bundle parseBundle(String theLocation) throws IOException {
String json = stringFromResource(theLocation);
Bundle bundle = (Bundle) myFhirContext.newJsonParser().parseResource(json);
return bundle;
}
protected Bundle loadBundle(Bundle bundle) {
return (Bundle) mySystemDao.transaction(null, bundle);
@Configuration
static class Config {
@Bean
public PartitionHelper myPartitionHelper() {
return new PartitionHelper();
}
}
protected Bundle loadBundle(String theLocation) throws IOException {
Bundle bundle = parseBundle(theLocation);
return loadBundle(bundle);
}
}

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.cql;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.cql.common.helper.PartitionHelper;
import ca.uhn.fhir.cql.common.provider.CqlProviderTestBase;
import ca.uhn.fhir.cql.config.CqlR4Config;
import ca.uhn.fhir.cql.config.TestCqlConfig;
@ -8,15 +9,17 @@ import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.subscription.match.config.SubscriptionProcessorConfig;
import ca.uhn.fhir.jpa.test.BaseJpaR4Test;
import ca.uhn.fhir.util.BundleUtil;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.test.utilities.RequestDetailsHelper;
import org.apache.commons.io.FileUtils;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.MeasureReport;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
@ -24,12 +27,16 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {CqlR4Config.class, TestCqlConfig.class, SubscriptionProcessorConfig.class})
@ContextConfiguration(classes = {CqlR4Config.class, TestCqlConfig.class, SubscriptionProcessorConfig.class, BaseCqlR4Test.Config.class})
public class BaseCqlR4Test extends BaseJpaR4Test implements CqlProviderTestBase {
Logger ourLog = LoggerFactory.getLogger(BaseCqlR4Test.class);
private static final Logger ourLog = LoggerFactory.getLogger(BaseCqlR4Test.class);
protected final RequestDetails myRequestDetails = RequestDetailsHelper.newServletRequestDetails();
@Autowired
@RegisterExtension
protected PartitionHelper myPartitionHelper;
@Autowired
protected
@ -40,16 +47,6 @@ public class BaseCqlR4Test extends BaseJpaR4Test implements CqlProviderTestBase
@Autowired
IFhirSystemDao mySystemDao;
@Override
public FhirContext getFhirContext() {
return myFhirContext;
}
@Override
public DaoRegistry getDaoRegistry() {
return myDaoRegistry;
}
protected int loadDataFromDirectory(String theDirectoryName) throws IOException {
int count = 0;
ourLog.info("Reading files in directory: {}", theDirectoryName);
@ -66,7 +63,7 @@ public class BaseCqlR4Test extends BaseJpaR4Test implements CqlProviderTestBase
if (filename.contains("bundle")) {
loadBundle(filename);
} else {
loadResource(filename);
loadResource(filename, myRequestDetails);
}
count++;
} else {
@ -76,18 +73,36 @@ public class BaseCqlR4Test extends BaseJpaR4Test implements CqlProviderTestBase
return count;
}
protected Bundle parseBundle(String theLocation) throws IOException {
@Override
public FhirContext getFhirContext() {
return myFhirContext;
}
@Override
public DaoRegistry getDaoRegistry() {
return myDaoRegistry;
}
protected Bundle loadBundle(String theLocation) throws IOException {
Bundle bundle = parseBundle(theLocation);
return loadBundle(bundle, myRequestDetails);
}
protected Bundle parseBundle(String theLocation) throws IOException {
String json = stringFromResource(theLocation);
Bundle bundle = (Bundle) myFhirContext.newJsonParser().parseResource(json);
return bundle;
}
protected Bundle loadBundle(Bundle bundle) {
return (Bundle) mySystemDao.transaction(null, bundle);
protected Bundle loadBundle(Bundle bundle, RequestDetails theRequestDetails) {
return (Bundle) mySystemDao.transaction(theRequestDetails, bundle);
}
protected Bundle loadBundle(String theLocation) throws IOException {
Bundle bundle = parseBundle(theLocation);
return loadBundle(bundle);
@Configuration
static class Config {
@Bean
public PartitionHelper myPartitionHelper() {
return new PartitionHelper();
}
}
}

View File

@ -0,0 +1,74 @@
package ca.uhn.fhir.cql.common.helper;
import ca.uhn.fhir.interceptor.api.Hook;
import ca.uhn.fhir.interceptor.api.IInterceptorService;
import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class PartitionHelper implements BeforeEachCallback, AfterEachCallback {
private static final Logger ourLog = LoggerFactory.getLogger(PartitionHelper.class);
protected final MyTestInterceptor myInterceptor = new MyTestInterceptor();
@Autowired
IInterceptorService myIInterceptorService;
@Autowired
PartitionSettings myPartitionSettings;
@Override
public void beforeEach(ExtensionContext context) throws Exception {
myPartitionSettings.setPartitioningEnabled(true);
myIInterceptorService.registerInterceptor(myInterceptor);
}
@Override
public void afterEach(ExtensionContext context) throws Exception {
myIInterceptorService.unregisterInterceptor(myInterceptor);
myPartitionSettings.setPartitioningEnabled(false);
myInterceptor.clear();
}
public void clear() {
myInterceptor.clear();
}
public boolean wasCalled() {
return myInterceptor.wasCalled();
}
public static class MyTestInterceptor {
private boolean myCalled = false;
@Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_READ)
RequestPartitionId partitionIdentifyRead(ServletRequestDetails theRequestDetails) {
myCalled = true;
if (theRequestDetails == null) {
ourLog.info("useful breakpoint :-)");
}
assertNotNull(theRequestDetails);
return RequestPartitionId.defaultPartition();
}
public void clear() {
myCalled = false;
}
public boolean wasCalled() {
return myCalled;
}
@Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_CREATE)
RequestPartitionId partitionIdentifyCreate(ServletRequestDetails theRequestDetails) {
return RequestPartitionId.defaultPartition();
}
}
}

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.cql.common.provider;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import com.google.common.base.Charsets;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -20,14 +21,14 @@ public interface CqlProviderTestBase {
DaoRegistry getDaoRegistry();
default IBaseResource loadResource(String theLocation) throws IOException {
default IBaseResource loadResource(String theLocation, RequestDetails theRequestDetails) throws IOException {
String json = stringFromResource(theLocation);
IBaseResource resource = getFhirContext().newJsonParser().parseResource(json);
IFhirResourceDao<IBaseResource> dao = getDaoRegistry().getResourceDao(resource.getIdElement().getResourceType());
if (dao == null) {
return null;
} else {
dao.update(resource);
dao.update(resource, theRequestDetails);
return resource;
}
}

View File

@ -1,17 +1,9 @@
package ca.uhn.fhir.cql.dstu3;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import ca.uhn.fhir.cql.BaseCqlDstu3Test;
import ca.uhn.fhir.cql.dstu3.provider.MeasureOperationsProvider;
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.util.BundleUtil;
import org.hamcrest.Matchers;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.DateTimeType;
@ -24,15 +16,24 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import ca.uhn.fhir.cql.BaseCqlDstu3Test;
import ca.uhn.fhir.cql.dstu3.provider.MeasureOperationsProvider;
import ca.uhn.fhir.util.BundleUtil;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
public class CqlMeasureEvaluationDstu3Test extends BaseCqlDstu3Test {
Logger ourLog = LoggerFactory.getLogger(CqlMeasureEvaluationDstu3Test.class);
@Autowired
MeasureOperationsProvider myMeasureOperationsProvider;
private final SystemRequestDetails mySrd = new SystemRequestDetails();
protected void testMeasureBundle(String theLocation) throws IOException {
Bundle bundle = parseBundle(theLocation);
@ -62,11 +63,11 @@ public class CqlMeasureEvaluationDstu3Test extends BaseCqlDstu3Test {
this.ourLog.info("Measure: %s, Patient: %s, Start: %s, End: %s", measureId, patientId, periodStart, periodEnd);
MeasureReport actual = this.myMeasureOperationsProvider.evaluateMeasure(new IdType("Measure", measureId),
periodStart, periodEnd, null,
// TODO: These are all individual reports
"patient", patientId,
// TODO: Generalize these parameters into a Parameters resource
null, null, null, null, null, null);
periodStart, periodEnd, null,
// TODO: These are all individual reports
"patient", patientId,
// TODO: Generalize these parameters into a Parameters resource
null, null, null, null, null, null, mySrd);
compareMeasureReport(expected, actual);
}

View File

@ -4,9 +4,6 @@ import ca.uhn.fhir.cql.BaseCqlDstu3Test;
import ca.uhn.fhir.cql.common.provider.CqlProviderFactory;
import ca.uhn.fhir.cql.dstu3.provider.MeasureOperationsProvider;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.rp.dstu3.LibraryResourceProvider;
import ca.uhn.fhir.jpa.rp.dstu3.MeasureResourceProvider;
import ca.uhn.fhir.jpa.rp.dstu3.ValueSetResourceProvider;
import ca.uhn.fhir.util.StopWatch;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.IdType;
@ -26,6 +23,7 @@ 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;
public class CqlProviderDstu3Test extends BaseCqlDstu3Test {
private static final Logger ourLog = LoggerFactory.getLogger(CqlProviderDstu3Test.class);
@ -37,12 +35,6 @@ public class CqlProviderDstu3Test extends BaseCqlDstu3Test {
@Autowired
CqlProviderFactory myCqlProviderFactory;
@Autowired
private LibraryResourceProvider myLibraryResourceProvider;
@Autowired
private MeasureResourceProvider myMeasureResourceProvider;
@Autowired
private ValueSetResourceProvider myValueSetResourceProvider;
@Autowired
private MeasureOperationsProvider myMeasureOperationsProvider;
@BeforeEach
@ -51,8 +43,8 @@ public class CqlProviderDstu3Test extends BaseCqlDstu3Test {
loadBundle("dstu3/hedis-ig/hedis-valuesets-bundle.json");
// Load libraries
loadResource("dstu3/hedis-ig/library/library-fhir-model-definition.json");
loadResource("dstu3/hedis-ig/library/library-fhir-helpers.json");
loadResource("dstu3/hedis-ig/library/library-fhir-model-definition.json", myRequestDetails);
loadResource("dstu3/hedis-ig/library/library-fhir-helpers.json", myRequestDetails);
}
/*
@ -80,9 +72,9 @@ public class CqlProviderDstu3Test extends BaseCqlDstu3Test {
*/
@Test
public void testHedisIGEvaluatePatientMeasure() throws IOException {
loadResource("dstu3/hedis-ig/library/library-asf-logic.json");
loadResource("dstu3/hedis-ig/library/library-asf-logic.json", myRequestDetails);
// Load the measure for ASF: Unhealthy Alcohol Use Screening and Follow-up (ASF)
loadResource("dstu3/hedis-ig/measure-asf.json");
loadResource("dstu3/hedis-ig/measure-asf.json", myRequestDetails);
Bundle result = loadBundle("dstu3/hedis-ig/test-patient-6529-data.json");
assertNotNull(result);
List<Bundle.BundleEntryComponent> entries = result.getEntry();
@ -96,8 +88,9 @@ public class CqlProviderDstu3Test extends BaseCqlDstu3Test {
String periodEnd = "2003-12-31";
// First run to absorb startup costs
myPartitionHelper.clear();
MeasureReport report = myMeasureOperationsProvider.evaluateMeasure(measureId, periodStart, periodEnd, null, null,
patient, null, null, null, null, null, null);
patient, null, null, null, null, null, null, myRequestDetails);
// Assert it worked
assertThat(report.getGroup(), hasSize(1));
assertThat(report.getGroup().get(0).getPopulation(), hasSize(3));
@ -108,17 +101,18 @@ public class CqlProviderDstu3Test extends BaseCqlDstu3Test {
StopWatch sw = new StopWatch();
for (int i = 0; i < runCount; ++i) {
myMeasureOperationsProvider.evaluateMeasure(measureId, periodStart, periodEnd, null, null,
patient, null, null, null, null, null, null);
patient, null, null, null, null, null, null, myRequestDetails);
}
ourLog.info("Called evaluateMeasure() {} times: average time per call: {}", runCount, sw.formatMillisPerOperation(runCount));
assertTrue(myPartitionHelper.wasCalled());
}
@Test
public void testHedisIGEvaluatePopulationMeasure() throws IOException {
loadResource("dstu3/hedis-ig/library/library-asf-logic.json");
loadResource("dstu3/hedis-ig/library/library-asf-logic.json", myRequestDetails);
// Load the measure for ASF: Unhealthy Alcohol Use Screening and Follow-up (ASF)
loadResource("dstu3/hedis-ig/measure-asf.json");
loadResource("dstu3/hedis-ig/measure-asf.json", myRequestDetails);
loadBundle("dstu3/hedis-ig/test-patient-6529-data.json");
// Add a second patient with the same data
loadBundle("dstu3/hedis-ig/test-patient-9999-x-data.json");
@ -129,7 +123,7 @@ public class CqlProviderDstu3Test extends BaseCqlDstu3Test {
// First run to absorb startup costs
MeasureReport report = myMeasureOperationsProvider.evaluateMeasure(measureId, periodStart, periodEnd, null, "population",
null, null, null, null, null, null, null);
null, null, null, null, null, null, null, myRequestDetails);
// Assert it worked
assertThat(report.getGroup(), hasSize(1));
assertThat(report.getGroup().get(0).getPopulation(), hasSize(3));
@ -140,7 +134,7 @@ public class CqlProviderDstu3Test extends BaseCqlDstu3Test {
StopWatch sw = new StopWatch();
for (int i = 0; i < runCount; ++i) {
myMeasureOperationsProvider.evaluateMeasure(measureId, periodStart, periodEnd, null, "population",
null, null, null, null, null, null, null);
null, null, null, null, null, null, null, myRequestDetails);
}
ourLog.info("Called evaluateMeasure() {} times: average time per call: {}", runCount, sw.formatMillisPerOperation(runCount));

View File

@ -1,13 +1,7 @@
package ca.uhn.fhir.cql.dstu3.provider;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import ca.uhn.fhir.cql.BaseCqlDstu3Test;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.opencds.cqf.cql.engine.runtime.Code;
@ -17,8 +11,13 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import ca.uhn.fhir.cql.BaseCqlDstu3Test;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class JpaTerminologyProviderTest extends BaseCqlDstu3Test {
private static final Logger ourLog = LoggerFactory.getLogger(JpaTerminologyProviderTest.class);
@ -32,7 +31,7 @@ public class JpaTerminologyProviderTest extends BaseCqlDstu3Test {
@BeforeEach
public void before() throws IOException {
// Load executable (i.e. "pre-expanded") value set
loadResource("dstu3/provider/test-executable-value-set.json");
loadResource("dstu3/provider/test-executable-value-set.json", myRequestDetails);
}
@Test

View File

@ -1,16 +1,8 @@
package ca.uhn.fhir.cql.r4;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import ca.uhn.fhir.cql.BaseCqlR4Test;
import ca.uhn.fhir.cql.r4.provider.MeasureOperationsProvider;
import ca.uhn.fhir.util.BundleUtil;
import org.hamcrest.Matchers;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.DateTimeType;
@ -24,9 +16,16 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import ca.uhn.fhir.cql.BaseCqlR4Test;
import ca.uhn.fhir.cql.r4.provider.MeasureOperationsProvider;
import ca.uhn.fhir.util.BundleUtil;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
public class CqlMeasureEvaluationR4Test extends BaseCqlR4Test {
Logger ourLog = LoggerFactory.getLogger(CqlMeasureEvaluationR4Test.class);
@ -36,7 +35,7 @@ public class CqlMeasureEvaluationR4Test extends BaseCqlR4Test {
protected void testMeasureBundle(String theLocation) throws IOException {
Bundle bundle = parseBundle(theLocation);
loadBundle(bundle);
loadBundle(bundle, myRequestDetails);
List<Measure> measures = BundleUtil.toListOfResourcesOfType(myFhirContext, bundle, Measure.class);
if (measures == null || measures.isEmpty()) {
@ -62,11 +61,11 @@ public class CqlMeasureEvaluationR4Test extends BaseCqlR4Test {
this.ourLog.info("Measure: %s, Patient: %s, Start: %s, End: %s", measureId, patientId, periodStart, periodEnd);
MeasureReport actual = this.myMeasureOperationsProvider.evaluateMeasure(new IdType("Measure", measureId),
periodStart, periodEnd, null,
// TODO: These are all individual reports
"patient", patientId,
// TODO: Generalize these parameters into a Parameters resource
null, null, null, null, null, null);
periodStart, periodEnd, null,
// TODO: These are all individual reports
"patient", patientId,
// TODO: Generalize these parameters into a Parameters resource
null, null, null, null, null, null, myRequestDetails);
compareMeasureReport(expected, actual);
}

View File

@ -18,6 +18,7 @@ import java.io.IOException;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class CqlProviderR4Test extends BaseCqlR4Test implements CqlProviderTestBase {
private static final Logger ourLog = LoggerFactory.getLogger(CqlProviderR4Test.class);
@ -47,11 +48,15 @@ public class CqlProviderR4Test extends BaseCqlR4Test implements CqlProviderTestB
@Test
public void testHedisIGEvaluateMeasureWithTimeframe() throws IOException {
loadBundles();
loadResource("r4/hedis-ig/library-asf-logic.json");
loadResource("r4/hedis-ig/measure-asf.json");
loadResource("r4/hedis-ig/library-asf-logic.json", myRequestDetails);
loadResource("r4/hedis-ig/measure-asf.json", myRequestDetails);
myPartitionHelper.clear();
MeasureReport report = myMeasureOperationsProvider.evaluateMeasure(measureId, periodStart, periodEnd, measure, "patient",
patient, null, null, null, null, null, null);
patient, null, null, null, null, null, null, myRequestDetails);
// Assert it worked
assertTrue(myPartitionHelper.wasCalled());
assertThat(report.getGroup(), hasSize(1));
assertThat(report.getGroup().get(0).getPopulation(), hasSize(3));
ourLog.info(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(report));
@ -60,11 +65,15 @@ public class CqlProviderR4Test extends BaseCqlR4Test implements CqlProviderTestB
@Test
public void testHedisIGEvaluateMeasureNoTimeframe() throws IOException {
loadBundles();
loadResource("r4/hedis-ig/library-asf-logic.json");
loadResource("r4/hedis-ig/measure-asf.json");
loadResource("r4/hedis-ig/library-asf-logic.json", myRequestDetails);
loadResource("r4/hedis-ig/measure-asf.json", myRequestDetails);
myPartitionHelper.clear();
MeasureReport report = myMeasureOperationsProvider.evaluateMeasure(measureId, null, null, measure, "patient",
patient, null, null, null, null, null, null);
patient, null, null, null, null, null, null, myRequestDetails);
// Assert it worked
assertTrue(myPartitionHelper.wasCalled());
assertThat(report.getGroup(), hasSize(1));
assertThat(report.getGroup().get(0).getPopulation(), hasSize(3));
ourLog.info(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(report));

View File

@ -1,13 +1,7 @@
package ca.uhn.fhir.cql.r4.provider;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import ca.uhn.fhir.cql.BaseCqlR4Test;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.opencds.cqf.cql.engine.runtime.Code;
@ -17,8 +11,13 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import ca.uhn.fhir.cql.BaseCqlR4Test;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class JpaTerminologyProviderTest extends BaseCqlR4Test {
private static final Logger ourLog = LoggerFactory.getLogger(JpaTerminologyProviderTest.class);
@ -32,7 +31,7 @@ public class JpaTerminologyProviderTest extends BaseCqlR4Test {
@BeforeEach
public void before() throws IOException {
// Load executable (i.e. "pre-expanded") value set
loadResource("r4/provider/test-executable-value-set.json");
loadResource("r4/provider/test-executable-value-set.json", myRequestDetails);
}
@Test

View File

@ -0,0 +1,76 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>TRACE</level>
</filter>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] %msg%n</pattern>
</encoder>
</appender>
<logger name="org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator" additivity="false"
level="info">
<appender-ref ref="STDOUT"/>
</logger>
<logger name="ca.uhn.fhir.jpa.dao.FhirResourceDaoSubscriptionDstu2" additivity="false" level="info">
<appender-ref ref="STDOUT"/>
</logger>
<logger name="org.eclipse.jetty.websocket" additivity="false" level="info">
<appender-ref ref="STDOUT"/>
</logger>
<!-- TODO GGG HS can probably eventually disable this. -->
<logger name="org.hibernate.search.backend.lucene.infostream" additivity="true" level="trace">
<appender-ref ref="STDOUT"/>
</logger>
<logger name="org.hibernate.search.query" additivity="true" level="trace">
<appender-ref ref="STDOUT"/>
</logger>
j
<logger name="org.hibernate.event.internal.DefaultPersistEventListener" additivity="true" level="info">
<appender-ref ref="STDOUT"/>
</logger>
<logger name="org.elasticsearch.client" additivity="true" level="trace">
<appender-ref ref="STDOUT"/>
</logger>
<logger name="org.eclipse" additivity="false" level="error">
</logger>
<logger name="ca.uhn.fhir.rest.client" additivity="false" level="info">
<appender-ref ref="STDOUT"/>
</logger>
<logger name="ca.uhn.fhir.jpa.dao" additivity="false" level="info">
<appender-ref ref="STDOUT"/>
</logger>
<!-- set to debug to enable term expansion logs -->
<logger name="ca.uhn.fhir.jpa.term" additivity="false" level="debug">
<appender-ref ref="STDOUT"/>
</logger>
<!-- Set to 'trace' to enable SQL logging -->
<logger name="org.hibernate.SQL" additivity="false" level="info">
<appender-ref ref="STDOUT"/>
</logger>
<!-- Set to 'trace' to enable SQL Value logging -->
<logger name="org.hibernate.type" additivity="false" level="info">
<appender-ref ref="STDOUT"/>
</logger>
<logger name="org.hibernate.search.elasticsearch.request" additivity="false" level="trace">
<appender-ref ref="STDOUT"/>
</logger>
<logger name="org.springframework.test.context.cache" additivity="false" level="debug">
<appender-ref ref="STDOUT"/>
</logger>
<root level="info">
<appender-ref ref="STDOUT"/>
</root>
</configuration>

View File

@ -59,6 +59,11 @@
<artifactId>spring-context</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core</artifactId>

View File

@ -0,0 +1,15 @@
package ca.uhn.fhir.test.utilities;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import org.springframework.mock.web.MockHttpServletRequest;
public class RequestDetailsHelper {
public static RequestDetails newServletRequestDetails() {
ServletRequestDetails retval = new ServletRequestDetails();
retval.setServletRequest(new MockHttpServletRequest());
retval.setServer(new RestfulServer());
return retval;
}
}