Skip to main content
Version: v0.1.14

Read measured values and their units

A measured value is a magnitude, a unit, and a type, and each of the three can be misread. These readers keep all three as the document wrote them: the magnitude as its exact text, the coded unit apart from the display string, and the value[x] variant that is actually present. Nothing here converts a unit or computes a flag.

Read an Observation's value by its type​

readObservationValue names the value[x] variant that is present. quantity is filled in only when that variant is a Quantity, so branch on type first:

import { parseResource, readObservationValue } from "@cosyte/fhir";

const numeric = parseResource(
'{"resourceType":"Observation","status":"final","code":{"text":"synthetic"},"valueQuantity":{"value":120.0,"unit":"mmHg","system":"http://unitsofmeasure.org","code":"mm[Hg]"}}',
).resource;

const reading = readObservationValue(numeric);

reading?.type; // => "Quantity"
reading?.quantity?.value?.raw; // => "120.0"
reading?.quantity?.code; // => "mm[Hg]"
reading?.quantity?.unit; // => "mmHg"

const text = parseResource(
'{"resourceType":"Observation","status":"final","code":{"text":"synthetic"},"valueString":"POSITIVE"}',
).resource;

readObservationValue(text)?.type; // => "String"
readObservationValue(text)?.quantity; // => undefined

Compare on code, the machine-actionable UCUM unit, never on unit, which is a display string a sender is free to spell however it likes.

Keep the magnitude exact​

The magnitude is a FhirDecimal, the exact text the sender wrote. equals treats 120.0 and 120 as different statements, because the trailing zero records the precision; equalsValue compares the quantity alone:

import { decimal, parseResource, readObservationValue } from "@cosyte/fhir";

const { resource } = parseResource(
'{"resourceType":"Observation","status":"final","code":{"text":"synthetic"},"valueQuantity":{"value":0.010,"system":"http://unitsofmeasure.org","code":"mg"}}',
);

const value = readObservationValue(resource)?.quantity?.value;

value?.toString(); // => "0.010"
value?.equals(decimal("0.01")); // => false
value?.equalsValue(decimal("0.01")); // => true

toNumber is there for when you have decided the precision loss of a JavaScript number is acceptable; nothing in the package calls it for you.

Read medication doses​

readMedicationDoses reads every dose quantity of a MedicationRequest (dosageInstruction) or a MedicationStatement (dosage), in document order. Pass the resource type, which resourceType reads for you:

import { parseResource, readMedicationDoses, resourceType } from "@cosyte/fhir";

const { resource } = parseResource(
'{"resourceType":"MedicationRequest","status":"active","intent":"order","subject":{"reference":"Patient/syn-0001"},"dosageInstruction":[{"doseAndRate":[{"doseQuantity":{"value":5,"unit":"mg","system":"http://unitsofmeasure.org","code":"mg"}}]}]}',
);

const doses = readMedicationDoses(resource, resourceType(resource));

doses.map((dose) => [dose.value?.raw, dose.code]); // => [["5", "mg"]]

Read reference ranges and interpretation flags​

readReferenceRanges and readInterpretations surface what the sender wrote. Neither derives a flag from a value and a range: an abnormal flag is the sender's statement, read as written.

import { parseResource, readInterpretations, readReferenceRanges } from "@cosyte/fhir";

const { resource } = parseResource(
'{"resourceType":"Observation","status":"final","code":{"text":"synthetic"},"valueQuantity":{"value":100,"system":"http://unitsofmeasure.org","code":"mg/dL"},"referenceRange":[{"low":{"value":70,"system":"http://unitsofmeasure.org","code":"mg/dL"},"high":{"value":99,"system":"http://unitsofmeasure.org","code":"mg/dL"}}],"interpretation":[{"coding":[{"system":"http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation","code":"N"}]}]}',
);

const [range] = readReferenceRanges(resource);

range?.low?.value?.raw; // => "70"
range?.high?.value?.raw; // => "99"
readInterpretations(resource).map((flag) => flag.code); // => ["N"]

Check a vital sign's unit​

The R4 vital-signs profile requires particular UCUM units for each vital sign. validateResource checks them on an Observation that declares the vital-signs category or names the vital-signs profile in meta.profile, on its value and on each component's, for the LOINC codes that profile lists. It checks the unit; it never converts one. requiredVitalSignUnits returns the units required for a LOINC code, and undefined for a code the profile does not list:

import { parseResource, requiredVitalSignUnits, validateResource } from "@cosyte/fhir";

requiredVitalSignUnits("8480-6"); // => ["mm[Hg]"]

const { resource } = parseResource(
'{"resourceType":"Observation","status":"final","category":[{"coding":[{"system":"http://terminology.hl7.org/CodeSystem/observation-category","code":"vital-signs"}]}],"code":{"coding":[{"system":"http://loinc.org","code":"8480-6"}]},"valueQuantity":{"value":120,"unit":"mmHg","system":"http://unitsofmeasure.org","code":"mmHg"}}',
);

const outcome = validateResource(resource);

outcome.valid; // => false
outcome.issues.map((issue) => [issue.code, issue.expression]); // => [["VITAL_SIGN_UNIT_NONCONFORMANT", "Observation.valueQuantity"]]

Reference​