Skip to content

Commit 5627934

Browse files
committed
OpenConceptLab/ocl_issues#2268 | Reference evaluation to defer resource_version | transform to use repo version
1 parent 6f40328 commit 5627934

3 files changed

Lines changed: 115 additions & 68 deletions

File tree

‎core/collections/models.py‎

Lines changed: 101 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -667,57 +667,68 @@ def fetch_mappings(self, refetch=False):
667667
self._mappings = self.get_mappings()
668668
self._fetched = True
669669

670-
def get_concepts(self, system_version=None): # pylint: disable=too-many-branches
670+
def get_concepts(self, system_version=None):
671671
system_version = system_version or self.resolve_system_version
672-
queryset = self.get_resource_queryset_from_system_and_valueset('concepts', system_version)
672+
concept_queryset = self.get_resource_queryset_from_system_and_valueset('concepts', system_version)
673673
valueset_versions = self.resolve_valueset_versions
674674
mapping_queryset = Mapping.objects.none()
675-
if queryset is None:
675+
676+
if concept_queryset is None:
676677
return Concept.objects.none(), mapping_queryset
677678

678679
if self.code:
679-
queryset = queryset.filter(mnemonic=decode_string(self.code))
680+
concept_queryset = concept_queryset.filter(mnemonic=decode_string(self.code))
680681
if self.resource_version:
681-
queryset = queryset.filter(version=self.resource_version)
682-
elif queryset.count() > 1:
683-
queryset = Concept.objects.filter(id=queryset.order_by('-id').first().id)
682+
concept_queryset = concept_queryset.filter(version=self.resource_version)
683+
elif concept_queryset.count() > 1:
684+
concept_queryset = Concept.objects.filter(id=concept_queryset.order_by('-id').first().id)
684685

685686
if self.should_apply_filter():
686-
queryset = self.apply_filters(queryset, Concept)
687-
687+
concept_queryset = self._apply_filters(concept_queryset, Concept)
688688
if self.cascade:
689-
cascade_params = self.get_concept_cascade_params(system_version or valueset_versions[0])
690-
concept_ids = set()
691-
mapping_ids = set()
692-
traversed = []
693-
for concept in queryset:
694-
concept_uri = drop_version(concept.uri)
695-
if concept_uri in traversed:
696-
continue
697-
traversed.append(concept_uri)
698-
result = concept.cascade(**cascade_params)
699-
concept_ids.update(set(result['concepts'].values_list('id', flat=True)))
700-
mapping_ids.update(set(result['mappings'].values_list('id', flat=True)))
701-
concept_ids.update(set(queryset.values_list('id', flat=True)))
702-
mapping_ids.update(set(mapping_queryset.values_list('id', flat=True)))
703-
queryset = Concept.objects.filter(id__in=concept_ids)
704-
mapping_queryset = Mapping.objects.filter(id__in=mapping_ids)
689+
concept_queryset, mapping_queryset = self._apply_cascade(
690+
concept_queryset, mapping_queryset, system_version, valueset_versions)
691+
if self.transform:
692+
concept_queryset, mapping_queryset = self._apply_transform(
693+
concept_queryset, mapping_queryset, system_version)
694+
695+
if concept_queryset is None:
696+
concept_queryset = Concept.objects.none()
705697

