Colorectal Cancer Screening and Management (CRCSM) Clinical Decision Support (CDS) Implementation Guide
0.1.0 - ci-build

Colorectal Cancer Screening and Management (CRCSM) Clinical Decision Support (CDS) Implementation Guide - Local Development build (v0.1.0) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions

Library: CSMCommonFunctions

Official URL: http://cancerscreeningcds.github.io/crcsm-cds/Library/CSMCommonFunctions Version: 0.1.0
Draft as of 2025-02-28 Computable Name: CSMCommonFunctions
Id: CSMCommonFunctions
Version: 0.1.0
Url: CSMCommonFunctions
Status: draft
Type:

system: http://terminology.hl7.org/CodeSystem/library-type

code: logic-library

Date: 2025-02-28 21:24:30+0000
Publisher: MITRE
Related Artifacts:

Dependencies

  • http://fhir.org/guides/cqf/common/Library/FHIR-ModelInfo|4.0.1
  • http://cancerscreeningcds.github.io/crcsm-cds/Library/CDSConnectCommonsforFHIRv401|1.0.0
  • http://cancerscreeningcds.github.io/crcsm-cds/Library/FHIRHelpers|4.0.1
  • ConditionVerificationStatus
Content: text/cql
library CSMCommonFunctions version '1.0.0'

using FHIR version '4.0.1'

include CDSConnectCommonsforFHIRv401 version '1.0.0' called C3F
include FHIRHelpers version '4.0.1' called FHIRHelpers

codesystem "CONDVERSTATUS": 'http://terminology.hl7.org/CodeSystem/condition-ver-status'

code "Condition Refuted code": 'refuted' from "CONDVERSTATUS" display 'Refuted'
code "Condition Entered in Error code": 'entered-in-error' from "CONDVERSTATUS" display 'Entered in Error'

concept "Condition Refuted": { "Condition Refuted code" } display 'Refuted'
concept "Condition Entered in Error": { "Condition Entered in Error code" } display 'Entered in Error'

/*******************************************************************************
 * NOTICE: This following code has been adapted from "Factors to Consider in 
 * Managing Chronic Pain: A Pain Management Summary," available at:
 * https://cds.ahrq.gov/cdsconnect/artifact/factors-consider-managing-chronic-pain-pain-management-summary
 * It is made available via an Apache 2.0 license.
*******************************************************************************/

// Returns the first-found display text for a CodeableConcept, looking first at the `text` attribute, then the
// `display` on each `coding` until it finds a non-null value.  Some PEG codes are normalized due to length.
// @param c - a FHIR CodeableConcept to get text from
// @returns {System.String} the display text or null if none is found
define function ConceptText(c FHIR.CodeableConcept):
  Coalesce(c.text.value, Coalesce((c.coding) c2 return c2.display.value))

// Returns a text representation of a date using the CQL `ToString` function.
// @param d - a FHIR date to get text for
// @returns {System.String} the text representation of the date
define function DateText(d FHIR.date):
  ToString(d.value)

// Returns a text representation of a dateTime using the CQL `ToString` function.
// @param d - a FHIR dateTime to get text for
// @returns {System.String} the text representation of the date portion of the dateTime
define function DateTimeText(d FHIR.dateTime):
  First(SplitOnMatches(ToString(d.value), 'T'))

// Returns a text representation of an instant using the CQL `ToString` function.
// @param i - a FHIR instant to get text for
// @returns {System.String} the text representation of the instant
define function InstantText(i FHIR.instant):
  ToString(i.value)

// Returns a text representation of a Quantity with the Quantity's value and unit.
// If the unit is {score}, then omit it (as it is not useful to display)
// @param q - a FHIR Quantity to get text for
// @returns {System.String} the text representation of the Quantity
define function QuantityText(q FHIR.Quantity):
  if (q is null) then null
  else if (q.unit is not null) then ToString(q.value.value) + ' ' + q.unit.value
  else if (q.code is not null) then ToString(q.value.value) + ' ' + q.code.value
  else ToString(q.value.value)

