DataRequirements test failures
on the most recent release of cqfTooling while running ECQMCreatorIT tests two failures occured when verifying DataRequirements matched between bundle and measure:
TestCMS125FHIR StartMatOutputTest("CMS125FHIR-v0-0-004-FHIR-4-0-1.json", "BreastCancerScreeningsFHIR") failed on 'MedicationRequest' match
TestCMS816HIR StartMatOutputTest("HH-01FHIR-v0-0-010-FHIR-4-0-1.json", "HospitalHarmSevereHypoglycemiaFHIR") failed on "MedicationAdministration" match
currently the test has been commented out until bug on DataRequirements has been fixed.
I am also seeing some unexpected behavior from the DataRequirementProcessor (currently using version 3.5.1). It would appear that something has changed between versions 3.1.0 and 3.2.0. If I use this small CQL file, I can replicate the behavior:
library "Test-Rule" version '0.0.1'
using FHIR version '4.0.0'
include FHIRHelpers version '4.0.0'
valueset "Test MedicationRequest VS": 'fake.medrequest.vs'
context Patient
define "Matching MedicationRequests": [MedicationRequest: "Test MedicationRequest VS"]
On version 3.1.0, the return value from gatherDataRequirements includes:
- a requirement for MedicationRequest containing a code filter for my value set
- a requirement for Patient
On version 3.2.0, repeating the same steps as above, I get:
- a requirement for MedicationRequest containing a code filter for my value set
- a requirement for MedicationRequest with no code filter attached
- a requirement for Medication with no code filter attached
- a requirement for Patient
The second and third requirements from version 3.2.0+ are unexpected to me. I tried up to version 3.6.0 and still see the same behavior from the DataRequirementProcessor.
It looks like this was the change which introduced the new behavior: https://github.com/cqframework/clinical_quality_language/pull/1228
Whats happening here is that Medication.medication is a choice type. It can be either a CodeableConcept or a Reference. In cases where it's a Reference, there's an implied requirement for Medication since you're referencing one directly by id.
The two other unfiltered data requirements fall out from that. Essentially, since you're referencing Medication by id but you don't know the ids ahead of time (it could whatever is stored in the medication Reference, you need all the Medications.
You can rewrite the last line as:
define "Matching MedicationRequests": ["MedicationRequest"] MR where MR.medication as CodeableConcept in "Test MedicationRequest VS"
And you'll see the behavior you're expecting.
@JPercival the Medication.medication property is a reference in the case of our FHIR implementation. What I'm hoping to infer from the data requirements is that the Medication requirement is originating from this MedicationRequest requirement, such that I can add the _include=MedicationRequest:medication parameter to the MedicationRequest search request and not separately fetch all Medication resources.
I understand why it is logical to include some indication that this artifact depends on Medication due to the choice type of MedicationRequest.medication and the possibility of it being a reference, but is it possible to report it in such a way that it could be differentiated from an explicit dependency on the Medication resource from the CQL?
On the other hand, I don't understand why the MedicationRequest data requirement without a code filter is a logical data requirement for this artifact.
but is it possible to report it in such a way that it could be differentiated from an explicit dependency on the Medication resource from the CQL?
Based on my understanding of data requirements that's not how they are intended to be used. Rather, it's a way to share metadata about all possible data the CQL might access. This is useful for things like access-control. "User A can see MedicationRequests, but not Medications".
In this case, which particular Medications are read depend on the data stored within the MedicationRequests, which is not known ahead of time. The narrowest it could be scoped and still work for all cases is an unfiltered Medication.
On the other hand, I don't understand why the MedicationRequest data requirement without a code filter is a logical data requirement for this artifact.
The data requirements processor can see that some Medications will be filtered by a ValueSet (those that have a CodeableConcept for medication). But other Medications that have a reference can not be filtered by a ValueSet. It's unable to distinguish in this particular context that you only care about those with CodeableConcept, so it gives you an unfiltered Medication to ensure those that have a reference are also captured. The explicit as CodeableConcept in the example I gave you is the clue it needs to remove that additional unfiltered Medication. "I know I'm talking about medication, which may be a Reference or a CodeableConcept, but I explicitly only care about the ones with a CodeableConcept, which precludes Medications." It may be possible to enhance the inference there to doesn't add that additional unfiltered MedicationRequest. I'll have to look into that.
Based on my understanding of data requirements that's not how they are intended to be used. Rather, it's a way to share metadata about all possible data the CQL might access. This is useful for things like access-control. "User A can see MedicationRequests, but not Medications".
This interpretation seems to conflict with the discussion here: https://cql.hl7.org/05-languagesemantics.html#artifact-data-requirements
It discusses in detail how to combine/collapse data requirements in order to produce "the minimum initial data requirements for the artifact, with any overlapping requests for the same type of data collapsed into a single request descriptor." Additionally, the presence of elements like codeFilter and dateFilter on the DataRequirement resource would indicate to me that they are meant to be used for optimal data fetching rather than primarily for access control.
The discussion in section 1.3 of the CQL Language Semantics guide is effectively exactly what we're trying to achieve, though we aren't bothering with the date filtering optimization at the moment, only the code filter so far. For this specific example of the MedicationRequest referencing a Medication, it'd seem the Includes component of the retrieve data requirement is most relevant. From that excerpt of the CQL guide:
Include elements for the clinical data. For data models that define relationships between data types, this element allows data matching the include relationships to be returned as part of the retrieve as well. Implementations that support this capability must ensure that included data returned is accessible via the related retrieve statements.
Though, I don't see a way to represent the include information in the FHIR resource for DataRequirement, so perhaps this is a gap with the resource definition? I'm far from a FHIR expert, though.
Based on my understanding of data requirements that's not how they are intended to be used.
This interpretation seems to conflict with the discussion here: https://cql.hl7.org/05-languagesemantics.html#artifact-data-requirements
It'd seem the Includes component of the retrieve data requirement is most relevant. From that excerpt of the CQL guide:
Though, I don't see a way to represent the include information in the FHIR resource for DataRequirement, so perhaps this is a gap with the resource definition? I'm far from a FHIR expert, though.
I'm referring to the FHIR data requirements returned by the DataRequirements processor in question, not artifact data requirements in the CQL spec. These are two separate and distinct specifications, despite the conceptual overlap and shared nomenclature. As you've pointed out, there's not a way to do includes in the FHIR data requirements.
with any overlapping requests for the same type of data collapsed into a single request descriptor
Currently with the CQL compiler you have to set collapseDataRequirements to true on the CqlCompilerOptions to opt-in to the collapsing behavior, though in this case it would not help.
These are two separate and distinct specifications, despite the conceptual overlap and shared nomenclature.
I see, thank you for clearing up that source of confusion!
If we take the DataRequirementProcessor and FHIR out of the question, is it currently possible to implement the logic described in the CQL spec I referenced above? We're using the cql2elm package to compile our CQL, which to my understanding utilizes the Cql2ElmVisitor class that was updated in #1228. Is that also going to prevent us from accurately analyzing and collapsing the ELM data requirements as described in the CQL spec?
Yes, the logic for that analysis is partially implemented internally and is the source for the FHIR data requirements. Here's the package for that. In particular the ElmRequirementsVisitor may be of interest to you:
https://github.com/cqframework/clinical_quality_language/blob/master/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/
We've yet to come up with a public API or serialization format for the ELM requirements, and includes have yet to be implemented, but you may find something useful there. We're definitely interested in support includes here it just hasn't bubbled up the backlog yet.