Skip to content

Commit 7e27854

Browse files
author
alex-omophub
committed
Update CHANGELOG for version 1.8.0 and add new FHIR resolution examples
- Updated CHANGELOG to reflect the release of version 1.8.0. - Added new functions in `fhir_resolver.py` for resolving administrative gender, user-selected codes, and unmapped sentinel handling, enhancing FHIR resolution capabilities.
1 parent a1996f1 commit 7e27854

2 files changed

Lines changed: 101 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [Unreleased]
8+
## [1.8.0] - 2026-05-25
99

1010
### Added
1111

examples/fhir_resolver.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,103 @@ def error_handling_examples() -> None:
489489
client.close()
490490

491491

492+
# ---------------------------------------------------------------------------
493+
# 13. Administrative code via the HL7 FHIR-to-OMOP IG ConceptMap layer
494+
# ---------------------------------------------------------------------------
495+
496+
497+
def resolve_administrative_gender() -> None:
498+
"""Resolve a FHIR administrative code (gender) via the IG ConceptMap layer.
499+
500+
Administrative/structural systems (administrative-gender, v3-ActCode
501+
encounter class, condition-clinical, ...) have no OMOP vocabulary-table
502+
representation and resolve through the IG's ConceptMaps.
503+
"""
504+
print("\n=== 13. Administrative gender (IG ConceptMap) ===")
505+
506+
client = omophub.OMOPHub()
507+
try:
508+
result = client.fhir.resolve(
509+
system="http://hl7.org/fhir/administrative-gender",
510+
code="male",
511+
resource_type="Patient",
512+
)
513+
res = result["resolution"]
514+
std = res["standard_concept"]
515+
print(f" male → {std['concept_name']} ({std['concept_id']})")
516+
print(f" target_table: {res['target_table']}")
517+
print(f" via IG ConceptMap: {res.get('concept_map_id')}")
518+
# Composite source concepts also surface a `value_as_concept`
519+
# (the IG 'Maps to value' / Value-as-Concept pattern) when present.
520+
if res.get("value_as_concept"):
521+
val = res["value_as_concept"]
522+
print(
523+
f" value_as_concept: {val['concept_name']}"
524+
f" → {res.get('value_target_field')}"
525+
)
526+
finally:
527+
client.close()
528+
529+
530+
# ---------------------------------------------------------------------------
531+
# 14. CodeableConcept with user_selected (overrides vocabulary preference)
532+
# ---------------------------------------------------------------------------
533+
534+
535+
def resolve_user_selected() -> None:
536+
"""A coding marked user_selected wins best_match over vocabulary preference."""
537+
print("\n=== 14. CodeableConcept with user_selected ===")
538+
539+
client = omophub.OMOPHub()
540+
try:
541+
result = client.fhir.resolve_codeable_concept(
542+
coding=[
543+
# SNOMED would normally win on OHDSI preference, but the
544+
# user-selected ICD-10-CM coding takes precedence.
545+
{"system": "http://snomed.info/sct", "code": "44054006"},
546+
{
547+
"system": "http://hl7.org/fhir/sid/icd-10-cm",
548+
"code": "E11.9",
549+
"user_selected": True,
550+
},
551+
],
552+
resource_type="Condition",
553+
)
554+
best = result["best_match"]
555+
if best:
556+
src = best["resolution"]["source_concept"]
557+
print(f" best_match source vocabulary: {src['vocabulary_id']}")
558+
finally:
559+
client.close()
560+
561+
562+
# ---------------------------------------------------------------------------
563+
# 15. on_unmapped="sentinel" — a concept_id 0 record instead of a 404
564+
# ---------------------------------------------------------------------------
565+
566+
567+
def resolve_unmapped_sentinel() -> None:
568+
"""With on_unmapped='sentinel', an unresolvable code yields a row, not a 404.
569+
570+
Handy for ETL pipelines that need one output row per input. Works on
571+
resolve(), resolve_batch(), and resolve_codeable_concept().
572+
"""
573+
print("\n=== 15. on_unmapped='sentinel' ===")
574+
575+
client = omophub.OMOPHub()
576+
try:
577+
result = client.fhir.resolve(
578+
system="http://snomed.info/sct",
579+
code="00000000",
580+
on_unmapped="sentinel",
581+
)
582+
res = result["resolution"]
583+
print(f" mapping_type: {res['mapping_type']}")
584+
print(f" standard concept_id: {res['standard_concept']['concept_id']}")
585+
finally:
586+
client.close()
587+
588+
492589
# ---------------------------------------------------------------------------
493590
# Main
494591
# ---------------------------------------------------------------------------
@@ -505,5 +602,8 @@ def error_handling_examples() -> None:
505602
resolve_batch()
506603
resolve_codeable_concept()
507604
resolve_codeable_concept_text_fallback()
605+
resolve_administrative_gender()
606+
resolve_user_selected()
607+
resolve_unmapped_sentinel()
508608
asyncio.run(async_resolve())
509609
error_handling_examples()

0 commit comments

Comments
 (0)