698+
return concept_queryset, mapping_queryset
699+
700+
def _apply_transform(self, concept_queryset, mapping_queryset, system_version):
706701
if self.should_transform_to_latest_version():
707-
queryset = self.transform_to_latest_version(queryset, Concept)
708-
if self.code:
709-
concept = queryset.first()
710-
if concept:
711-
self.resource_version = concept.version
712-
self.expression = concept.uri
702+
concept_queryset = self._update_by_transform_to_latest_version(concept_queryset, Concept)
713703
mapping_queryset = self.transform_to_latest_version(mapping_queryset, Mapping)
714704
if self.should_transform_to_versioned() and not system_version.is_head: # For HEAD it will be versioned
715-
queryset = Concept.objects.filter(id__in=queryset.values_list('versioned_object_id', flat=True))
705+
self.version = HEAD
706+
concept_queryset = Concept.objects.filter(
707+
id__in=concept_queryset.values_list('versioned_object_id', flat=True))
716708
mapping_queryset = Mapping.objects.filter(
717709
id__in=mapping_queryset.values_list('versioned_object_id', flat=True))
718-
if queryset is None:
719-
queryset = Concept.objects.none()
720-
return queryset, mapping_queryset
710+
711+
return concept_queryset, mapping_queryset
712+
713+
def _apply_cascade(self, concept_queryset, mapping_queryset, system_version, valueset_versions):
714+
cascade_params = self.get_concept_cascade_params(system_version or valueset_versions[0])
715+
concept_ids = set()
716+
mapping_ids = set()
717+
traversed = []
718+
719+
for concept in concept_queryset:
720+
concept_uri = drop_version(concept.uri)
721+
if concept_uri in traversed:
722+
continue
723+
traversed.append(concept_uri)
724+
result = concept.cascade(**cascade_params)
725+
concept_ids.update(set(result['concepts'].values_list('id', flat=True)))
726+
mapping_ids.update(set(result['mappings'].values_list('id', flat=True)))
727+
728+
concept_ids.update(set(concept_queryset.values_list('id', flat=True)))
729+
mapping_ids.update(set(mapping_queryset.values_list('id', flat=True)))
730+
731+
return Concept.objects.filter(id__in=concept_ids), Mapping.objects.filter(id__in=mapping_ids)
721732

722733
def get_mappings(self, system_version=None):
723734
queryset = self.get_resource_queryset_from_system_and_valueset('mappings', system_version)
@@ -730,48 +741,74 @@ def get_mappings(self, system_version=None):
730741
queryset = queryset.filter(version=self.resource_version)
731742

732743
if self.should_apply_filter():
733-
queryset = self.apply_filters(queryset, Mapping)
744+
queryset = self._apply_filters(queryset, Mapping)
734745

735746
if self.should_transform_to_latest_version():
736-
queryset = self.transform_to_latest_version(queryset, Mapping)
737-
if self.code:
738-
mapping = queryset.first()
739-
self.resource_version = mapping.version
740-
self.expression = mapping.uri
747+
queryset = self._update_by_transform_to_latest_version(queryset, Mapping)
741748
if queryset is None:
742749
queryset = Mapping.objects.none()
743750
return queryset
744751

752+
def _update_by_transform_to_latest_version(self, queryset, klass):
753+
queryset = self.transform_to_latest_version(queryset, klass)
754+
if self.code:
755+
resource = queryset.first()
756+
if resource:
757+
self.version = get(resource.latest_source_version, 'version')
758+
self.resource_version = None
759+
if not self.version:
760+
self.version = HEAD
761+
self.resource_version = resource.version
762+
# self.resource_version = resource.version # old
763+
self.expression = resource.uri
764+
return queryset
765+
745766
@staticmethod
746767
def dedupe_by_expression(references):
747768
return list({reference.expression: reference for reference in references}.values())
748769

