Commit 75788911 authored by Mickaël Desfrênes's avatar Mickaël Desfrênes
Browse files

add comments

parent 75115c4f
Loading
Loading
Loading
Loading
+45 −0
Original line number Diff line number Diff line
@@ -934,6 +934,9 @@ class Collection(models.Model):
        """
        reverse=True for grandparent  -> parent -> child list
        reverse=False for child -> parent -> grandparent list

        This walks the parent relation lazily. Prefer a batched ancestor
        hydrator for list endpoints that serialize many collections at once.
        """
        ancestors = []
        parent = self.parent
@@ -957,9 +960,17 @@ class Collection(models.Model):
        )

    def descendants(self) -> Iterator["Collection"]:
        """Yield descendant collections in child-title order."""
        yield from _recurse_collection(self)

    def descendants_resources(self) -> Iterator[Resource]:
        """
        Yield direct resources first, then resources from each descendant collection.

        Callers that need file-specific fields should prefetch/select related data
        after collecting the resources, because this generic traversal intentionally
        returns plain Resource rows.
        """
        for res in (
            self.resources.filter(deleted_at__isnull=True)
            .order_by("collectionmembership__rank", "title")
@@ -1079,6 +1090,7 @@ class Collection(models.Model):
        return row

    def dublin_core_metas(self) -> List["MetadataCollectionValue"]:
        """Return all Dublin Core metadata values attached to this collection."""
        metas = []
        try:
            dublin_core_set = MetadataSet.objects.only("id").get(
@@ -1102,6 +1114,7 @@ class Collection(models.Model):
            return []

    def dublin_core_title(self) -> str:
        """Return the Dublin Core title override, falling back to the collection title."""
        meta_value = (
            self.metadatacollectionvalue_set.filter(
                metadata__set__title__iexact="Dublin Core",
@@ -1115,6 +1128,12 @@ class Collection(models.Model):
        return self.title

    def to_path(self, include_pk: bool = False):
        """
        Return the path from the root collection to this collection.

        `include_pk=True` is useful for API payloads that need stable breadcrumb
        identifiers; the default keeps the historical plain title list.
        """
        titles = []
        for ancestor in self.ancestors():
            if include_pk:
@@ -1128,6 +1147,12 @@ class Collection(models.Model):
        return titles

    def _subtree_collection_ids_for_export(self) -> List[int]:
        """
        Return this collection id plus all descendant ids using one recursive query.

        Export code only needs ids at this stage; full rows are hydrated later with
        an explicit field list and ordered in Python.
        """
        with connection.cursor() as cursor:
            cursor.execute(
                """
@@ -1148,10 +1173,17 @@ class Collection(models.Model):
            return [int(row[0]) for row in cursor.fetchall()]

    def _ordered_subtree_collections_for_export(self) -> List["Collection"]:
        """
        Hydrate the export subtree and return collections in parent-before-child order.

        The recursive CTE gives membership in the subtree, then this method rebuilds
        the tree in memory so sibling ordering stays consistent with collection lists.
        """
        collection_ids = self._subtree_collection_ids_for_export()
        if not collection_ids:
            return []

        # Batch-load the narrow row shape needed by XLSX export rows.
        collections = {
            collection.pk: collection
            for collection in Collection.objects.filter(pk__in=collection_ids).only(
@@ -1167,6 +1199,7 @@ class Collection(models.Model):
        ordered_collections = []

        def visit(collection_id: int):
            # Depth-first traversal keeps each collection before its descendants.
            collection = collections.get(collection_id)
            if not collection:
                return
@@ -1182,6 +1215,12 @@ class Collection(models.Model):
        metadata_ids: Union[List[int], None] = None,
        metadataset_ids: Union[List[int], None] = None,
    ) -> Iterator[List[Union[int, str, None]]]:
        """
        Stream XLSX rows for this collection subtree.

        Metadata values and resource memberships are fetched in batches and grouped
        by object id so row generation does not query once per collection/resource.
        """
        known_metadatas = list(
            self.project.metadatas(
                not settings.JAMA_XLSX_EXPORT_AUTOMATIC_METADATAS,
@@ -1304,6 +1343,12 @@ class Collection(models.Model):


def _recurse_collection(collection: Collection) -> Iterator[Collection]:
    """
    Recursive generator used by public descendant helpers.

    It follows `children()` ordering and stops silently on excessive recursion,
    matching the historical behavior of descendant traversal.
    """
    try:
        for child in collection.children().iterator():
            yield child