Stream: cql
Topic: Case Statements require consistent type resolution?
Michael Riley (Jun 23 2021 at 15:46):
I'm trying to work with the choice data in fhir resources, and would really like to handle with dates or periods across the resources where there is a choice. I have this function.
define function msConvertEffective(medStatement FHIR.MedicationStatement):
case
when (medStatement.effective as FHIR.dateTime) is not null then (medStatement.effective as FHIR.dateTime).value
when (medStatement.effective as FHIR.Period) is not null then ToInterval((medStatement.effective as FHIR.Period))
else null
end
But it creates this error message.
>> Error [20:3] Expected an expression of type 'System.DateTime', but found an expression of type 'Interval of System.DateTime'.
And when I switch the order of the two case statements, I find that
Error [20:3] Expected an expression of type 'Interval of System.DateTime', but found an expression of type 'System.DateTime'.
So it seems that whatever the first type resolution is in a switch case statement, all other types must match. I would rather not use the if else statements as they read poorly, and these could scale out to all choice fields in the future rather easily. I'm also unsure as to how I could convert this to work with lists, and not just individual resources.
JP (Jun 24 2021 at 19:07):
Hi Michael!
In principle you should be able to do that. In practice the cql-translator isn't quite smart enough to do type inference all the way through conditionals. A work-around is to cast the first then
statement to the type you want. Here's an example (also handles a List):
define function msConvertEffective(medStatments List<FHIR.MedicationStatement>):
medStatments S
return
case
when (S.effective as FHIR.dateTime) is not null then ((S.effective as FHIR.dateTime).value as Choice<DateTime, Interval<DateTime>>)
when (S.effective as FHIR.Period) is not null then FHIRHelpers.ToInterval((S.effective as FHIR.Period))
else null
end
Michael Riley (Jun 24 2021 at 21:55):
thanks JP this is illuminating a lot for me.
What is this line called here? It acts like an unwrapper/iterator.
medStatments S
JP (Jun 24 2021 at 22:07):
That's the syntax for a query in CQL:
<query source> <alias>
medStatments S
https://cql.hl7.org/02-authorsguide.html#queries
Any list can be a query source. You typically see this construct when doing retrieves:
[Encounter: "Inpatient"] E
where duration in days of E.period >= 120
JP (Jun 24 2021 at 22:07):
It's not an iterator or unwrapper per se since CQL is declarative (like SQL) as opposed to imperative (like Java, C, etc) but the outcome in this use case is the same. You're basically saying "for each thing in this List, perform this transformation".
Michael Riley (Jun 28 2021 at 14:15):
Ah ok, so all statements should generally start with a query source, and a query does not always have to be a retrieval, but could be an existing definition or a parameter in a function. Thank you!
Last updated: Apr 12 2022 at 19:14 UTC