// Returns a tuple containing a Period's start and end as text representations.
// @param p - a FHIR Period to get a tuple for
// @returns {Tuple<Start System.String, End System.String>} the tuple representation of the Period
define function PeriodObject(p FHIR.Period):
  if p is null then null
  else
    {
      Start: DateTimeText(p."start"),
      End: DateTimeText(p."end")
    }

// Returns a tuple containing a Range's low and high as text representations.
// @param r - a FHIR Range to get a tuple for
// @returns {Tuple<Low System.String, High System.String>} the tuple representation of the Range
define function RangeObject(r FHIR.Range):
  if r is null then null
  else
    {
      Low: QuantityText(r.low),
      High: QuantityText(r.high)
    }

define function ObservationDate(o FHIR.Observation):
  Coalesce(
    (o.effective as FHIR.dateTime).value,
    (o.effective as FHIR.instant).value,
    (o.effective as FHIR.Period)."end".value,
    (o.effective as FHIR.Period)."start".value,
    (o.issued as FHIR.instant).value
  )

// Returns a text representation of a date associated with an Observation, preferring `effectiveDateTime`, then
// `effectivePeriod.start`, then `issued`.
// @param o - a FHIR Observation to get the text date from
// @returns {System.String} the text representation of a relevant date from the Observation
define function ObservationDateString(o FHIR.Observation):
  Coalesce(
    DateTimeText(o.effective as FHIR.dateTime),
    InstantText(o.effective as FHIR.instant),
    DateTimeText((o.effective as FHIR.Period)."end"),
    DateTimeText((o.effective as FHIR.Period)."start"),
    InstantText(o.issued)
  )

// Returns a text representation of a date associated with a MedicationStatement, preferring `effectiveDateTime`, then
// `.start`.
// @param s - a FHIR MedicationStatement to get the text date from
// @returns {System.String} the text representation of a relevant date from the MedicationStatement
define function MedicationStatementDate(s FHIR.MedicationStatement):
  Coalesce(
    DateTimeText(s.effective as FHIR.dateTime),
    DateTimeText((s.effective as FHIR.Period)."end"),
    DateTimeText((s.effective as FHIR.Period)."start")
  )

// Returns a text representation of a Condition's onset, whether represented as a dateTime, Period, Quantity (Age),
// Range (Age), or string.
// @param c - a FHIR Condition to get the text representation of the onset from
// @returns {System.String} the text representation of the Condition's onset
define function Onset(c FHIR.Condition):
  Coalesce( List{
    DateTimeText(c.onset as FHIR.dateTime),
    QuantityText(c.onset as FHIR.Age),
    PeriodObject(c.onset as FHIR.Period),
    RangeObject(c.onset as FHIR.Range),
    (c.onset as FHIR.string).value
  })

// Returns a text representation of a Condition's abatement, whether represented as a dateTime, Period, Quantity (Age),
// Range (Age), string, or boolean.
// @param c - a FHIR Condition to get the text representation of the abatement from
// @returns {System.String} the text representation of the Condition's abatement
define function Abatement(c FHIR.Condition):
  Coalesce( List{
    DateTimeText(c.abatement as FHIR.dateTime),
    // QuantityText(c.abatement as FHIR.Age),
    PeriodObject(c.abatement as FHIR.Period),
    RangeObject(c.abatement as FHIR.Range),
    (c.abatement as FHIR.string).value
  })

/*******************************************************************************
 * END: Code adapted from "Factors to Consider in Managing Chronic Pain: A Pain 
 * Management Summary"
*******************************************************************************/

/*******************************************************************************
* Condition Functions
*******************************************************************************/

define function ConditionDate(C Condition):
  Coalesce(
    (C.onset as FHIR.dateTime).value,
    (C.onset as FHIR.Period)."end".value,
    (C.onset as FHIR.Period)."start".value,
    C.recordedDate.value
  )

/**
 * The oldest condition.  For each Condition, this algorithm will use the Coalesce function, which uses the
 * first non-null result from these fields: onsetDateTime, onsetPeriod.start, assertedDate, onsetPeriod.end.
 * The found date will be used to compare Conditions and determine the oldest one.
 * @param CondList - a list of Conditions
 * @returns {Condition} the oldest Condition from the list, or null if null was passed in
 */
