Two coupled defects around FHIR choice types (e.g. Observation.effective = choice<dateTime, Period>):
- Standard FHIRPath emptiness checks fail to compile because the operators have no overload for FHIR choice types or individual FHIR primitives:
effective.exists().not() - Could not resolve call to operator Exists with signature (choice<FHIR.Period, FHIR.dateTime>)
exists(effective as FHIR.dateTime) - Could not resolve call to operator Exists with signature (FHIR.dateTime)
effective.count() = 0 - Could not resolve call to operator Count with signature (choice<...>)
(effective is FHIR.dateTime).not() compiles, but when effective is absent, is returns empty (per FHIRPath spec is semantics on empty input). Empty propagates through .not(), the surrounding or chain, .where(), and .exists(). So an Observation with no effective field never triggers even when the surrounding predicate would otherwise let it through.
Repro (part 1- resolution failures):
library Repro
using FHIR version '4.0.1'
include FHIRHelpers version '4.0.1' called FHIRHelpers
context Patient
define A: [Observation] O where O.effective.exists().not()
define B: [Observation] O where exists(O.effective as FHIR.dateTime)
define C: [Observation] O where O.effective.count() = 0
All three fail to translate.
Repro (part 2 - empty propagation):
define D:
[Observation] O
where ((O.effective is FHIR.dateTime).not()
or (O.effective as FHIR.dateTime) >= @2025-01-01)
An Observation with no effective field is filtered out because both OR operands evaluate empty.
Expected: Exists, Empty, and Count should have overloads for FHIR choice types (choice<...>) and for individual FHIR primitives (FHIR.dateTime, FHIR.Period, etc.). is on empty should be safe to compose with .not() and boolean logic without dropping the containing collection.
Workaround: wrap in CQL Coalesce:
Coalesce((O.effective is FHIR.dateTime).not(), true)
Two coupled defects around FHIR choice types (e.g. Observation.effective = choice<dateTime, Period>):
effective.exists().not()- Could not resolve call to operator Exists with signature (choice<FHIR.Period, FHIR.dateTime>)exists(effective as FHIR.dateTime)- Could not resolve call to operator Exists with signature (FHIR.dateTime)effective.count() = 0- Could not resolve call to operator Count with signature (choice<...>)(effective is FHIR.dateTime).not()compiles, but when effective is absent, is returns empty (per FHIRPath spec is semantics on empty input). Empty propagates through.not(), the surrounding or chain,.where(), and.exists(). So an Observation with no effective field never triggers even when the surrounding predicate would otherwise let it through.Repro (part 1- resolution failures):
All three fail to translate.
Repro (part 2 - empty propagation):
An Observation with no effective field is filtered out because both OR operands evaluate empty.
Expected: Exists, Empty, and Count should have overloads for FHIR choice types (choice<...>) and for individual FHIR primitives (FHIR.dateTime, FHIR.Period, etc.). is on empty should be safe to compose with .not() and boolean logic without dropping the containing collection.
Workaround: wrap in CQL Coalesce:
Coalesce((O.effective is FHIR.dateTime).not(), true)