Skip to content

Commit b7fd53f

Browse files
committed
Update operations
1 parent 78eee80 commit b7fd53f

1 file changed

Lines changed: 206 additions & 7 deletions

File tree

docs/v2-to-fhir-spec/add-mapping-fhir-operation.md

Lines changed: 206 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
11
# ConceptMap Mapping Operations
22

3-
This page defines three operations for managing individual mappings within large [ConceptMap](https://hl7.org/fhir/conceptmap.html) resources: `$add-mapping`, `$update-mapping`, and `$remove-mapping`.
3+
This page defines four operations for managing individual mappings within large [ConceptMap](https://hl7.org/fhir/conceptmap.html) resources: `$add-mapping`, `$update-mapping`, `$remove-mapping`, and `$replace-element`.
44

55
## Background
66

77
The existing [$add](https://fhir.hl7.org/fhir/resource-operation-add.html) and [$remove](https://fhir.hl7.org/fhir/resource-operation-remove.html) operations (see [Operations for Large Resources](https://www.hl7.org/fhir/operations-for-large-resources.html)) return the modified resource and use structural matching on array entries. ConceptMap resources may contain thousands of mappings and require matching on a domain-specific composite key, so these operations return an OperationOutcome instead.
88

9-
For all three operations, only `group` elements in the input are processed; all other elements are ignored.
9+
For all four operations, only `group` elements in the input are processed; all other elements are ignored.
1010

1111
## Matching Algorithm
1212

13-
All three operations use the same matching algorithm. Two mappings match when they have identical values for `group.source`, `group.target`, `element.code`, and `element.target.code`.
13+
`$add-mapping`, `$update-mapping`, and `$remove-mapping` use target-level matching. Two mappings match when they have identical values for `group.source`, `group.target`, `element.code`, and `element.target.code`.
1414

1515
For `noMap` entries (no `element.target`), matching uses `group.source`, `group.target`, and `element.code` only.
1616

1717
Only these fields are compared; other element properties such as `display` or `relationship` are not considered. To update an existing mapping's non-key properties, use `$update-mapping`.
1818

19+
`$replace-element` uses element-level matching: two elements match when they have identical values for `group.source`, `group.target`, and `element.code`. All targets and `noMap` state for the matched element are replaced atomically.
20+
1921
## $add-mapping Operation
2022

2123
The `$add-mapping` operation merges mappings into a ConceptMap, skipping any that already exist.
2224

2325
URL: [base]/ConceptMap/[id]/$add-mapping
2426

25-
The server SHALL add each input mapping that does not already exist. Existing mappings (same match key) are skipped; the server SHOULD report skipped entries in the OperationOutcome. If no `group` exists for the given `source` and `target`, one is created.
27+
The server SHALL add each input mapping that does not already exist. If an input mapping already exists (same match key), the server ignores it by default (`if-exists=ignore`) and SHOULD report skipped entries in the OperationOutcome; set `if-exists=fail` to return an error instead. If no `group` exists for the given `source` and `target`, one is created.
2628

2729
It is an error to add a mapping with `target` for a source code that already has `noMap=true`, or to add `noMap=true` for a code that already has target mappings.
2830
It is also an error if the ConceptMap contains more than one group with the same `source` and `target` as an input mapping, since the target group is ambiguous.
@@ -35,6 +37,7 @@ Clients MAY supply an `If-Match` header; servers SHALL reject the request if the
3537
| Name | Cardinality | Type | Documentation |
3638
|------|-------------|------|---------------|
3739
| mappings | 1..1 | ConceptMap | Only `group` elements are processed |
40+
| if-exists | 0..1 | code | Behaviour when an input mapping already exists: `ignore` (default) — skip with SHOULD-report; `fail` — return an error |
3841

3942
**Out Parameters**
4043

@@ -100,6 +103,46 @@ Content-Type: application/fhir+json
100103
}
101104
```
102105

106+
Request: add GLUC → LOINC, failing if it already exists (`if-exists=fail` passed as query parameter).
107+
108+
```http
109+
POST /ConceptMap/lab-codes-to-loinc/$add-mapping?if-exists=fail HTTP/1.1
110+
Content-Type: application/fhir+json
111+
112+
{
113+
"resourceType": "ConceptMap",
114+
"group": [{
115+
"source": "http://example.org/local-codes",
116+
"target": "http://loinc.org",
117+
"element": [{
118+
"code": "GLUC",
119+
"display": "Glucose",
120+
"target": [{
121+
"code": "2345-7",
122+
"display": "Glucose [Mass/volume] in Serum or Plasma",
123+
"relationship": "equivalent"
124+
}]
125+
}]
126+
}]
127+
}
128+
```
129+
130+
Error response: mapping already exists.
131+
132+
```http
133+
HTTP/1.1 422 Unprocessable Entity
134+
Content-Type: application/fhir+json
135+
136+
{
137+
"resourceType": "OperationOutcome",
138+
"issue": [{
139+
"severity": "error",
140+
"code": "duplicate",
141+
"diagnostics": "Mapping already exists for code 'GLUC' → '2345-7' in group (source=http://example.org/local-codes, target=http://loinc.org)"
142+
}]
143+
}
144+
```
145+
103146
### Formal Definition
104147

105148
```json
@@ -127,6 +170,14 @@ Content-Type: application/fhir+json
127170
"documentation": "ConceptMap containing mappings to add. Only group elements are processed.",
128171
"type": "ConceptMap"
129172
},
173+
{
174+
"name": "if-exists",
175+
"use": "in",
176+
"min": 0,
177+
"max": "1",
178+
"documentation": "Behaviour when an input mapping already exists: 'ignore' (default) — skip with SHOULD-report; 'fail' — return an error.",
179+
"type": "code"
180+
},
130181
{
131182
"name": "return",
132183
"use": "out",
@@ -149,7 +200,7 @@ The server SHALL replace each matching mapping with the input values; properties
149200
The server SHOULD report the number of mappings updated and added in the OperationOutcome.
150201

151202
Like `$add-mapping`, it is an error to add a mapping with `target` for a source code that already has `noMap=true`, or to add `noMap=true` for a code that already has target mappings.
152-
It is also an error if the ConceptMap contains more than one group with the same `source` and `target` as an input mapping, since the target group is ambiguous.
203+
It is also an error if the ConceptMap contains more than one group with the same `source` and `target` as an input mapping, since the target group is ambiguous.
153204
In either case the server SHALL return an OperationOutcome with `severity=error` and `code=business-rule`.
154205

155206
Clients MAY supply an `If-Match` header; servers SHALL reject the request if the ETag does not match. See [Managing Resource Contention](https://hl7.org/fhir/http.html#concurrency).
@@ -264,7 +315,7 @@ The `$remove-mapping` operation removes mappings from a ConceptMap.
264315

265316
URL: [base]/ConceptMap/[id]/$remove-mapping
266317

267-
The server SHALL remove all mappings that match the input entries, across all groups in the ConceptMap. If no matching mapping exists for an input entry, the server SHALL ignore it.
318+
The server SHALL remove all mappings that match the input entries. If no matching mapping exists for an input entry, the server SHALL ignore it. If an input entry matches entries across more than one group, the server SHALL return an error by default (`on-multiple-match=fail`); set `on-multiple-match=remove-all` to remove from all matching groups.
268319

269320
Clients MAY supply an `If-Match` header; servers SHALL reject the request if the ETag does not match. See [Managing Resource Contention](https://hl7.org/fhir/http.html#concurrency).
270321

@@ -273,6 +324,7 @@ Clients MAY supply an `If-Match` header; servers SHALL reject the request if the
273324
| Name | Cardinality | Type | Documentation |
274325
|------|-------------|------|---------------|
275326
| mappings | 1..1 | ConceptMap | Only `group` elements are processed |
327+
| on-multiple-match | 0..1 | code | Behaviour when an input entry matches entries across more than one group: `fail` (default) — return an error; `remove-all` — remove from all matching groups |
276328

277329
**Out Parameters**
278330

@@ -319,6 +371,43 @@ Content-Type: application/fhir+json
319371
}
320372
```
321373

374+
Request: remove the GLUC → 2345-7 mapping from all groups when duplicate groups exist.
375+
376+
```http
377+
POST /ConceptMap/lab-codes-to-loinc/$remove-mapping?on-multiple-match=remove-all HTTP/1.1
378+
Content-Type: application/fhir+json
379+
380+
{
381+
"resourceType": "ConceptMap",
382+
"group": [{
383+
"source": "http://example.org/local-codes",
384+
"target": "http://loinc.org",
385+
"element": [{
386+
"code": "GLUC",
387+
"target": [{
388+
"code": "2345-7"
389+
}]
390+
}]
391+
}]
392+
}
393+
```
394+
395+
Response: mapping removed from all matching groups.
396+
397+
```http
398+
HTTP/1.1 200 OK
399+
Content-Type: application/fhir+json
400+
401+
{
402+
"resourceType": "OperationOutcome",
403+
"issue": [{
404+
"severity": "information",
405+
"code": "informational",
406+
"diagnostics": "2 mappings removed"
407+
}]
408+
}
409+
```
410+
322411
### Formal Definition
323412

324413
```json
@@ -346,6 +435,116 @@ Content-Type: application/fhir+json
346435
"documentation": "ConceptMap containing mappings to remove. Only group elements are processed.",
347436
"type": "ConceptMap"
348437
},
438+
{
439+
"name": "on-multiple-match",
440+
"use": "in",
441+
"min": 0,
442+
"max": "1",
443+
"documentation": "Behaviour when an input entry matches entries across more than one group: 'fail' (default) — return an error; 'remove-all' — remove from all matching groups.",
444+
"type": "code"
445+
},
446+
{
447+
"name": "return",
448+
"use": "out",
449+
"min": 1,
450+
"max": "1",
451+
"documentation": "Outcome of the operation",
452+
"type": "OperationOutcome"
453+
}
454+
]
455+
}
456+
```
457+
458+
## $replace-element Operation
459+
460+
The `$replace-element` operation atomically replaces entire elements (all targets and `noMap` state) in a ConceptMap.
461+
462+
URL: [base]/ConceptMap/[id]/$replace-element
463+
464+
The server SHALL match each input element by `(group.source, group.target, element.code)` and replace the entire element with the input values. If no matching element exists, the server SHALL add it. If no `group` exists for the given `source` and `target`, one is created. The server SHOULD report the number of elements replaced and added in the OperationOutcome.
465+
466+
Unlike `$add-mapping` and `$update-mapping`, no `noMap` conflict check is performed — the input element replaces whatever was previously there, enabling atomic transitions between mapped and `noMap` states.
467+
468+
It is an error if the ConceptMap contains more than one group with the same `source` and `target` as an input element, since the target group is ambiguous. The server SHALL return an OperationOutcome with `severity=error` and `code=business-rule`.
469+
470+
Clients MAY supply an `If-Match` header; servers SHALL reject the request if the ETag does not match. See [Managing Resource Contention](https://hl7.org/fhir/http.html#concurrency).
471+
472+
**In Parameters**
473+
474+
| Name | Cardinality | Type | Documentation |
475+
|------|-------------|------|---------------|
476+
| elements | 1..1 | ConceptMap | Only `group` elements are processed |
477+
478+
**Out Parameters**
479+
480+
| Name | Cardinality | Type | Documentation |
481+
|------|-------------|------|---------------|
482+
| return | 1..1 | OperationOutcome | Outcome of the operation |
483+
484+
### Example
485+
486+
Request: atomically transition GLUC from a target mapping to `noMap`.
487+
488+
```http
489+
POST /ConceptMap/lab-codes-to-loinc/$replace-element HTTP/1.1
490+
Content-Type: application/fhir+json
491+
492+
{
493+
"resourceType": "ConceptMap",
494+
"group": [{
495+
"source": "http://example.org/local-codes",
496+
"target": "http://loinc.org",
497+
"element": [{
498+
"code": "GLUC",
499+
"noMap": true
500+
}]
501+
}]
502+
}
503+
```
504+
505+
Response: element replaced.
506+
507+
```http
508+
HTTP/1.1 200 OK
509+
Content-Type: application/fhir+json
510+
511+
{
512+
"resourceType": "OperationOutcome",
513+
"issue": [{
514+
"severity": "information",
515+
"code": "informational",
516+
"diagnostics": "1 element replaced"
517+
}]
518+
}
519+
```
520+
521+
### Formal Definition
522+
523+
```json
524+
{
525+
"resourceType": "OperationDefinition",
526+
"id": "ConceptMap-replace-element",
527+
"url": "http://hl7.org/fhir/OperationDefinition/ConceptMap-replace-element",
528+
"version": "6.0.0",
529+
"name": "ReplaceElement",
530+
"title": "Replace elements in a ConceptMap",
531+
"status": "draft",
532+
"kind": "operation",
533+
"affectsState": true,
534+
"code": "replace-element",
535+
"resource": ["ConceptMap"],
536+
"system": false,
537+
"type": false,
538+
"instance": true,
539+
"parameter": [
540+
{
541+
"name": "elements",
542+
"use": "in",
543+
"min": 1,
544+
"max": "1",
545+
"documentation": "ConceptMap containing elements to replace. Only group elements are processed.",
546+
"type": "ConceptMap"
547+
},
349548
{
350549
"name": "return",
351550
"use": "out",
@@ -360,4 +559,4 @@ Content-Type: application/fhir+json
360559

361560
## Notes
362561

363-
Multiple groups with the same `source` and `target` within a single ConceptMap are permitted but discouraged. When different mapping subsets require different `unmapped` handling, they SHOULD be modeled as separate ConceptMap resources — subsets are a concept map-level concern.
562+
Multiple groups with the same `source` and `target` within a single ConceptMap are permitted but discouraged. When different mapping subsets require different `unmapped` handling, they SHOULD be modeled as separate ConceptMap resources — subsets are a concept map-level concern.

0 commit comments

Comments
 (0)