define function OldestCondition(CondList List<Condition>):
  First(CondList C sort by Coalesce(
    (onset as FHIR.dateTime).value,
    (onset as FHIR.Period)."start".value,
    recordedDate.value,
    (onset as FHIR.Period)."end".value)
  )

/**
 * Date of the oldest condition in a list.  For each Condition, this algorithm will use the Coalesce function, which uses the
 * first non-null result from these fields: onsetDateTime, onsetPeriod.start, assertedDate, onsetPeriod.end.
 * The found date will be used to compare Conditions and determine the oldest one. The date of the oldest Condition
 * will be returned.
 * @param CondList - a list of Conditions
 * @returns {System.String} the text representation of the Condition's date
 */
define function DateOfFirstCondition(CondList List<Condition>):
  ConditionDate(
    OldestCondition(
      CondList
    )
  )

/**
 * Conditions that are valid. This is reflected by a Condition that does not have a verificationStatus of 'refuted' or `entered-in-error`.
 * @see http://hl7.org/fhir/R4/valueset-condition-ver-status.html
 * @param CondList - a list of Conditions
 * @returns {List<Condition>} a list of valid Conditions, or null if null was passed in
 */
define function ValidCondition(CondList List<Condition>):
  CondList C where C.verificationStatus !~ "Condition Refuted"
    and C.verificationStatus !~ "Condition Entered in Error"

/*******************************************************************************
* DiagnosticReport Functions
*******************************************************************************/

// Returns a text representation of a date associated with a DiagnosticReport, preferring `effectiveDateTime`, then
// `.start`.
// @param s - a FHIR DiagnosticReport to get the text date from
// @returns {System.String} the text representation of a relevant date from the DiagnosticReport
define function DiagnosticReportDateString(d FHIR.DiagnosticReport):
  Coalesce(
    DateTimeText((d.effective as FHIR.Period)."end" as FHIR.dateTime),
    DateTimeText(d.effective as FHIR.dateTime),
    DateTimeText((d.effective as FHIR.Period)."start" as FHIR.dateTime)
  )

define function DiagnosticReportDate(d FHIR.DiagnosticReport):
  Coalesce(
    (d.effective as FHIR.Period)."end".value,
    (d.effective as FHIR.dateTime).value,
    (d.effective as FHIR.Period)."start".value
  )

define function SortedDiagnosticReports(ReportList List<FHIR.DiagnosticReport>):
  ReportList R sort by Coalesce(
    (effective as FHIR.Period)."end".value,
    (effective as FHIR.dateTime).value,
    (effective as FHIR.Period)."start".value
  )

define function MostRecentDiagnosticReport(ReportList List<FHIR.DiagnosticReport>):
  Last(
    SortedDiagnosticReports(
      ReportList
    )
  )

/**
* Diagnostic Reports that are issued in the specified "look back" period.
* TODO: Rename to LookBack once the execution engine supports overloaded functions.
* @param DiagnosticReportList - a list of DiagnosticReports
* @param LookBack - the lookback period for when the DiagnosticReport specimen was collected
* @returns {List<DiagnosticReport>} a list of DiagnosticReports in the look back period, or null if null
* was passed in
*/
define function LookBack(DiagnosticReportList List<DiagnosticReport>, LookBack System.Quantity):
  DiagnosticReportList D
    let LookBackInterval: Interval[Now() - LookBack, Now()]
    where (D.effective as FHIR.dateTime).value in LookBackInterval
      or C3F.PeriodToInterval(D.effective as FHIR.Period) overlaps LookBackInterval

  /**
* Diagnostic Reports that are issued in the specified "look back" period and after a specified "look back" date
* @param DiagnosticReportList - a list of DiagnosticReports
* @param LookBack - the lookback period for when the DiagnosticReport specimen was collected
* @param LookBackDate - the date that the DiagnosticReport test must fall after
* @returns {List<DiagnosticReport>} a list of DiagnosticReports in the look back period and after the
* look back date, or null if null was passed in
*/
define function LookBack(DiagnosticReportList List<DiagnosticReport>, LookBack System.Quantity, LookBackDate System.DateTime):
  DiagnosticReportList D
    let LookBackInterval: Interval[Now() - LookBack, Now()]
    where ( ((D.effective as FHIR.dateTime).value in LookBackInterval) and ((D.effective as FHIR.dateTime).value after LookBackDate) )
      or ( (C3F.PeriodToInterval(D.effective as FHIR.Period) overlaps LookBackInterval) and (C3F.PeriodToInterval(D.effective as FHIR.Period) starts after LookBackDate) )

