3. Data types
Requirement prefix: D3.
The DATA_VALUE hierarchy is every leaf value a clinical record can hold. Two
themes run through this section: precision is preserved, and comparison
refuses more often than it answers.
Where the quantity invariants come from#
The rendered RM 1.1.0 Data Types page does not include the class-definition
tables — the specification sources include:: them from a UML export that is
generated at build time and is not in the repository. The invariants in the
Quantity part of this section were therefore read from the Release 1.0.2
publication (Data Types Information Model, Rev 2.1.1, 20 Nov 2008,
§6.2.1–6.2.12), and the RM amendment record was then checked for every change
since:
| Release | Change affecting these classes |
|---|---|
| 1.0.3 | SPECRM-32 — DV_PROPORTION gains the zero-denominator invariant |
| 1.1.0 | SPECRM-19 — DV_SCALE added; DV_ORDINAL.limits removed |
| 1.1.0 | SPECRM-65 — units_system, units_display_name added to DV_QUANTITY |
| 1.1.0 | SPECRM-94, SPECRM-96 — arithmetic, comparison, negative durations |
None of them altered precision, accuracy, magnitude_status, or the
DV_ORDERED range invariants, so the 1.0.2 text governs them. DV_SCALE, new
in 1.1.0, is taken to inherit DV_ORDERED's invariants unchanged — it is a
DV_ORDERED descendant and the amendment describes it as DV_ORDINAL with a
Real value. That last inference is the only one not read from a source.
Coverage#
- D3.1 The crate MUST model every concrete
DATA_VALUEdescendant in openEHR RM 1.1.0:DV_BOOLEAN,DV_STATE,DV_IDENTIFIER,DV_TEXT,DV_CODED_TEXT,DV_PARAGRAPH,DV_ORDINAL,DV_SCALE,DV_QUANTITY,DV_COUNT,DV_PROPORTION,DV_DATE,DV_TIME,DV_DATE_TIME,DV_DURATION,DV_MULTIMEDIA,DV_PARSABLE,DV_URI,DV_EHR_URI,DV_INTERVAL,DV_PERIODIC_TIME_SPECIFICATION, andDV_GENERAL_TIME_SPECIFICATION. - D3.2
DV_PARAGRAPHMUST be readable and MUST NOT be recommended. openEHR deprecates it in favour of markdown-formattedDV_TEXT, and instances written before the deprecation must still round-trip.
Text and terminology#
- D3.3
DV_TEXT.valueMUST be non-empty. A field that is present and empty is indistinguishable from one that is absent, and openEHR already has a way to say absent. - D3.4
DV_TEXT.formattingMUST be non-empty when present, and a value ofplain_no_newlinesMUST be refused whenvaluecontains a newline. - D3.5
CODE_PHRASEMUST require a non-emptycode_stringand a well-formedTERMINOLOGY_ID, and MUST NOT check the code against any terminology other than openEHR's own (S1.10). - D3.6
TERM_MAPPING.matchMUST be one of>,=,<,?, modelled as a closed set rather than a character. - D3.7
DV_CODED_TEXT.valueis required by openEHR to be the rubric ofdefining_code. The crate MUST check this only for codes in the openEHR support terminology, and MUST report not checked as an outcome distinct from valid. Reporting an unchecked external code as valid would be a claim about a terminology the crate cannot see. - D3.8 Where a code appears in more than one openEHR terminology group with
different rubrics, agreement with any group MUST be accepted: a bare
DV_CODED_TEXTdoes not know which attribute it sits on.
Dates, times, and durations#
- D3.9 Partial precision MUST be preserved.
2024,2024-05, and2024-05-17are three different dates and MUST NOT be completed to one another. A completed date is a fabricated clinical fact that no downstream reader can distinguish from a real one. - D3.10 The lexical form MUST be preserved exactly, including the choice
between
Zand+00:00, and including the number of digits in a fractional second. - D3.11 Date, time, and date-time MUST be validated on construction: component ranges, month lengths, and the full Gregorian leap rule including the century exceptions.
- D3.12 A leap second (
:60) MUST be accepted. A record that captured one must not be rejected on read-back. - D3.13
DV_DURATIONMUST accept openEHR's leading-, which plain ISO 8601 does not, and MUST refuse designators that are out of order or repeated. - D3.13a The extended ISO 8601 format is required; the basic format
(
20240517) MUST be refused. It does not appear in openEHR canonical JSON, and accepting it would make2024ambiguous. Recorded as a limitation inaudit.md.
Comparison#
- D3.14 Comparison MUST be partial. Where an ordering is not established,
the answer MUST be "not comparable", never a default. Specifically:
- two dates or times whose known components agree but whose precisions differ,
- a local time and one carrying a UTC offset,
- two durations whose approximations agree and whose calendar components differ,
- values of different
DATA_VALUEclasses.
- D3.15
DV_QUANTITYvalues MUST be comparable only when theirunitsstrings are equal (S1.9). - D3.16
DV_ORDINALandDV_SCALEvalues MUST be comparable only when their symbols come from the same terminology. Ordinal2on a pain scale and ordinal2on a sedation scale are unrelated. - D3.17
DV_PROPORTIONvalues MUST be comparable only when their kinds match. - D3.18 Times carrying UTC offsets MUST be normalised to UTC before comparison.
Quantities and proportions#
- D3.19
DV_QUANTITYMUST require a finite magnitude and a non-emptyunits. A quantity with no units is a number, and openEHR hasDV_COUNT. - D3.19a The non-empty requirement in
D3.19is a declared narrowing of openEHR'sUnits_valid: units /= void, which forbids only a missing value and not an empty one. What survives: everyDV_QUANTITYthis crate accepts has a units string that names a measured property, which is whatis_strictly_comparable_todepends on (D3.15). What it costs: an instance carrying"units": ""is refused rather than read. - D3.20
precisionMUST satisfy openEHR'sPrecision_valid: precision >= -1.0means an integral quantity;-1means no limit — any number of decimal places — and is a stated precision, distinct from the attribute being absent. Requiringprecision >= 0would reject conformant data. - D3.20a
is_integralMUST be exactlyprecision = 0, as openEHR defines it, and MUST answer "unknown" when no precision is recorded. A magnitude that happens to be whole is not a quantity declared integral. - D3.21
accuracyMUST be finite and MUST satisfy both openEHR rules:Accuracy_validity— a percentage accuracy lies in 0–100 — andAccuracy_is_percent_validity— an accuracy of 0 must not be flagged as a percentage, because 0 means 100% accurate and "0%" reads as the opposite. - D3.21a
-1.0MUST be honoured as openEHR'sunknown_accuracy_value: it records that accuracy was not measured, and a reader treating it as an error of minus one is wrong by the width of the scale.accuracy_unknownMUST answer true for it and for an absent accuracy, because both mean the same thing to a reader and only one of them is obvious. - D3.22
magnitude_statusMUST be one of=,<,>,<=,>=,~, modelled as a closed set — openEHR'svalid_magnitude_status. A result below an assay's detection limit is a real result and recording it as the limit loses the only part that matters. - D3.23
DV_PROPORTIONMUST refuse a zero denominator, MUST require denominator 1 forpk_unitaryand 100 forpk_percent, and MUST require integral parts forpk_fractionandpk_integer_fraction. These comparisons are exact: a tolerance would accept a denominator of 99.999 and then render it as a percentage. - D3.23a
DV_PROPORTION.precisionMUST satisfyPrecision_validity: precision = 0 implies is_integral. Note the direction: declaring precision0asserts the parts are whole numbers. It does not forbid an integral kind from carrying a precision, which is the reading an implementation usually arrives at and which rejects valid data. - D3.24
DV_ORDEREDreference ranges MUST be modelled, and "outside the normal range" MUST be distinguishable from "no normal range recorded". - D3.24a
normal_statusMUST come from the openEHRnormal statusescode set (Normal_status_validity). A renderer prints this letter verbatim beside a result, so an invented one reaches a clinician. - D3.24b Where both
normal_rangeandnormal_statusare present, they MUST agree:Nif and only if the value lies inside the range (Normal_range_and_status_consistency). They disagree when a result is copied from one system and its flag from another — which is the case where a clinician sees a normal flag beside an abnormal number.
Encapsulated data#
- D3.25
DV_MULTIMEDIAMUST NOT render its bytes in anyDisplayorDebugoutput.DebugMUST print media type and length instead. This is the one place the crate's usual "Debugmay show everything" rule is overridden, because "everything" is a megabyte of base64 that ends up in a ticket. - D3.26
DV_MULTIMEDIA.integrity_checkMUST be verifiable, and the verification MUST distinguish passed, failed, not recorded, no inline data, and unsupported algorithm. A field saying "SHA-256: …" that nothing checks is worse than no field, because it reads as an assurance. - D3.27 The crate MUST read an integrity check declared as
SHA-1and MUST NOT emit one. openEHR lists SHA-1; a clinical record may outlive it, and it has already been outlived. - D3.28
DV_PARSABLEMUST require bothvalueandformalismto be non-empty. An empty formalism leaves content nothing can decide how to read. - D3.29 Base64 decoding MUST tolerate embedded whitespace, which XML-derived payloads carry and which conveys nothing.
URIs#
- D3.30
DV_URIMUST require a well-formed scheme and MUST refuse spaces and control characters. - D3.31
DV_EHR_URIMUST require the schemeehr.LINK.targetis typedDV_EHR_URIprecisely so that a link cannot point out of the record without saying so. - D3.32 Validity of a
DV_EHR_URIis structural only. The crate cannot resolve it, and documentation MUST NOT let "valid" be read as "resolvable".
Identifiers as values#
- D3.33
DV_IDENTIFIER.idMUST be non-empty. - D3.34
DV_IDENTIFIER'sDisplayMUST render the type and issuer and MUST NOT render the identifier (X11.6).