From b2068a17c5d1a64d1d933c1dc72a879664037524 Mon Sep 17 00:00:00 2001 From: Luke deGruchy Date: Thu, 21 Nov 2024 16:56:03 -0500 Subject: [PATCH] Remove validation for individual reports. Add utility method for evalType derivation. --- .../measure/common/BaseMeasureEvaluation.java | 5 ++ .../measure/dstu3/Dstu3MeasureProcessor.java | 13 +-- .../cr/measure/r4/R4MeasureProcessor.java | 80 +++++++++++++++++-- .../cr/measure/r4/R4MeasureReportBuilder.java | 12 ++- 4 files changed, 95 insertions(+), 15 deletions(-) diff --git a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/common/BaseMeasureEvaluation.java b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/common/BaseMeasureEvaluation.java index e7ae51ccae..f44a9e5655 100644 --- a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/common/BaseMeasureEvaluation.java +++ b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/common/BaseMeasureEvaluation.java @@ -7,8 +7,11 @@ import org.opencds.cqf.cql.engine.runtime.Interval; import org.opencds.cqf.fhir.cql.LibraryEngine; import org.opencds.cqf.fhir.cr.measure.constant.MeasureConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public abstract class BaseMeasureEvaluation { + private static final Logger log = LoggerFactory.getLogger(BaseMeasureEvaluation.class); protected MeasureDefBuilder measureDefBuilder; protected MeasureReportBuilder measureReportBuilder; @@ -83,6 +86,8 @@ public MeasureReportT evaluate( } else { measurementPeriodInterval = measurementPeriod; } + final MeasureReportType measureReportType = this.evalTypeToReportType(measureEvalType); + log.info("592: measureEvalType: {}, measureReportType: {}", measureEvalType, measureReportType); return this.measureReportBuilder.build( measure, measureDef, this.evalTypeToReportType(measureEvalType), measurementPeriodInterval, subjectIds); } diff --git a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/dstu3/Dstu3MeasureProcessor.java b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/dstu3/Dstu3MeasureProcessor.java index 910399d3e4..83a644af93 100644 --- a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/dstu3/Dstu3MeasureProcessor.java +++ b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/dstu3/Dstu3MeasureProcessor.java @@ -27,6 +27,7 @@ import org.opencds.cqf.fhir.cr.measure.common.MeasureReportType; import org.opencds.cqf.fhir.cr.measure.common.SubjectProvider; import org.opencds.cqf.fhir.cr.measure.helper.DateHelper; +import org.opencds.cqf.fhir.cr.measure.r4.R4MeasureProcessor; import org.opencds.cqf.fhir.utility.repository.FederatedRepository; import org.opencds.cqf.fhir.utility.repository.InMemoryFhirRepository; @@ -125,11 +126,13 @@ protected MeasureReport evaluateMeasure( this.repository, new InMemoryFhirRepository(this.repository.fhirContext(), additionalData)); } - var evalType = MeasureEvalType.fromCode(reportType) - .orElse( - subjectIds == null || subjectIds.isEmpty() || subjectIds.get(0) == null - ? MeasureEvalType.POPULATION - : MeasureEvalType.SUBJECT); + // LUKETODO: +// var evalType = MeasureEvalType.fromCode(reportType) +// .orElse( +// subjectIds == null || subjectIds.isEmpty() || subjectIds.get(0) == null +// ? MeasureEvalType.POPULATION +// : MeasureEvalType.SUBJECT); + var evalType = R4MeasureProcessor.someSortOfMeasureTypeCodeConversion(null, reportType, subjectIds); var subjects = subjectProvider.getSubjects(actualRepo, evalType, subjectIds).collect(Collectors.toList()); diff --git a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MeasureProcessor.java b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MeasureProcessor.java index d7280d3ee3..004edbad10 100644 --- a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MeasureProcessor.java +++ b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MeasureProcessor.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; import org.cqframework.cql.cql2elm.CqlIncludeException; @@ -29,6 +30,7 @@ import org.opencds.cqf.fhir.cql.VersionedIdentifiers; import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions; import org.opencds.cqf.fhir.cr.measure.common.MeasureEvalType; +import org.opencds.cqf.fhir.cr.measure.common.MeasureReportType; import org.opencds.cqf.fhir.cr.measure.common.SubjectProvider; import org.opencds.cqf.fhir.cr.measure.r4.utils.R4DateHelper; import org.opencds.cqf.fhir.utility.Canonicals; @@ -36,8 +38,12 @@ import org.opencds.cqf.fhir.utility.repository.FederatedRepository; import org.opencds.cqf.fhir.utility.repository.InMemoryFhirRepository; import org.opencds.cqf.fhir.utility.search.Searches; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class R4MeasureProcessor { + + private static final Logger log = LoggerFactory.getLogger(R4MeasureProcessor.class); private final Repository repository; private final MeasureEvaluationOptions measureEvaluationOptions; private final SubjectProvider subjectProvider; @@ -59,11 +65,17 @@ public MeasureReport evaluateMeasure( IBaseBundle additionalData, Parameters parameters) { - var evalType = MeasureEvalType.fromCode(reportType) - .orElse( - subjectIds == null || subjectIds.isEmpty() || subjectIds.get(0) == null - ? MeasureEvalType.POPULATION - : MeasureEvalType.SUBJECT); + var evalType = MeasureEvalType.fromCode( + // validate in R4 accepted values + MeasureEvalType.fromCode(reportType) + .orElse( + // map null reportType parameter to evalType if no subject parameter is provided + subjectIds == null || subjectIds.isEmpty() || subjectIds.get(0) == null + ? MeasureEvalType.POPULATION + : MeasureEvalType.SUBJECT) + .toCode()) + .orElse(MeasureEvalType.SUBJECT); +// var evalType = R4MeasureProcessor.someSortOfMeasureTypeCodeConversion(null, reportType, subjectIds); var actualRepo = this.repository; if (additionalData != null) { @@ -160,6 +172,8 @@ protected MeasureReport evaluateMeasure( ? MeasureEvalType.POPULATION : MeasureEvalType.SUBJECT); } +// evalType = someSortOfMeasureTypeCodeConversion(evalType, reportType, subjectIds); + log.info("592: NEW evalType: {}, reportType: {}, subjectIds: {}", evalType, reportType, subjectIds); // Library Evaluate var libraryEngine = new LibraryEngine(repository, this.measureEvaluationOptions.getEvaluationSettings()); R4MeasureEvaluation measureEvaluator = new R4MeasureEvaluation(context, measure, libraryEngine, id); @@ -206,4 +220,58 @@ private Map resolveParameterMap(Parameters parameters) { }); return parameterMap; } -} + + // LUKETODO: this is one part of the logic for converting null to INDIVIDUAL + /* + +| Number | ReportType | subject | EvalType | MeasureReportType | Note | +| | param | param | used | returned | | +| ------ | ------------ | ----------------- | ------------ | ----------------- | ---------------------------------------------------- | +| 1 | empty | empty | population | summary | default behavior, when NO subject parameter provided | +| 2 | empty | Patient/{id} | subject | individual | default behavior, when subject parameter provided | +| 2 | empty | Practitioner/{id} | subject | individual | default behavior, when subject parameter provided | +| 2 | empty | Organization/{id} | subject | individual | default behavior, when subject parameter provided | +| 3 | empty | Group/{id} | subject | individual | default behavior, when subject parameter provided | +| 4 | subject | empty | subject | individual | | >>> currently this is an error? +| 5 | subject | Patient/{id} | subject | individual | | +| 5 | subject | Practitioner/{id} | subject | individual | | +| 5 | subject | Organization/{id} | subject | individual | | +| 6 | subject | Group/{id} | subject | individual | | +| 7 | population | empty | population | summary | | +| 8 | population | Patient/{id} | population | summary | | +| 8 | population | Practitioner/{id} | population | summary | | +| 8 | population | Organization/{id} | population | summary | | +| 9 | population | Group/{id} | population | summary | | +| 10 | subject-list | empty | subject-list | subject-list | | +| 11 | subject-list | Patient/{id} | subject-list | subject-list | | +| 11 | subject-list | Practitioner/{id} | subject-list | subject-list | | +| 11 | subject-list | Organization/{id} | subject-list | subject-list | | +| 12 | subject-list | Group/{id} | subject-list | subject-list | | + */ + public static MeasureEvalType someSortOfMeasureTypeCodeConversion(MeasureEvalType evalType, String reportType, List subjectIds) { + log.info("592: OLD evalType: {}, reportType: {}, subjectIds: {}", evalType, reportType, subjectIds); + + return Optional.ofNullable(evalType) + .orElse(MeasureEvalType.fromCode(reportType) + .orElse( + subjectIds == null || subjectIds.isEmpty() || subjectIds.get(0) == null + ? MeasureEvalType.POPULATION + : MeasureEvalType.SUBJECT)); + + // LUKETODO: will this work? + // LUKETODO: does this conflict with the changes we made in cdr? +// return Optional.ofNullable(evalType) +// .orElse(MeasureEvalType.fromCode(reportType) +// .orElseGet(() -> { +// if (isSubjectListEffectivelyEmpty(subjectIds)) { +// return MeasureEvalType.POPULATION; +// } +// +// return MeasureEvalType.SUBJECT; +// })); + } + + public static boolean isSubjectListEffectivelyEmpty(List subjectIds) { + return subjectIds == null || subjectIds.isEmpty() || subjectIds.get(0) == null; + } +} \ No newline at end of file diff --git a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MeasureReportBuilder.java b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MeasureReportBuilder.java index e79d98961e..6ec3d3b907 100644 --- a/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MeasureReportBuilder.java +++ b/cqf-fhir-cr/src/main/java/org/opencds/cqf/fhir/cr/measure/r4/R4MeasureReportBuilder.java @@ -668,11 +668,15 @@ protected void buildSDE(BuilderContext bc, SdeDef sde) { return; } + + // LUKETODO: investigate why this is NOT happening on master + // LUKETODO: what's this about? // This is an individual report... shouldn't have more than one subject! - if (report.getType() == MeasureReport.MeasureReportType.INDIVIDUAL - && sde.getResults().keySet().size() > 1) { - throw new IllegalArgumentException(); - } + // LUKETODO: see if this works +// if (report.getType() == MeasureReport.MeasureReportType.INDIVIDUAL +// && sde.getResults().keySet().size() > 1) { +// throw new IllegalArgumentException(); +// } // Add all evaluated resources for (var e : sde.getResults().entrySet()) {