// TODO: Parameterize by association window (currently hard-coded to 1 day)
define function AssociateDiagnosticReports(d1 FHIR.DiagnosticReport, d2 FHIR.DiagnosticReport):
  if (
    (d1.effective as FHIR.dateTime).value within 1 day of (d2.effective as FHIR.dateTime).value or
    (d1.effective as FHIR.dateTime).value within 1 day of (d2.effective as FHIR.Period)."start".value or 
    (d1.effective as FHIR.dateTime).value within 1 day of (d2.effective as FHIR.Period)."end".value or
    (d2.effective as FHIR.dateTime).value within 1 day of (d1.effective as FHIR.Period)."start".value or 
    (d2.effective as FHIR.dateTime).value within 1 day of (d1.effective as FHIR.Period)."end".value or
    (d1.effective as FHIR.Period) overlaps (d2.effective as FHIR.Period)
  ) then
    true
  else
    false

define function CoincidentDiagnosticReports(d1 FHIR.DiagnosticReport, d2 FHIR.DiagnosticReport):
  if (
    AssociateDiagnosticReports(d1, d2) or
    d1.encounter = d2.encounter or
    (
      Coalesce((d1.basedOn) R where R.type = 'ServiceRequest' return R.reference) =
      Coalesce((d2.basedOn) R where R.type = 'ServiceRequest' return R.reference)
    )
  ) then
    true
  else
    false


/*******************************************************************************
* Encounter Functions
*******************************************************************************/

/**
 * Encounters that are triaged, in-progress or completed.
 * @see http://hl7.org/fhir/R4/valueset-encounter-status.html
 * @param EncList - a list of Encounters
 * @returns {List<Encounter>} a list of encounters, or null if null was passed in
 */
define function RelevantEncounterStatus(EncList List<Encounter>):
  EncList E
    where E.status.value = 'triaged'
      or E.status.value = 'in-progress'
      or E.status.value = 'finished'


/*******************************************************************************
* Medication Functions
*******************************************************************************/

// Returns a text representation of a date associated with a MedicationAdministration, preferring `effectiveDateTime`, then
// `.start`.
// @param s - a FHIR MedicationAdministration to get the text date from
// @returns {System.String} the text representation of a relevant date from the MedicationAdministration
define function MedicationAdministrationDate(a FHIR.MedicationAdministration):
  Coalesce(
    DateTimeText(a.effective as FHIR.dateTime),
    DateTimeText((a.effective as FHIR.Period)."end"),
    DateTimeText((a.effective as FHIR.Period)."start")
  )

/**
* Medication administrations that are completed, according to a prescription.
* @see https://www.hl7.org/fhir/valueset-medication-admin-status.html
* @param MedList - a list of MedicationAdministrations
* @returns {List<MedicationAdministration>} a list of completed medication administrations, or null if null was passed in
*/
define function CompletedMedicationAdministration(MedList List<MedicationAdministration>):
  MedList M
    where M.status.value = 'completed'

define function CompletedMedicationDispense(MedList List<MedicationDispense>):
  MedList M
    where M.status.value = 'completed'

/**
* Diagnostic reports that are completed.
* @see https://www.hl7.org/fhir/valueset-diagnostic-report-status.html
* @param DiagnosticReportList - a list of DiagnosticReports
* @returns {List<DiagnosticReport>} a list of completed diagnostic reports, or null if null was passed in
*/
define function CompletedDiagnosticReport(DiagnosticReportList List<DiagnosticReport>):
  DiagnosticReportList D
    where D.status.value in List{'final', 'amended', 'corrected', 'appended'}

