Skip to content

Support numeric uncertainty ranges, lists of numeric intervals, and lists of temporal intervals - #129

Merged
bryantaustin13 merged 3 commits into
mainfrom
fix-ivl-lists-and-uncertainties
Aug 31, 2026
Merged

bryantaustin13 merged 3 commits into
mainfrom
fix-ivl-lists-and-uncertainties

Conversation

@cmoesel

@cmoesel cmoesel commented Aug 26, 2026 •

Copy link
Copy Markdown
Member

NOTE: I updated this PR from the originally submitted PR to also include support for lists of temporal intervals.

This PR follows on to #109 and #110 by extending numeric interval extraction to numeric uncertainty ranges and lists of numeric intervals during result extraction, as well as extending temporal interval extraction to lists of temporal intervals.

Numeric Uncertainty Ranges

In this CQL testing framework, uncertainties are represented as intervals since CQL does not have a literal Uncertainty type. When these are serialized as FHIR operation results, they are represented as a parameter with a CQL type indicating the original scalar result type (e.g., Integer) and a FHIR Range indicating the uncertain range.

For example, the DateTimeUncertain test is defined to expect Interval[18,49] representing the uncertain range from 18 to 49:

<test name="DateTimeUncertain" version="1.0">
  <capability code="types" />
  <expression>days between DateTime(2015, 2, 10) and DateTime(2015, 3)</expression>
  <output>Interval [ 18, 49 ]</output>
</test>

CQL engines should return this result to the test runner using this serialization:

{
  "resourceType": "Parameters",
  "parameter": [{
    "extension": [{
      "url": "http://hl7.org/fhir/StructureDefinition/cqf-cqlType",
      "valueString": "System.Integer"
    }],
    "name": "return",
    "valueRange": {
      "low": { "value": 18, "system": "http://unitsofmeasure.org", "code": "1" },
      "high": { "value": 49, "system": "http://unitsofmeasure.org", "code": "1" }
    }
  }]
}

Prior to this PR, the test runner did not recognize this as a numeric interval because the cqf-cqlType is not one of Interval<System.Integer> | Interval<System.Long> | Interval<System.Decimal>. This PR now recognizes the pattern of a numeric cqf-cqlType with a valueRange as an uncertainty that should be processed as a numeric interval.

Lists of Numeric Intervals

The Using CQL IG specifies that list-typed results should be returned as an array of parameters, each of which indicates its cqf-cqlType using the list specifier (e.g., List<Integer>) and a value serialized as the contained type (e.g., valueInteger). This means that a list of Integer intervals should result in a list of parameters, each of which has cqf-cqlType List<Interval<Integer>> and a valueRange.

For example, the IntegerIntervalCollapse2 test is defined to expect a list containing Interval[1,19] as the result:

<test name="IntegerIntervalCollapse2" version="1.0">
  <capability code="interval-operators"/>
  <expression>collapse { Interval[1,2], Interval[3,7], Interval[10,19], Interval[7,10] }</expression>
  <output>{Interval [ 1, 19 ]}</output>
</test>

CQL engines should return this result to the test runner using this serialization:

{
  "resourceType": "Parameters",
  "parameter": [{
    "extension": [{
      "url": "http://hl7.org/fhir/StructureDefinition/cqf-cqlType",
      "valueString": "List<Interval<System.Integer>>"
    }],
    "name": "return",
    "valueRange": {
      "low": { "value": 1, "system": "http://unitsofmeasure.org", "code": "1" },
      "high": { "value": 19, "system": "http://unitsofmeasure.org", "code": "1" }
    }
  }]
}

Prior to this PR, the test runner did not recognize this as a numeric interval because the cqf-cqlType is not one of Interval<System.Integer> | Interval<System.Long> | Interval<System.Decimal>. This PR now strips the outer List (if it is there) before checking to see if the type is a numeric interval.

Lists of Temporal Intervals

Similar to the approach for lists of numeric intervals, lists of temporal intervals also indicate the list specifier type within each parameter. Following this, a list of Date intervals should result in a list of parameters, each of which has cqf-cqlType List<Interval<Date>> and a valuePeriod.

For example, the ExpandPer2Days test is defined to expect a list containing Interval[@2018-01-01, @2018-01-02] and Interval[@2018-01-03, @2018-01-04] as the result:

