Skip to content

Commit

Permalink
OpenConceptLab/ocl_issues#1343 | added translation in collection refe…
Browse files Browse the repository at this point in the history
…rences
  • Loading branch information
snyaggarwal committed Sep 2, 2022
1 parent c4a0bec commit bb9802c
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 5 deletions.
5 changes: 5 additions & 0 deletions core/collections/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
REFERENCE_TYPE_CHOICES, CONCEPT_REFERENCE_TYPE, MAPPING_REFERENCE_TYPE, SOURCE_MAPPINGS, SOURCE_TO_CONCEPTS,
TRANSFORM_TO_RESOURCE_VERSIONS, COLLECTION_REFERENCE_TYPE)
from core.collections.parsers import CollectionReferenceParser
from core.collections.translators import CollectionReferenceTranslator
from core.collections.utils import is_concept, is_mapping
from core.common.constants import (
DEFAULT_REPOSITORY_TYPE, ACCESS_TYPE_VIEW, ACCESS_TYPE_EDIT,
Expand Down Expand Up @@ -725,6 +726,10 @@ def link_resources(self):
if not is_concept_expression and not self.mappings.exists():
self.mappings.add(*expansion.mappings.filter(uri=self.expression))

@property
def translation(self):
return CollectionReferenceTranslator(self).translate()


def default_expansion_parameters():
return {
Expand Down
2 changes: 1 addition & 1 deletion core/collections/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ class Meta:
fields = (
*CollectionReferenceSerializer.Meta.fields,
'code', 'resource_version', 'namespace', 'system', 'version', 'valueset', 'cascade', 'filter', 'display',
'created_at', 'updated_at', 'concepts', 'mappings'
'created_at', 'updated_at', 'concepts', 'mappings', 'translation'
)


Expand Down
82 changes: 79 additions & 3 deletions core/collections/tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -2290,7 +2290,7 @@ def get_expanded_references(**kwargs):
parser.to_reference_structure()
return parser.to_objects()

def test_parse_string_expression_generic(self):
def test_parse_string_expression_generic(self): # pylint: disable=too-many-statements
references = self.get_expanded_references(
expression=dict(expressions=[
"/orgs/MyOrg/sources/MySource/concepts/c-1234/",
Expand All @@ -2311,6 +2311,7 @@ def test_parse_string_expression_generic(self):
self.assertIsNone(reference.valueset)
self.assertIsNone(reference.filter)
self.assertIsNone(reference.cascade)
self.assertEqual(reference.translation, 'Include latest concept "c-1234" from MyOrg/MySource')

reference = references[1]
self.assertEqual(reference.expression, "/orgs/MyOrg/sources/MySource/mappings/m-1234/")
Expand All @@ -2321,6 +2322,7 @@ def test_parse_string_expression_generic(self):
self.assertIsNone(reference.valueset)
self.assertIsNone(reference.filter)
self.assertIsNone(reference.cascade)
self.assertEqual(reference.translation, 'Include latest mapping "m-1234" from MyOrg/MySource')

reference = references[2]
self.assertEqual(reference.expression, "/users/Me/sources/MySource/concepts/?q=foobar")
Expand All @@ -2331,6 +2333,7 @@ def test_parse_string_expression_generic(self):
self.assertIsNone(reference.valueset)
self.assertIsNone(reference.cascade)
self.assertIsNone(reference.code)
self.assertEqual(reference.translation, 'Include latest concepts from Me/MySource containing "foobar"')

reference = references[3]
self.assertEqual(reference.expression, "/users/Me/sources/MySource/v1/concepts/?q=foobar&datatype=rule")
Expand All @@ -2343,6 +2346,10 @@ def test_parse_string_expression_generic(self):
self.assertIsNone(reference.valueset)
self.assertIsNone(reference.cascade)
self.assertIsNone(reference.code)
self.assertEqual(
reference.translation,
'Include concepts from version "v1" of Me/MySource containing "foobar" & having datatype equal to "rule"'
)

reference = references[4]
self.assertEqual(reference.expression, "/users/Me/collections/MyColl/v1/mappings/?mapType=Q-AND-A")
Expand All @@ -2355,6 +2362,10 @@ def test_parse_string_expression_generic(self):
self.assertIsNone(reference.system)
self.assertIsNone(reference.cascade)
self.assertIsNone(reference.code)
self.assertEqual(
reference.translation,
'Include mappings from version "v1" of Me/MyColl having mapType equal to "Q-AND-A"'
)

def test_parse_string_expression_concepts_mappings_explicit(self): # pylint: disable=too-many-statements
references = self.get_expanded_references(
Expand All @@ -2379,6 +2390,7 @@ def test_parse_string_expression_concepts_mappings_explicit(self): # pylint: di
self.assertIsNone(reference.valueset)
self.assertIsNone(reference.filter)
self.assertIsNone(reference.cascade)
self.assertEqual(reference.translation, 'Include latest concept "c-1234" from MyOrg/MySource')

reference = references[1]
self.assertTrue(isinstance(reference, CollectionReference))
Expand All @@ -2390,6 +2402,7 @@ def test_parse_string_expression_concepts_mappings_explicit(self): # pylint: di
self.assertIsNone(reference.valueset)
self.assertIsNone(reference.cascade)
self.assertIsNone(reference.code)
self.assertEqual(reference.translation, 'Include latest concepts from Me/MySource containing "foobar"')

reference = references[2]
self.assertTrue(isinstance(reference, CollectionReference))
Expand All @@ -2403,6 +2416,10 @@ def test_parse_string_expression_concepts_mappings_explicit(self): # pylint: di
self.assertIsNone(reference.valueset)
self.assertIsNone(reference.cascade)
self.assertIsNone(reference.code)
self.assertEqual(
reference.translation,
'Include concepts from version "v1" of Me/MySource containing "foobar" & having datatype equal to "rule"'
)

reference = references[3]
self.assertTrue(isinstance(reference, CollectionReference))
Expand All @@ -2414,6 +2431,7 @@ def test_parse_string_expression_concepts_mappings_explicit(self): # pylint: di
self.assertIsNone(reference.valueset)
self.assertIsNone(reference.filter)
self.assertIsNone(reference.cascade)
self.assertEqual(reference.translation, 'Include latest mapping "m-1234" from MyOrg/MySource')

reference = references[4]
self.assertTrue(isinstance(reference, CollectionReference))
Expand All @@ -2427,6 +2445,10 @@ def test_parse_string_expression_concepts_mappings_explicit(self): # pylint: di
self.assertIsNone(reference.system)
self.assertIsNone(reference.cascade)
self.assertIsNone(reference.code)
self.assertEqual(
reference.translation,
'Include mappings from version "v1" of Me/MyColl having mapType equal to "Q-AND-A"'
)

def test_parse_source_all_resources_expression(self):
references = self.get_expanded_references(
Expand All @@ -2444,6 +2466,7 @@ def test_parse_source_all_resources_expression(self):
self.assertIsNone(reference.valueset)
self.assertIsNone(reference.filter)
self.assertIsNone(reference.cascade)
self.assertEqual(reference.translation, 'Include latest concepts from MyOrg/MySource')

reference = references[1]
self.assertTrue(isinstance(reference, CollectionReference))
Expand All @@ -2455,6 +2478,7 @@ def test_parse_source_all_resources_expression(self):
self.assertIsNone(reference.valueset)
self.assertIsNone(reference.filter)
self.assertIsNone(reference.cascade)
self.assertEqual(reference.translation, 'Include latest mappings from MyOrg/MySource')

def test_parse_new_style(self): # pylint: disable=too-many-statements
references = self.get_expanded_references(
Expand All @@ -2476,6 +2500,10 @@ def test_parse_new_style(self): # pylint: disable=too-many-statements
self.assertIsNone(references[0].version)
self.assertEqual(
references[0].build_expression(), "http://hl7.org/fhir/CodeSystem/my-codeystem/concepts/1948/")
self.assertEqual(
references[0].translation,
'Include latest concept "1948" from http://hl7.org/fhir/CodeSystem/my-codeystem'
)

references = self.get_expanded_references(
expression={
Expand Down Expand Up @@ -2519,6 +2547,10 @@ def test_parse_new_style(self): # pylint: disable=too-many-statements
references[0].build_expression(),
"http://hl7.org/fhir/CodeSystem/my-codeystem|0.8/concepts/?datatype=Numeric"
)
self.assertEqual(
references[0].translation,
'Include concepts from version "0.8" of http://hl7.org/fhir/CodeSystem/my-codeystem intersection with http://hl7.org/fhir/ValueSet/my-valueset1 intersection with http://hl7.org/fhir/ValueSet/my-valueset2 having datatype equal to "Numeric"' # pylint: disable=line-too-long
)

references = self.get_expanded_references(
expression={
Expand Down Expand Up @@ -2551,6 +2583,10 @@ def test_parse_new_style(self): # pylint: disable=too-many-statements
references[0].build_expression(),
"http://hl7.org/fhir/CodeSystem/my-codeystem/concepts/?datatype=Numeric"
)
self.assertEqual(
references[0].translation,
'Include latest concepts from http://hl7.org/fhir/CodeSystem/my-codeystem having datatype equal to "Numeric"' # pylint: disable=line-too-long
)

references = self.get_expanded_references(
expression={
Expand Down Expand Up @@ -2583,6 +2619,10 @@ def test_parse_new_style(self): # pylint: disable=too-many-statements
references[0].build_expression(),
"http://hl7.org/fhir/ValueSet/my-valueset1/concepts/?datatype=Numeric"
)
self.assertEqual(
references[0].translation,
'Include latest concepts from http://hl7.org/fhir/ValueSet/my-valueset1 having datatype equal to "Numeric"'
)

references = self.get_expanded_references(
expression={
Expand All @@ -2602,25 +2642,41 @@ def test_parse_new_style(self): # pylint: disable=too-many-statements
self.assertEqual(reference.display, "abcd")
self.assertEqual(reference.reference_type, "concepts")
self.assertIsNone(reference.version)
self.assertEqual(
reference.translation,
'Include latest concept "1948" from http://hl7.org/fhir/CodeSystem/my-codeystem'
)

reference = references[1]
self.assertEqual(reference.system, "http://hl7.org/fhir/CodeSystem/my-codeystem")
self.assertEqual(reference.code, "1234")
self.assertEqual(reference.reference_type, "concepts")
self.assertIsNone(reference.display)
self.assertIsNone(reference.version)
self.assertEqual(
reference.translation,
'Include latest concept "1234" from http://hl7.org/fhir/CodeSystem/my-codeystem'
)

reference = references[2]
self.assertEqual(reference.system, "http://hl7.org/fhir/CodeSystem/my-codeystem")
self.assertEqual(reference.code, "93")
self.assertEqual(reference.reference_type, "mappings")
self.assertIsNone(reference.version)
self.assertEqual(
reference.translation,
'Include latest mapping "93" from http://hl7.org/fhir/CodeSystem/my-codeystem'
)

reference = references[3]
self.assertEqual(reference.system, "http://hl7.org/fhir/CodeSystem/my-codeystem")
self.assertEqual(reference.code, "urjdk")
self.assertEqual(reference.reference_type, "mappings")
self.assertIsNone(reference.version)
self.assertEqual(
reference.translation,
'Include latest mapping "urjdk" from http://hl7.org/fhir/CodeSystem/my-codeystem'
)

references = self.get_expanded_references(expression={
"valueSet": "http://hl7.org/fhir/ValueSet/my-valueset1",
Expand All @@ -2634,6 +2690,10 @@ def test_parse_new_style(self): # pylint: disable=too-many-statements
self.assertEqual(references[0].reference_type, "concepts")
self.assertEqual(references[0].code, "1948")
self.assertEqual(references[0].build_expression(), "http://hl7.org/fhir/ValueSet/my-valueset1/concepts/1948/")
self.assertEqual(
references[0].translation,
'Include latest concept "1948" from http://hl7.org/fhir/ValueSet/my-valueset1'
)

references = self.get_expanded_references(
expression={
Expand All @@ -2650,19 +2710,27 @@ def test_parse_new_style(self): # pylint: disable=too-many-statements
self.assertEqual(reference.reference_type, "concepts")
self.assertIsNone(reference.version)
self.assertIsNone(reference.display)
self.assertEqual(
references[0].translation,
'Include latest concept "1948" from http://hl7.org/fhir/CodeSystem/my-codeystem'
)

reference = references[1]
self.assertEqual(reference.system, "http://hl7.org/fhir/CodeSystem/my-codeystem")
self.assertEqual(reference.code, "93")
self.assertEqual(reference.reference_type, "mappings")
self.assertIsNone(reference.version)
self.assertEqual(
references[1].translation,
'Include latest mapping "93" from http://hl7.org/fhir/CodeSystem/my-codeystem'
)

references = self.get_expanded_references(
expression=[{
"system": "http://hl7.org/fhir/CodeSystem/my-codeystem",
"concept": "1948",
}, {
"system": "http://hl7.org/fhir/CodeSystem/my-codeystem",
"system": "http://hl7.org/fhir/CodeSystem/my-codeystem2",
"mapping": "93"
}]
)
Expand All @@ -2674,12 +2742,20 @@ def test_parse_new_style(self): # pylint: disable=too-many-statements
self.assertEqual(reference.reference_type, "concepts")
self.assertIsNone(reference.version)
self.assertIsNone(reference.display)
self.assertEqual(
reference.translation,
'Include latest concept "1948" from http://hl7.org/fhir/CodeSystem/my-codeystem'
)

reference = references[1]
self.assertEqual(reference.system, "http://hl7.org/fhir/CodeSystem/my-codeystem")
self.assertEqual(reference.system, "http://hl7.org/fhir/CodeSystem/my-codeystem2")
self.assertEqual(reference.code, "93")
self.assertEqual(reference.reference_type, "mappings")
self.assertIsNone(reference.version)
self.assertEqual(
reference.translation,
'Include latest mapping "93" from http://hl7.org/fhir/CodeSystem/my-codeystem2'
)


class ExpansionConceptsIndexViewTest(OCLAPITestCase):
Expand Down
99 changes: 99 additions & 0 deletions core/collections/translators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
from pydash import get

from core.collections.constants import SOURCE_TO_CONCEPTS, SOURCE_MAPPINGS


class CollectionReferenceTranslator:
def __init__(self, reference):
self.reference = reference

@staticmethod
def __format_system_value(value):
if value.startswith('http'):
return value
return value.replace(
'/users/', '').replace('/orgs/', '').replace('/sources/', '/').replace('/collections/', '/').strip("/")

def __has_any_repo_version(self):
return bool(
self.reference.version or (
isinstance(self.reference.valueset, list) and any(
bool(get(valueset.split('|'), '1')) for valueset in self.reference.valueset)
)
)

@property
def ref_entity(self):
return 'concept' if self.reference.is_concept else 'mapping'

@property
def reference_effect(self):
return 'Include' if self.reference.include else 'Exclude'

def __get_cascade_translation(self):
english = ''
cascade = None
if self.reference.cascade:
if isinstance(self.reference.cascade, str):
cascade = self.reference.cascade
elif isinstance(self.reference.cascade, dict):
cascade = self.reference.cascade.get('method')
if cascade:
cascade = cascade.lower()
if cascade == SOURCE_TO_CONCEPTS:
english += 'PLUS its mappings and their target concepts '
if cascade == SOURCE_MAPPINGS:
english += 'PLUS its mappings '
return english

def translate(self): # pylint: disable=too-many-branches
english = f'{self.reference_effect} '
if not self.__has_any_repo_version() and not self.reference.resource_version:
english += 'latest '
entity = self.ref_entity
if self.reference.code:
if self.reference.resource_version:
english += f'version "{self.reference.resource_version}" of '
elif self.reference.transform:
english += 'latest version of '
english += f'{entity} "{self.reference.code}" from '
else:
english += f'{entity}s from '
if self.reference.system:
if self.reference.version:
english += f'version "{self.reference.version}" of '
english += f'{self.__format_system_value(self.reference.system)} '
if self.reference.valueset and isinstance(self.reference.valueset, list):
if self.reference.system:
english += 'intersection with '
__count = 0
for valueset in self.reference.valueset:
if __count > 0:
english += 'intersection with '
parts = valueset.split('|')
collection = self.__format_system_value(parts[0])
coll_version = get(parts, '1') or None
if coll_version:
english += f'version "{coll_version}" of '
english += f'{collection} '
__count += 1
if self.reference.filter:
__count = 0
for filter_def in self.reference.filter:
if filter_def['property'] == 'q' and filter_def['value']:
if __count > 0:
english += '& '
english += f'containing "{filter_def["value"]}" '
__count += 1
elif filter_def['property'] == 'exact_match' and filter_def['value']:
if __count > 0:
english += '& '
english += f'matching exactly with "{filter_def["value"]}" '
__count += 1
elif filter_def['value']:
if __count > 0:
english += '& '
english += f'having {filter_def["property"]} equal to "{filter_def["value"]}" '
__count += 1
english += self.__get_cascade_translation()
return english.strip()

0 comments on commit bb9802c

Please sign in to comment.