Skip to content

Commit 07a9235

Browse files
authored
Merge pull request #2708 from opensafely-core/Jongmassey/amp-desc-to-synonym
Use AMP description field as the primary name, and use the name field as the synonym - using the existing synonym mechanisms developed for SNOMED CT codelists.
2 parents fdb463d + 4a9a2fd commit 07a9235

2 files changed

Lines changed: 34 additions & 6 deletions

File tree

coding_systems/dmd/coding_system.py

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
from django.db.models import Q
1+
import collections
2+
3+
from django.db.models import F, Q
4+
from django.db.models.functions import Coalesce
25

36
from ..base.coding_system_base import BuilderCompatibleCodingSystem
47
from .models import AMP, AMPP, VMP, VMPP, VTM, Ing
@@ -47,21 +50,38 @@ def lookup_names(self, codes):
4750
# these models first
4851
# If not found, look up VTM, VMPP, AMPPs also, in case of user-uploaded codelists that
4952
# might contain these
53+
#
54+
# If the model type is AMP, we should prefer the `descr` field over the `nm` for the name
55+
# as this contains the supplier name which helps distinguish AMPs apart.
56+
# It appears to be populated in 100% of cases but coalese with `nm` just in case it is not.
5057
codes = set(codes)
5158
lookup = {}
5259
for model_cls in [AMP, VMP, AMPP, VMPP, VTM]:
53-
matched = dict(
54-
model_cls.objects.using(self.database_alias)
55-
.filter(id__in=codes)
56-
.values_list("id", "nm")
60+
model_objs = model_cls.objects.using(self.database_alias).filter(
61+
id__in=codes
5762
)
63+
name_field = Coalesce("descr", "nm") if model_cls == AMP else F("nm")
64+
model_objs = model_objs.annotate(name=name_field)
65+
matched = dict(model_objs.values_list("id", "name"))
5866
for code, name in matched.items():
5967
lookup[code] = f"{name} ({model_cls.__name__})"
6068
codes = codes - set(matched.keys())
6169
if not codes:
6270
break
6371
return lookup
6472

73+
def lookup_synonyms(self, codes):
74+
descriptions = (
75+
AMP.objects.using(self.database_alias)
76+
.filter(id__in=codes)
77+
.values("id", "nm")
78+
)
79+
80+
result = collections.defaultdict(list)
81+
for d in descriptions:
82+
result[d["id"]].append(d["nm"])
83+
return dict(result)
84+
6585
def code_to_term(self, codes):
6686
lookup = self.lookup_names(codes)
6787
unknown = set(codes) - set(lookup)

coding_systems/dmd/tests/test_coding_system.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ def coding_system():
1010

1111
def test_lookup_names(dmd_data, coding_system):
1212
assert coding_system.lookup_names(
13-
["10514511000001106", "10525011000001107", "99999"]
13+
["10514511000001106", "10525011000001107", "99999", "22503111000001109"]
1414
) == {
1515
"10514511000001106": "Adrenaline (base) 220micrograms/dose inhaler (VMP)",
1616
"10525011000001107": "Adrenaline (base) 220micrograms/dose inhaler refill (VMP)",
17+
"22503111000001109": "AirSalb 100micrograms/dose inhaler CFC free (Sandoz Ltd) (AMP)",
1718
}
1819

1920

@@ -215,3 +216,10 @@ def test_search_by_term_specific_fields(
215216
)
216217
def test_search_by_code(dmd_data, coding_system, code, expected_response):
217218
assert coding_system.search_by_code(code) == expected_response
219+
220+
221+
def test_lookup_synonyms(dmd_data, coding_system):
222+
assert coding_system.lookup_synonyms(["3293111000001105", "22503111000001109"]) == {
223+
"3293111000001105": ["Aerolin 100micrograms/dose Autohaler"],
224+
"22503111000001109": ["AirSalb 100micrograms/dose inhaler CFC free"],
225+
}

0 commit comments

Comments
 (0)