/**
* Medication Administrations that are issued in the specified "look back" period.
* TODO: Rename to LookBack once the execution engine supports overloaded functions.
* @param MedList - a list of MedicationAdministrations
* @param LookBack - the lookback period for when the medication was prescribed
* @returns {List<MedicationAdministration>} a list of MedicationAdministrations prescribed in the look back period, or null if null
* was passed in
*/
define function LookBack(MedList List<MedicationAdministration>, LookBack System.Quantity):
  MedList M
    let LookBackInterval: Interval[Now() - LookBack, Now()]
    where (M.effective as FHIR.dateTime).value in LookBackInterval
      or C3F.PeriodToInterval(M.effective as FHIR.Period) overlaps LookBackInterval

/**
* Medication requests that are completed, according to a prescription.
* @see http://hl7.org/fhir/R4/valueset-medicationrequest-status.html
* @param MedList - a list of MedicationRequests
* @returns {List<MedicationRequest>} a list of completed medication requests, or null if null was passed in
*/
define function CompletedMedicationRequest(MedList List<MedicationRequest>):
  MedList M
    where M.status.value = 'completed'

/**
* Medication requests with an intent of 'order', or one of the sub-categories of 'order'.
* @see http://hl7.org/fhir/R4/valueset-medicationrequest-intent.html
* @param MedList - a list of MedicationRequests
* @returns {List<MedicationRequest>} a list of medication requests with an intent of 'order', or null if null was passed in
*/
define function MedicationRequestsWithOrderIntent(MedList List<MedicationRequest>):
  MedList M
    where M.intent.value = 'order'
      or M.intent.value = 'original-order'
      or M.intent.value = 'reflex-order'
      or M.intent.value = 'filler-order'
      or M.intent.value = 'instance-order'

/*******************************************************************************
* Observation Functions
*******************************************************************************/


/*******************************************************************************
* Procedure Functions
*******************************************************************************/

define function ProcedureDate(p FHIR.Procedure):
  Coalesce(
    (p.performed as FHIR.dateTime).value,
    (p.performed as FHIR.Period)."end".value,
    (p.performed as FHIR.Period)."start".value
  )

// TODO: Can replace this with an overloaded function
// Returns a text representation of a date associated with a Procedure, preferring `effectiveDateTime`, then
// `.start`.
// @param s - a FHIR Procedure to get the text date from
// @returns {System.String} the text representation of a relevant date from the Procedure
define function ProcedureDateString(p FHIR.Procedure):
  Coalesce(
    DateTimeText(p.performed as FHIR.dateTime),
    DateTimeText((p.performed as FHIR.Period)."end"),
    DateTimeText((p.performed as FHIR.Period)."start")
  )

  /**
 * The oldest procedure.  For each Procedure, this algorithm will use the Coalesce function, which returns the
 * first non-null result from these fields: performedDateTime, performedPeriod.start, performedPeriod.end.
 * The found date will be used to compare Procedures and determine the oldest one.
 * @param ProcList - a list of Procedures
 * @returns {Procedure} the oldest Procedure from the list, or null if null was passed in
 */
define function OldestProcedure(ProcList List<Procedure>):
  First(ProcList P sort by Coalesce(
    (performed as FHIR.dateTime).value,
    (performed as FHIR.Period)."start".value,
    (performed as FHIR.Period)."end".value)
  )

/**
 * Date of the oldest procedure in a list.  For each Procedure, this algorithm will use the Coalesce function, which returns the
 * first non-null result from these fields: performedDateTime, performedPeriod.end, performedPeriod.start.
 * The found date will be used to compare Procedures and determine the oldest one. The date of the oldest Procedure
 * will be returned.
 * @param ProcList - a list of Procedures
 * @returns {System.String} the text representation of the Procedure's date
 */
define function DateOfFirstProcedure(ProcList List<Procedure>):
  ProcedureDate(
    OldestProcedure(
      ProcList
    )
  )

/*******************************************************************************
* Immunization Functions
*******************************************************************************/

/**
* Immunizations that are completed.
* @see http://hl7.org/fhir/R4/valueset-immunization-status.html
* @param ImmunizationList - a list of Immunizations
* @returns {List<Immunization>} a list of completed immunizations, or null if null was passed in
*/
define function CompletedImmunization(ImmunizationList List<Immunization>):
  ImmunizationList I
    where I.status.value = 'completed'
Content: application/elm+xml
Encoded data (401912 characters)
Content: application/elm+json
Encoded data (763832 characters)