The process described here to evaluate a CQL query uses the Quality Reporting framework of FHIR and includes three steps. First, a Library resource is created on Blaze, followed by a Measure resource, which is then evaluated in the third step.
The Library resource serves as a container for the CQL Query, which in fact is also a CQL library.
The following sub-items have to be done to create the corresponding Library resource:
Using the following command:
cat docs/cql-queries/gender-male.cql | base64 | tr -d '\n'
the following Base64 string can be generated:
bGlicmFyeSBSZXRyaWV2ZQp1c2luZyBGSElSIHZlcnNpb24gJzQuMC4wJwppbmNsdWRlIEZISVJIZWxwZXJzIHZlcnNpb24gJzQuMC4wJwoKY29udGV4dCBQYXRpZW50CgpkZWZpbmUgSW5Jbml0aWFsUG9wdWxhdGlvbjoKICBQYXRpZW50LmdlbmRlciA9ICdtYWxlJwo=
Other methods of Base64 encoding are of course also possible.
This Base64 string is then inserted into the library resource under content[0].data
. The resulting library resource will look like this:
{
"resourceType": "Library",
"url": "urn:uuid:a2b9f4b4-5d5b-46bd-a9fd-35f024c852fa",
"status": "active",
"type" : {
"coding" : [
{
"system": "http://terminology.hl7.org/CodeSystem/library-type",
"code" : "logic-library"
}
]
},
"content": [
{
"contentType": "text/cql",
"data": "bGlicmFyeSBSZXRyaWV2ZQp1c2luZyBGSElSIHZlcnNpb24gJzQuMC4wJwppbmNsdWRlIEZISVJIZWxwZXJzIHZlcnNpb24gJzQuMC4wJwoKY29udGV4dCBQYXRpZW50CgpkZWZpbmUgSW5Jbml0aWFsUG9wdWxhdGlvbjoKICBQYXRpZW50LmdlbmRlciA9ICdtYWxlJwo="
}
]
}
The library resource can be uploaded using curl for example:
curl -sH "Content-Type: application/fhir+json" -d @library.json "http://localhost:8080/fhir/Library"
The Measure resource represents the actual definition of the measure, which is evaluated in the third step. In its simplest form, a Measure resource looks like this:
{
"resourceType": "Measure",
"url": "urn:uuid:49f4c7de-3320-4208-8e60-ecc0d8824e08",
"status": "active",
"library": "urn:uuid:a2b9f4b4-5d5b-46bd-a9fd-35f024c852fa",
"scoring": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/measure-scoring",
"code": "cohort"
}
]
},
"group": [
{
"population": [
{
"code": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
"code": "initial-population"
}
]
},
"criteria": {
"language": "text/cql-identifier",
"expression": "InInitialPopulation"
}
}
]
}
]
}
The two important points here are on the one hand the reference to the Library resource via its canonical URL (urn:uuid:a2b9f4b4-5d5b-46bd-a9fd-35f024c852fa
) and on the other hand the name of the CQL expression to be evaluated (InitialPopulation
), which must appear in the CQL library.
The measure resource can be uploaded using curl, for example:
curl -sH "Content-Type: application/fhir+json" -d @measure.json "http://localhost:8080/fhir/Measure"
The Measure resource is finally evaluated using the FHIR operation $evaluate-measure.
Via curl this can be done as follows:
curl -s 'http://localhost:8080/fhir/Measure/$evaluate-measure?measure=urn:uuid:49f4c7de-3320-4208-8e60-ecc0d8824e08&periodStart=2000&periodEnd=2030'
the result should be the following MeasureReport:
{
"resourceType": "MeasureReport",
"status": "complete",
"type": "summary",
"measure": "urn:uuid:49f4c7de-3320-4208-8e60-ecc0d8824e08",
"date": "2021-06-14T10:54:31.458494Z",
"period": {
"start": "2000",
"end": "2030"
},
"group": [
{
"population": [
{
"code": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
"code": "initial-population"
}
]
},
"count": 0
}
]
}
]
}
Under group[0].population[0].count
the result of the query can be found.
By default, the evaluation results in a MeasureReport of type summary
. Such a MeasureReport contains only the number of resources of each population. However, if you also need the resources itself, you can have a MeasureReport of type subject-list
generated. This works as follows:
curl -sd '{"resourceType": "Parameters", "parameter": [{"name": "periodStart", "valueDate": "2000"}, {"name": "periodEnd", "valueDate": "2030"}, {"name": "measure", "valueString": "urn:uuid:49f4c7de-3320-4208-8e60-ecc0d8824e08"}, {"name": "reportType", "valueCode": "subject-list"}]}' -H "Content-Type: application/fhir+json" 'http://localhost:8080/fhir/Measure/$evaluate-measure'
the result should be the following MeasureReport:
{
"resourceType": "MeasureReport",
"id": "C6QKSKQ2YWQIY4A2",
"meta": {
"versionId": "913",
"lastUpdated": "2021-06-14T12:50:19.711Z"
},
"status": "complete",
"type": "subject-list",
"measure": "urn:uuid:49f4c7de-3320-4208-8e60-ecc0d8824e08",
"date": "2021-06-14T12:50:19.431239Z",
"period": {
"start": "2000",
"end": "2030"
},
"group": [
{
"population": [
{
"code": {
"coding": [
{
"system": "http://terminology.hl7.org/CodeSystem/measure-population",
"code": "initial-population"
}
],
"count": 57,
"subjectResults": {
"reference": "List/C6QKSKQ2V7DAF3X6"
}
}
}
]
}
]
}
When generating the MeasureReport, the list of Patient references has been stored by Blaze in the List resource List/C6QKSKQ2V7DAF3X6
. If this List resource is called via:
curl -s 'http://localhost:8080/fhir/List/C6QKSKQ2V7DAF3X6'
it looks like this, truncated after two references:
{
"resourceType": "List",
"id": "C6QKSKQ2V7DAF3X6",
"meta": {
"versionId": "913",
"lastUpdated": "2021-06-14T12:50:19.711Z"
},
"status": "current",
"mode": "working",
"entry": [
{
"item": {
"reference": "Patient/C6QKGRHBFJIQ3B5U"
}
},
{
"item": {
"reference": "Patient/C6QKGROQ5G5NCKUY"
}
}
]
}
Thus, all patient references can be found under entry.item.reference
.
The pure List resource with its references is not particularly useful at first. When it comes to further processing of the populations, you would rather download the patients themselves.
There are two ways to do this, on the one hand you can use the _include
search parameter on the list endpoint and on the other hand you can use the _list
search parameter on the patient endpoint.
The following call:
curl -s 'http://localhost:8080/fhir/List?_id=C6QKSKQ2V7DAF3X6&_include=List:item'
yields, truncated and thinned out after two patients, the following bundle:
{
"resourceType": "Bundle",
"id": "C6QKZUY3NTTIU5M5",
"type": "searchset",
"entry": [
{
"fullUrl": "http://localhost:8080/fhir/List/C6QKSKQ2V7DAF3X6",
"resource": {
"resourceType": "List",
"id": "C6QKSKQ2V7DAF3X6",
"meta": {
"versionId": "913",
"lastUpdated": "2021-06-14T12:50:19.711Z"
},
"status": "current",
"mode": "working",
"entry": [
{
"item": {
"reference": "Patient/C6QKGRHBFJIQ3B5U"
}
},
{
"item": {
"reference": "Patient/C6QKGROQ5G5NCKUY"
}
}
]
},
"search": {
"mode": "match"
}
},
{
"fullUrl": "http://localhost:8080/fhir/Patient/C6QKGROQ5G5NCKUY",
"resource": {
"resourceType": "Patient",
"id": "C6QKGROQ5G5NCKUY",
"meta": {
"versionId": "7",
"lastUpdated": "2021-06-14T11:07:25.416Z"
},
"gender": "male",
"birthDate": "1913-10-06"
},
"search": {
"mode": "include"
}
},
{
"fullUrl": "http://localhost:8080/fhir/Patient/C6QKGUT6PPAUX3FV",
"resource": {
"resourceType": "Patient",
"id": "C6QKGUT6PPAUX3FV",
"meta": {
"versionId": "59",
"lastUpdated": "2021-06-14T11:08:13.899Z"
},
"gender": "male",
"birthDate": "2006-03-15"
},
"search": {
"mode": "include"
}
}
]
}
This variant has the disadvantage that paging cannot be used. Thus, the include variant is only suitable for small population sizes.
The following call:
curl -s 'http://localhost:8080/fhir/Patient?_list=C6QKSKQ2V7DAF3X6&_count=2'
results in, thinned out, the following bundle:
{
"resourceType": "Bundle",
"id": "C6QK4HB4FDS6PKRY",
"type": "searchset",
"entry": [
{
"fullUrl": "http://localhost:8080/fhir/Patient/C6QKGRHBFJIQ3B5U",
"resource": {
"resourceType": "Patient",
"id": "C6QKGRHBFJIQ3B5U",
"meta": {
"versionId": "3",
"lastUpdated": "2021-06-14T11:07:19.316Z"
},
"gender": "male",
"birthDate": "1986-06-22"
},
"search": {
"mode": "match"
}
},
{
"fullUrl": "http://localhost:8080/fhir/Patient/C6QKGROQ5G5NCKUY",
"resource": {
"resourceType": "Patient",
"id": "C6QKGROQ5G5NCKUY",
"meta": {
"versionId": "7",
"lastUpdated": "2021-06-14T11:07:25.416Z"
},
"gender": "male",
"birthDate": "1913-10-06"
},
"search": {
"mode": "match"
}
}
],
"link": [
{
"relation": "next",
"url": "http://localhost:8080/fhir/Patient?_list=C6QKSKQ2V7DAF3X6&_count=2&__t=913&__page-id=C6QKGRPAJHAD6KFW"
}
]
}
This variant uses the special search parameter _list
to search for patients included in the list with the given ID. This list of patients can be further shaped using the normal search parameters like _count
or additionally using _include
.