<test name="ExpandPer2Days" version="1.3">
  <capability code="interval-operators"/>
  <expression>expand { Interval[@2018-01-01, @2018-01-04] } per 2 days</expression>
  <output>{ Interval[@2018-01-01, @2018-01-02], Interval[@2018-01-03, @2018-01-04] }</output>
</test>

CQL engines should return this result to the test runner using this serialization:

{
  "resourceType": "Parameters",
  "parameter": [
    {
      "extension": [{
        "url": "http://hl7.org/fhir/StructureDefinition/cqf-cqlType",
        "valueString": "List<Interval<System.Date>>"
      }],
      "name": "return",
      "valuePeriod": {
        "start": "2018-01-01",
        "end": "2018-01-02"
      }
    },
    {
      "extension": [{
        "url": "http://hl7.org/fhir/StructureDefinition/cqf-cqlType",
        "valueString": "List<Interval<System.Date>>"
      }],
      "name": "return",
      "valuePeriod": {
        "start": "2018-01-03",
        "end": "2018-01-04"
      }
    }
  ]
}

Prior to this PR, the test runner did not recognize this as a temporal interval because the cqf-cqlType is not one of Interval<System.Date> | Interval<System.DateTime> | Interval<System.Time>. This PR now strips the outer List (if it is there) before checking to see if the type is a temporal interval.

Testing

This PR includes unit tests demonstrating these fixes, but if you have a compliant CQL server that returns numeric uncertainty ranges and lists of intervals as specified above, then you should note that tests resulting in those types now pass.

When a result is a list of intervals, the result is serialized as a list
of parameters, each of which has a CQL type indicating a list
(e.g., List<Interval<Integer>>) and a valueRange representing
that interval in the list.

Update the extractor to recognize lists of numeric intervals and
extract them as such.
When a result is a numeric uncertainty, the result is serialized a
a parameter with a CQL type indicating the scalar type of the
result (e.g., Integer) and a valueRange representing the uncertain
range.

Update the extractor to recognize this pattern (a scalar type with
a valueRange) and extract these cases as intervals, since that is
how uncertainties are modeled in this test framework.
When a result is a list of temporal intervals, the result is serialized as a list of parameters, each of which has a CQL type indicating a list (e.g., List<Interval<Date>>) and a valuePeriod representing that interval in the list.

Update the extractor to recognize lists of temporal intervals and extract them as such.
@cmoesel cmoesel changed the title Support numeric uncertainty ranges and lists of numeric intervals mapped as Ranges Support numeric uncertainty ranges, lists of numeric intervals, and lists of temporal intervals Aug 26, 2026
cmoesel added a commit that referenced this pull request Aug 26, 2026
- Unskip tests that were skipped due to test runner bugs that are now fixed
- Unskip tests that were skipped due to invalid tests that have been fixed
- Skip tests related to test runner bugs that are waiting on PR #129
@bryantaustin13
bryantaustin13 merged commit b8b2b6d into main Aug 31, 2026
cmoesel added a commit that referenced this pull request Sep 19, 2026
- Unskip tests that were skipped due to test runner bugs that are now fixed
- Unskip tests that were skipped due to invalid tests that have been fixed
- Skip tests related to test runner bugs that are waiting on PR #129
cmoesel added a commit that referenced this pull request Sep 20, 2026
- Unskip tests that were skipped due to test runner bugs that are now fixed
- Unskip tests that were skipped due to invalid tests that have been fixed
- Skip tests related to test runner bugs that are waiting on PR #129
bryantaustin13 added a commit that referenced this pull request Sep 22, 2026
Resolves the conflict in datetime-interval-extractor.ts, which arose because this
branch predates #129 and #135 and carried an older copy of the whole file.

Taking either side alone would have lost work:

- main's side drops this branch's null guards and its `highClosed: high !== null`,
  leaving an absent Period boundary reported as closed.
- this branch's side drops #135's applyDeclaredTimePrecision on the `_start`/`_end`
  companion elements and #129's List<...> unwrapping in declaredPointType, which
  would have reverted time-precision support and lists of temporal intervals.

The resolution keeps all of it: this branch's early-return guards and derived
highClosed, wrapping main's precision-aware boundary extraction, with #129's
List unwrapping untouched above.

Verified after resolution: 247 tests pass, and each behaviour checked directly —
a Period with hour time-precision extracts as @T10/@t12, List<Interval<System.Date>>
still resolves to Date literals, an absent end yields highClosed:false, and null
valuePeriod / valueRange / boundary no longer throw. tsc reports only the two
pre-existing rest-routes.ts errors present on main.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants