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
This commit is contained in:
Goffi 2026-04-11 02:08:15 +02:00
commit f1ceb7db8e

View file

@ -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.