Try   HackMD

CQL程式 Workthrough

程式來源

https://github.com/cqframework/cqf-exercises/blob/master/input/cql/Exercises10Key.cql

Recommendation Statement

The USPSTF recommends annual screening for lung cancer with low-dose computed tomography (LDCT) in adults aged 55 to 80 years who have a 30 pack-year smoking history and currently smoke or have quit within the past 15 years. Screening should be discontinued once a person has not smoked for 15 years or develops a health problem that substantially limits life expectancy or the ability or willingness to have curative lung surgery

USPSTF 建議對55至80歲,曾經有每年抽30包之吸菸史,目前吸菸或在過去15年內戒菸的成年人每年進行一次低劑量電腦斷層掃描(LDCT)肺癌篩檢。一旦一個人15年不吸煙或出現嚴重限制預期壽命或進行治療性肺部手術的能力或意願的健康問題,就應停止篩檢。

程式說明

Libbrary名稱

library Exercises10Key version '0.0.1'

使用Model Info

using FHIR version '4.0.1'

使用外部程式碼

include FHIRHelpers version '4.0.1' called FHIRHelpers

include FHIRCommon version '4.0.1' called FC

定義Terminilogy

codesystem "SNOMED": 'http://snomed.info/sct'
codesystem "LOINC": 'http://loinc.org'

定義value set

valueset "Lung Cancer":  'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113762.1.4.1116.89'
valueset "Smoking Status": 'http://hl7.org/fhir/us/core/ValueSet/us-core-observation-smokingstatus'
valueset "Current Smoker": 'http://example.org/fhir/ValueSet/currentsmoker'
valueset "Chest CT": 'http://example.org/fhir/ValueSet/chest-ct-procedure'
valueset "Condition Clinical Status Active": 'http://example.org/fhir/ValueSet/conditionclinicalstatusactive'

定義code

code "Tobacco Smoking Status": '72166-2' from "LOINC"
code "Former Smoker": '8517006' from "SNOMED"
code "PACKS A DAY": '8663-7' from "LOINC" display 'packs per day'

設定context為Patient

context Patient

基本參數定義:使用CQL Retrieve語法,設定"Patient age in years based on date of birth", "Smoking status observation", "Lung cancer diagnosis"與"Chest CT procedure"四個基本參數。

define "Patient age in years based on date of birth":
  AgeInYears()

define "Smoking status observation":
  [Observation: "Tobacco Smoking Status"] O
    where O.status in { 'final', 'amended' }

define "Lung cancer diagnosis":
  [Condition: "Lung Cancer"] C
    where C.clinicalStatus in "Condition Clinical Status Active"

define "Chest CT procedure":
  [Procedure: "Chest CT"] P
    where P.status = 'completed'

"55 through 80":年齡範圍為55到80歲

define "55 through 80":
  AgeInYears() >= 55 and AgeInYears() <= 80

"Most recent smoking status observation":目前吸菸狀況

define "Current smoker observation":
  "Most recent smoking status observation" O
    where (O.value as CodeableConcept) in "Current Smoker"

"Former smoker observation":是否曾經抽菸

define "Former smoker observation":
  "Most recent smoking status observation" O
    where (O.value as CodeableConcept) ~ "Former Smoker"

"Is current smoker":目前是否抽菸

define "Is current smoker":
  "Current smoker observation" is not null

"Is former smoker who quit within past 15 years":戒菸是否超過15年

define "Is former smoker who quit within past 15 years":
  ("Former smoker observation" O
    where O.effective ends 15 years or less before Today()
  ) is not null

"Pack-years":計算每年抽菸的數量(單位:Pack)

define "Pack-years":
  "Most recent smoking status observation" O
    let PacksPerDay: singleton from (O.component C where C.code ~ "PACKS A DAY").value,
    DurationInDays: duration in days of O.effective
    return System.Quantity { value: Round((PacksPerDay * (DurationInDays / 365.25)).value), unit: '{Pack-years}' }

"Has 30 pack-year smoking history":是否曾經每年抽30包菸

define "Has 30 pack-year smoking history":
  "Pack-years" >= 30 '{Pack-years}'

"Has lung cancer":是否罹患肺癌

define "Has lung cancer":
  exists ("Lung cancer diagnosis")

"Had chest CT in past year":過去一年內是否做過chest CT,由於Procedure.performed的資料型態為Choice,轉換較為複雜,因此需要呼叫外部函數FHIRCommon.ToInterval()。

define "Had chest CT in past year":
  exists ("Chest CT procedure" P
    where FC.ToInterval(P.performed) ends 1 year or less before Today()
  )

"Inclusion Criteria":建議:條件如下:

  1. 年齡介於55~80歲
  2. 仍在抽煙或以戒菸但未超過15年
  3. 曾經有一年抽30包香菸經驗
  4. 未曾罹患肺癌
  5. 過去一年內未做過chest CT
define "Inclusion Criteria":
  "55 through 80"
    and ("Is current smoker" or "Is former smoker who quit within past 15 years")
    and "Has 30 pack-year smoking history"
    and not "Has lung cancer"
    and not "Had chest CT in past year"

"Exclusion Criteria":不建議,條件如下:

  1. 不抽煙或已戒菸超過15年
  2. 已罹患肺癌
define "Exclusion Criteria":
  (
    not ("Is current smoker" or "Is former smoker who quit within past 15 years")
      or "Has lung cancer"
  )

CQL語法說明

  • CQL Retrive
    [Type:Value_set]Type為FHIR的Resource名稱,Value_set則是過濾條件。表示將讀取符合過濾條件的FHIR Resource資料。以[Observation: "Tobacco Smoking Status"]為例,表示要讀取的Observation資料必須滿則Observation.code.coding.code = 72166條件。實際FHIR資料如下:
"code": {
        "coding": [ {
          "system": "http://loinc.org",
          "code": "72166-2",
          "display": "Tobacco smoking status"
        } ],
        "text": "Tobacco smoking status"
      },
  • CQL Query Structure
    • let : allows additional expressions to be defined for use within the query let
    • with/without : allows relationships to be established between the source and other expressions
    • where : allows the results of the query to be filtered by criteria
    • sort : allows sort the results of the query to be ordered

測試與驗證

使用https://github.com/cqframework/cqf-exercises/tree/master/input/tests/Exercises10測試資料可以得到預期的結果。若使用synthea產生合成資料時,"Has 30 pack-year smoking history",這個條件無法驗證,因為synthea並沒有產生對應資料。這一點是值得思考的問題,由於實際FHIR資料並無法保證資料是否完整,因此撰寫CQL時還是必須對既有資料有一定的基本認識。