Medication order
DSP medication orders land on MedicationRequest. DSP's free-text dosing narrative fits R5's renderedDosage better than R4's dosageInstruction.text — a good candidate for a cross-version extension.
order.medication
MedicationRequest (R4) + R5 renderedDosage (xver)
Field-by-field
| DSP | FHIR R4 | Notes |
|---|---|---|
type: MEDICATION_ORDER | MedicationRequest resource type | |
intent (proposal/plan/order/...) | MedicationRequest.intent | Direct valueset match. |
description | dosageInstruction.text; also cross-version extension renderedDosageInstruction (R5 xver) | Free-text "Chantix 0.5 mg, take one a day for 3 days, then twice a day". |
reason (string) | reasonCode.text | |
reason_references | reasonReference[] → Condition / Observation | |
order_data.medication (RxNorm) | medicationCodeableConcept | Or medicationReference → Medication for compound drugs. |
order_data.form | Medication.form or dosageInstruction.method | |
order_data.dosage + dosage_unit | dosageInstruction.doseAndRate.doseQuantity | UCUM units required. |
order_data.frequency | dosageInstruction.timing.repeat | count→frequency, period/period_unit→period/periodUnit; prn→asNeededBoolean. |
order_data.frequency.text | dosageInstruction.text | Keep the narrative; structured fields are best-effort. |
order_data.duration | dosageInstruction.timing.repeat.bounds[x] | boundsDuration with UCUM unit. |
order_data.route + route_coded | dosageInstruction.route | Bind to NCIT or SNOMED CT route codes. |
order_data.refills | dispenseRequest.numberOfRepeatsAllowed | |
order_data.dispense | dispenseRequest.quantity | "56" tablets. |
order_data.discontinue / discontinue_date | status = stopped + statusReason (R4 native) + meta.lastUpdated for the date | Or represent via a new MedicationRequest with intent=order and status=stopped. |
order_data.notes | note.text | |
confidence_score | DSP extension confidence-score | No native request-side element in R4 or R5. The IG defines confidence-score as a new extension; R5's grading pattern from Evidence.certainty informs its valueset. |
update_status | meta.versionId + Provenance.activity |
Example
DSP
{
"id": "med-001",
"type": "MEDICATION_ORDER",
"intent": "order",
"description": "Chantix 0.5 mg, take one a day for 3 days, then twice a day",
"reason": "Smoking cessation",
"order_data": {
"medication": { "text":"Chantix",
"codes":[{"system":"rxnorm","code":"1000048"}]},
"form": "tablet",
"dosage": "0.5", "dosage_unit":"mg",
"frequency": {"count":1,"period":1,"period_unit":"d","prn":false},
"route_coded": {"codes":[{"system":"NCIT","code":"C38288"}]},
"refills":"5","dispense":"56"
},
"confidence_score": 1.0
} FHIR R4 (DSP-FHIR profile)
{
"resourceType":"MedicationRequest",
"status":"active","intent":"order",
"medicationCodeableConcept":{
"coding":[{"system":"http://www.nlm.nih.gov/research/umls/rxnorm","code":"1000048"}],
"text":"Chantix"
},
"subject":{"reference":"Patient/pat-67890"},
"encounter":{"reference":"Encounter/enc-12345"},
"reasonCode":[{"text":"Smoking cessation"}],
"dosageInstruction":[{
"text":"Chantix 0.5 mg, take one a day for 3 days, then twice a day",
"timing":{"repeat":{"frequency":1,"period":1,"periodUnit":"d"}},
"asNeededBoolean":false,
"route":{"coding":[{"system":"http://ncithesaurus.nci.nih.gov","code":"C38288","display":"Oral"}]},
"doseAndRate":[{"doseQuantity":{"value":0.5,"unit":"mg","system":"http://unitsofmeasure.org","code":"mg"}}]
}],
"dispenseRequest":{"numberOfRepeatsAllowed":5,"quantity":{"value":56,"unit":"tablet"}},
"extension":[{
"url":"https://dsp-fhir.org/StructureDefinition/confidence-score",
"valueDecimal":1.0
}]
} DSP → FHIR mapping
Executable FHIR Mapping Language skeleton for DspMedicationOrder → MedicationRequest. The full map ships in the downloadable IG package.
map "https://dsp-fhir.org/StructureMap/DspMedicationOrderToMedicationRequest" = "DspMedicationOrderToMedicationRequest"
uses "https://dsp-fhir.org/StructureDefinition/DspOrderMedicationResource" alias DspMedOrder as source
uses "http://hl7.org/fhir/StructureDefinition/MedicationRequest" alias MedicationRequest as target
group DspMedicationOrderToMedicationRequest(source src : DspMedOrder, target tgt : MedicationRequest) {
src.id as id -> tgt.id = id;
src -> tgt.status = 'active';
src -> tgt.intent = 'order';
src.payload as p then {
p.drug as drug -> tgt.medication = create('CodeableConcept') as cc,
cc.text = drug "drug-text";
p.rxnorm_code as rx -> tgt.medication as med, med.coding as co,
co.system = 'http://www.nlm.nih.gov/research/umls/rxnorm', co.code = rx "rxnorm";
// Rendered sig - both extension (xver) and literal dosageInstruction.text
p.rendered_dosage_instruction as rdi -> tgt.extension as ext then {
rdi -> ext.url = 'https://dsp-fhir.org/StructureDefinition/dsp-rendered-dosage-instruction',
ext.value = create('string') as v, v.value = rdi;
} "rendered-sig";
p.rendered_dosage_instruction as rdi -> tgt.dosageInstruction as di, di.text = rdi "sig-text";
p.prn as prn -> tgt.dosageInstruction as di, di.asNeededBoolean = prn "prn";
};
src.confidence as conf -> tgt.extension as ext then {
conf -> ext.url = 'https://dsp-fhir.org/StructureDefinition/dsp-confidence-score',
ext.value = create('decimal') as v, v.value = conf;
} "confidence";
// One extension per turn index (controller adds the version-pinned transcript reference).
src.transcript_turn_refs as t -> tgt.extension as ext then {
t -> ext.url = 'https://dsp-fhir.org/StructureDefinition/dsp-transcript-turn-ref',
ext.extension as turnExt,
turnExt.url = 'turn',
turnExt.value = create('integer') as v, v.value = t;
} "turn-ref";
} FHIR → DSP (canonical $graphql read)
Standard FHIR $graphql selects every native MedicationRequest field and DSP-namespaced extension that the write projection populated. A small adapter renames the result into the DSP shape — no FML inverse engine required.
Canonical query
query DspMedicationOrder($id: ID!) {
MedicationRequest(id: $id) {
id status intent
meta { profile source versionId lastUpdated }
medicationCodeableConcept {
text
coding { system code display }
}
medicationReference { reference }
reasonCode { text coding { system code display } }
reasonReference { reference }
dosageInstruction {
text
asNeededBoolean
timing {
repeat {
frequency period periodUnit
boundsDuration { value unit system code }
}
}
route { coding { system code display } text }
doseAndRate {
doseQuantity { value unit system code }
}
}
dispenseRequest {
numberOfRepeatsAllowed
quantity { value unit }
}
note { text }
rendered: extension(url: "https://dsp-fhir.org/StructureDefinition/dsp-rendered-dosage-instruction") {
valueString
}
confidence: extension(url: "https://dsp-fhir.org/StructureDefinition/dsp-confidence-score") {
valueDecimal
}
spokenForms: extension(url: "https://dsp-fhir.org/StructureDefinition/dsp-spoken-forms") {
valueString
}
turnRefs: extension(url: "https://dsp-fhir.org/StructureDefinition/dsp-transcript-turn-ref") {
transcript: extension(url: "transcript") { valueReference { reference } }
turn: extension(url: "turn") { valueInteger }
}
}
} DSP reconstruction adapter
function toDspMedicationOrder(m) {
const med = m.medicationCodeableConcept;
const di = m.dosageInstruction?.[0];
const turnRefs = m.turnRefs ?? [];
return {
id: m.id,
type: 'MEDICATION_ORDER',
intent: m.intent,
description: m.rendered?.[0]?.valueString ?? di?.text,
reason: m.reasonCode?.[0]?.text,
reason_references: m.reasonReference?.map(r => r.reference),
order_data: {
medication: {
text: med?.text,
codes: (med?.coding ?? []).map(toDspCode),
},
dosage: di?.doseAndRate?.[0]?.doseQuantity?.value,
dosage_unit: di?.doseAndRate?.[0]?.doseQuantity?.unit,
route_coded: { codes: (di?.route?.coding ?? []).map(toDspCode) },
frequency: di?.timing?.repeat ? {
count: di.timing.repeat.frequency,
period: di.timing.repeat.period,
period_unit: di.timing.repeat.periodUnit,
prn: di.asNeededBoolean,
} : undefined,
duration: di?.timing?.repeat?.boundsDuration && {
value: di.timing.repeat.boundsDuration.value,
unit: di.timing.repeat.boundsDuration.unit,
},
refills: m.dispenseRequest?.numberOfRepeatsAllowed,
dispense: m.dispenseRequest?.quantity?.value,
notes: m.note?.map(n => n.text),
},
confidence_score: m.confidence?.[0]?.valueDecimal,
spoken_forms: m.spokenForms?.map(e => e.valueString) ?? [],
provenance: turnRefs.map(t => t.turn?.valueInteger),
transcript_ref: turnRefs[0]?.transcript?.valueReference?.reference,
};
} dsp-rendered-dosage-instruction (the adapter prefers it over the
structured dosageInstruction.text reconstruction).
SQL-on-FHIR v2 ViewDefinition that flattens every field above — including DSP extensions — into a tabular projection. Runnable as-is on any spec-conformant engine (Pathling, sof-exec, Aidbox SQL-on-FHIR, Databricks). See the SQL-on-FHIR v2 spec. These ViewDefinitions also ship as JSON in the IG zip.
dsp_medication_request — DSP MedicationRequest
Flattens DSP medication orders: route/dose/frequency/duration, substitution, first dosageInstruction.
{
"resourceType": "ViewDefinition",
"url": "https://dsp-fhir.org/ViewDefinition/dsp-medication-request",
"name": "dsp_medication_request",
"title": "DSP MedicationRequest",
"status": "draft",
"description": "Flattens DSP medication orders: route/dose/frequency/duration, substitution, first dosageInstruction.",
"resource": "MedicationRequest",
"fhirVersion": [
"4.0.1"
],
"select": [
{
"column": [
{
"name": "id",
"path": "id",
"type": "id",
"description": "Server-assigned logical id."
},
{
"name": "version_id",
"path": "meta.versionId",
"type": "id",
"description": "FHIR version id (drives NEW/UPDATED classification)."
},
{
"name": "last_updated",
"path": "meta.lastUpdated",
"type": "instant",
"description": "Instant of last mutation."
},
{
"name": "meta_source",
"path": "meta.source",
"type": "uri"
},
{
"name": "payload_version",
"path": "meta.tag.where(system='https://dsp-fhir.org/CodeSystem/payload-version').code.first()",
"type": "code",
"description": "DSP payload version this resource was last emitted under."
},
{
"name": "confidence_score",
"path": "extension('https://dsp-fhir.org/StructureDefinition/confidence-score').value.ofType(decimal)",
"type": "decimal",
"description": "DSP confidence (0..1)."
},
{
"name": "transcript_ref",
"path": "extension('https://dsp-fhir.org/StructureDefinition/transcript-turn-refs').extension('transcript').value.ofType(Reference).reference",
"type": "string",
"description": "DocumentReference/<id>/_history/<v> that pins the transcript version for turn indices."
},
{
"name": "turn_indices",
"path": "extension('https://dsp-fhir.org/StructureDefinition/transcript-turn-refs').extension('turn').value.ofType(integer)",
"type": "integer",
"collection": true,
"description": "Turn indices joined by $ground into transcript content."
},
{
"name": "spoken_forms",
"path": "extension('https://dsp-fhir.org/StructureDefinition/spoken-forms').extension('form').value.ofType(string)",
"type": "string",
"collection": true
},
{
"name": "search_terms",
"path": "extension('https://dsp-fhir.org/StructureDefinition/search-terms').extension('term').value.ofType(string)",
"type": "string",
"collection": true
},
{
"name": "status",
"path": "status",
"type": "code"
},
{
"name": "intent",
"path": "intent",
"type": "code"
},
{
"name": "subject_patient_id",
"path": "subject.reference.substring(8)",
"type": "string"
},
{
"name": "encounter_id",
"path": "encounter.reference.substring(10)",
"type": "string"
},
{
"name": "authored_on",
"path": "authoredOn",
"type": "dateTime"
},
{
"name": "requester_practitioner_id",
"path": "requester.reference.where($this.startsWith('Practitioner/')).substring(13).first()",
"type": "string"
},
{
"name": "medication_code_system",
"path": "medication.ofType(CodeableConcept).coding.system.first()",
"type": "uri"
},
{
"name": "medication_code",
"path": "medication.ofType(CodeableConcept).coding.code.first()",
"type": "code"
},
{
"name": "medication_display",
"path": "medication.ofType(CodeableConcept).coding.display.first()",
"type": "string"
},
{
"name": "medication_text",
"path": "medication.ofType(CodeableConcept).text",
"type": "string"
},
{
"name": "medication_reference",
"path": "medication.ofType(Reference).reference",
"type": "string",
"description": "Populated when Medication is a contained/shared resource instead of inline CodeableConcept."
},
{
"name": "dose_value",
"path": "dosageInstruction.doseAndRate.dose.ofType(Quantity).value.first()",
"type": "decimal"
},
{
"name": "dose_unit",
"path": "dosageInstruction.doseAndRate.dose.ofType(Quantity).unit.first()",
"type": "string"
},
{
"name": "route_code",
"path": "dosageInstruction.route.coding.code.first()",
"type": "code"
},
{
"name": "frequency",
"path": "dosageInstruction.timing.repeat.frequency.first()",
"type": "integer"
},
{
"name": "period",
"path": "dosageInstruction.timing.repeat.period.first()",
"type": "decimal"
},
{
"name": "period_unit",
"path": "dosageInstruction.timing.repeat.periodUnit.first()",
"type": "code"
},
{
"name": "duration",
"path": "dosageInstruction.timing.repeat.bounds.ofType(Duration).value.first()",
"type": "decimal"
},
{
"name": "duration_unit",
"path": "dosageInstruction.timing.repeat.bounds.ofType(Duration).unit.first()",
"type": "string"
},
{
"name": "as_needed",
"path": "dosageInstruction.asNeeded.ofType(boolean).first()",
"type": "boolean"
},
{
"name": "substitution_allowed",
"path": "substitution.allowed.ofType(boolean)",
"type": "boolean"
},
{
"name": "reason_reference",
"path": "reasonReference.reference.first()",
"type": "string"
},
{
"name": "refills",
"path": "dispenseRequest.numberOfRepeatsAllowed",
"type": "unsignedInt"
}
]
}
]
}MedicationRequest.renderedDosageInstruction
in R5 is an explicit string for exactly what DSP's description carries.
Publish it as a cross-version extension on R4 instead of overloading dosageInstruction.text.