770+
def __get_repo_and_resource_version(self, resource, is_intensional, is_extensional):
771+
repo_version = self.version
772+
resource_version = None
773+
if not self.version and self.transform:
774+
repo_version = get(resource.latest_source_version, 'version') or HEAD
775+
is_head = repo_version == HEAD
776+
if is_intensional and is_head:
777+
resource_version = resource.version
778+
elif is_extensional:
779+
resource_version = None
780+
if is_intensional and repo_version == HEAD and not resource_version:
781+
resource_version = resource.version
782+
return repo_version, resource_version
783+
784+
def __generate_references_for_type(self, queryset, resource_type):
785+
references = []
786+
is_extensional = self.is_extensional_transform
787+
is_intensional = self.is_static_transform
788+
789+
for resource in queryset:
790+
repo_version, resource_version = self.__get_repo_and_resource_version(
791+
resource, is_intensional, is_extensional)
792+
793+
references.append(CollectionReference(
794+
expression=resource.uri,
795+
reference_type=resource_type,
796+
code=encode_string(resource.mnemonic) if resource_type == 'concepts' else resource.mnemonic,
797+
collection_id=self.collection_id,
798+
created_by=self.created_by,
799+
resource_version=resource_version,
800+
system=self.system,
801+
version=repo_version
802+
))
803+
return references
804+
749805
def generate_references(self):
750806
references = []
807+
751808
if self.should_generate_multiple_references():
752809
concepts, mappings = self.get_concepts()
753-
for concept in concepts:
754-
references.append(CollectionReference(
755-
expression=concept.uri,
756-
reference_type='concepts',
757-
code=encode_string(concept.mnemonic),
758-
collection_id=self.collection_id,
759-
created_by=self.created_by,
760-
resource_version=concept.version if self.transform == TRANSFORM_TO_RESOURCE_VERSIONS else None,
761-
system=self.system,
762-
version=self.version
763-
))
764-
for mapping in mappings:
765-
references.append(CollectionReference(
766-
expression=mapping.uri,
767-
reference_type='mappings',
768-
code=mapping.mnemonic,
769-
collection_id=self.collection_id,
770-
created_by=self.created_by,
771-
resource_version=mapping.version if self.transform == TRANSFORM_TO_RESOURCE_VERSIONS else None,
772-
system=self.system,
773-
version=self.version
774-
))
810+
references += self.__generate_references_for_type(concepts, 'concepts')
811+
references += self.__generate_references_for_type(mappings, 'mappings')
775812
else:
776813
references.append(self)
777814
return references
@@ -854,7 +891,7 @@ def clean_fields(_fields):
854891
)
855892
return search
856893

857-
def apply_filters(self, queryset, resource_klass):
894+
def _apply_filters(self, queryset, resource_klass):
858895
if self.filter:
859896
pks = []
860897
document = resource_klass.get_search_document()

‎core/collections/views.py‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
from core.collections.utils import is_version_specified
4040
from core.common.constants import (
4141
HEAD, RELEASED_PARAM, PROCESSING_PARAM, OK_MESSAGE,
42-
ACCESS_TYPE_NONE, INCLUDE_RETIRED_PARAM, INCLUDE_INVERSE_MAPPINGS_PARAM, ALL, LATEST)
42+
ACCESS_TYPE_NONE, INCLUDE_RETIRED_PARAM, INCLUDE_INVERSE_MAPPINGS_PARAM, ALL, LATEST, DEPRECATED_API_HEADER)
4343
from core.common.exceptions import Http409, Http405, Http400
4444
from core.common.mixins import (
4545
ConceptDictionaryCreateMixin, ListWithHeadersMixin, ConceptDictionaryUpdateMixin,
@@ -517,25 +517,31 @@ def update(self, request, *args, **kwargs): # pylint: disable=too-many-locals,u
517517

518518
added_expressions = set()
519519
added_original_expressions = set()
520+
is_deprecated = False
520521
for reference in added_references:
521522
added_expressions.add(reference.expression)
522523
if reference.cascade and reference.transform:
523524
added_expression = reference.expression or reference.original_expression
524525
else:
525526
added_expression = reference.original_expression or reference.expression
526527
added_original_expressions.add(added_expression)
528+
if not is_deprecated and reference.resource_version:
529+
is_deprecated = True
527530
if errors:
528531
for expression in errors:
529532
added_original_expressions.add(expression)
530533

531-
response = []
534+
results = []
532535

533536
for expression in added_original_expressions:
534537
response_item = self.create_response_item(added_expressions, errors, expression)
535538
if response_item:
536-
response.append(response_item)
539+
results.append(response_item)
537540

538-
return Response(response, status=status.HTTP_200_OK)
541+
response = Response(results, status=status.HTTP_200_OK)
542+
if is_deprecated:
543+
response[DEPRECATED_API_HEADER] = True
544+
return response
539545

540546
def should_cascade_mappings(self):
541547
return self.request.query_params.get('cascade', '').lower() == SOURCE_MAPPINGS

‎core/mappings/models.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,10 @@ def get_source(url):
393393
def is_existing_in_parent(self):
394394
return self.parent.mappings_set.filter(mnemonic__exact=self.mnemonic).exists()
395395

396+
@property
397+
def latest_source_version(self):
398+
return self.sources.exclude(version=HEAD).order_by('-created_at').first()
399+
396400
@classmethod
397401
def create_new_version_for(cls, instance, data, user):
398402
instance.populate_fields_from_relations(data)

0 commit comments

Comments
 (0)