From f1ceb7db8ee808dce8385d2331a14c2afb0d29da Mon Sep 17 00:00:00 2001 From: Goffi Date: Sat, 11 Apr 2026 02:08:15 +0200 Subject: [PATCH] memory (sqla): Add `with_parent` and `with_link` to `get_pubsub_nodes()`: Added `with_parent` and `with_link` parameters for eager loading of parent and linked_node relationships. Fixed CTE to include all children (not just base nodes) and use `selectinload` for parent to avoid cartesian products. rel 476 --- libervia/backend/memory/sqla.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/libervia/backend/memory/sqla.py b/libervia/backend/memory/sqla.py index e8666a4d..8b058111 100644 --- a/libervia/backend/memory/sqla.py +++ b/libervia/backend/memory/sqla.py @@ -1283,6 +1283,8 @@ class Storage: with_items: bool = False, with_subscriptions: bool = False, with_affiliations: bool = False, + with_parent: bool = False, + with_link: bool = False, ) -> list[PubsubNode]: """Retrieve pubsub nodes with their hierarchy and linking nodes. @@ -1300,6 +1302,8 @@ class Storage: @param with_items: If True, eagerly load items for each node. @param with_subscriptions: If True, eagerly load subscriptions for each node. @param with_affiliations: If True, eagerly load affiliations for each node. + @param with_parent: If True, eagerly load parent_node for each node. + @param with_link: If True, eagerly load linked_node for each node. @return: List of base nodes matching criteria (root nodes of the request). """ # Base criteria that always apply @@ -1313,13 +1317,15 @@ class Storage: criteria.append(PubsubNode.linked_node_id.is_(None)) # Prepare query options + # Always include parent_node and linked_node for all nodes when requested + options = [] if depth > 0: - options = [ - selectinload(PubsubNode.child_nodes), - joinedload(PubsubNode.parent_node), - ] - else: - options = [] + # Load child_nodes when depth > 0 so hierarchy can be traversed + options.append(selectinload(PubsubNode.child_nodes)) + if with_parent: + options.append(selectinload(PubsubNode.parent_node)) + if with_link: + options.append(joinedload(PubsubNode.linked_node)) if with_items: options.append(selectinload(PubsubNode.items)) if linked_node: @@ -1369,13 +1375,11 @@ class Storage: .cte(name="hierarchy", recursive=True) ) - # Recursive part: get direct children that are also base nodes. + # Recursive part: get direct children (including nodes with linked_node_id). children = ( select(PubsubNode.id, hierarchy.c.depth + 1) .join(hierarchy, PubsubNode.parent_node_id == hierarchy.c.id) - .filter( - hierarchy.c.depth < depth, PubsubNode.linked_node_id.is_(None) - ) + .filter(hierarchy.c.depth < depth) ) # Combine and create the full hierarchy.