From 3b868f7415eb8fd3888dbfb6206db4347529ef5d Mon Sep 17 00:00:00 2001 From: michael Date: Fri, 23 Jan 2026 13:01:39 -0600 Subject: [PATCH] Fix proof types not loading for sub-channels in dropdown hierarchy Replace nested selectinload chain with separate explicit queries for channels, sub-channels, and proof types. The self-referential selectinload chain didn't reliably load the third level (proof types) in async SQLAlchemy. Also add order_by to DropdownOption.children relationship for consistent ordering. Co-Authored-By: Claude Opus 4.5 --- backend/app/models/models.py | 6 ++- .../app/repositories/dropdown_repository.py | 43 +++++++++++++++---- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/backend/app/models/models.py b/backend/app/models/models.py index 45af22d..8d3513b 100755 --- a/backend/app/models/models.py +++ b/backend/app/models/models.py @@ -172,4 +172,8 @@ class DropdownOption(Base): # Self-referential relationship for hierarchy parent: Mapped[Optional["DropdownOption"]] = relationship("DropdownOption", remote_side=[id], back_populates="children") - children: Mapped[list["DropdownOption"]] = relationship("DropdownOption", back_populates="parent") + children: Mapped[list["DropdownOption"]] = relationship( + "DropdownOption", + back_populates="parent", + order_by="DropdownOption.display_order" + ) diff --git a/backend/app/repositories/dropdown_repository.py b/backend/app/repositories/dropdown_repository.py index b41b381..7737786 100644 --- a/backend/app/repositories/dropdown_repository.py +++ b/backend/app/repositories/dropdown_repository.py @@ -23,26 +23,51 @@ class DropdownRepository: campaigns: [] } """ - # Get all channels (top-level, no parent) - stmt = select(DropdownOption).where( + # Query 1: Get all channels + channels_stmt = select(DropdownOption).where( DropdownOption.option_type == "channel", DropdownOption.parent_id.is_(None) - ).options(selectinload(DropdownOption.children).selectinload(DropdownOption.children)) + ).order_by(DropdownOption.display_order) + channels_result = await self.session.execute(channels_stmt) + channels = channels_result.scalars().all() - result = await self.session.execute(stmt) - channels = result.scalars().all() + # Query 2: Get all sub-channels + sub_channels_stmt = select(DropdownOption).where( + DropdownOption.option_type == "sub_channel" + ).order_by(DropdownOption.display_order) + sub_channels_result = await self.session.execute(sub_channels_stmt) + sub_channels = sub_channels_result.scalars().all() - # Build hierarchical structure for channels + # Query 3: Get all proof types + proof_types_stmt = select(DropdownOption).where( + DropdownOption.option_type == "proof_type" + ).order_by(DropdownOption.display_order) + proof_types_result = await self.session.execute(proof_types_stmt) + proof_types = proof_types_result.scalars().all() + + # Build lookup dictionaries + sub_channels_by_parent: dict[uuid.UUID, list] = {} + for sc in sub_channels: + if sc.parent_id not in sub_channels_by_parent: + sub_channels_by_parent[sc.parent_id] = [] + sub_channels_by_parent[sc.parent_id].append(sc) + + proof_types_by_parent: dict[uuid.UUID, list] = {} + for pt in proof_types: + if pt.parent_id not in proof_types_by_parent: + proof_types_by_parent[pt.parent_id] = [] + proof_types_by_parent[pt.parent_id].append(pt) + + # Assemble hierarchy hierarchy: dict[str, dict[str, list[str]]] = {} - for channel in channels: channel_name = channel.value hierarchy[channel_name] = {} - for sub_channel in channel.children: + for sub_channel in sub_channels_by_parent.get(channel.id, []): sub_channel_name = sub_channel.value hierarchy[channel_name][sub_channel_name] = [ - pt.value for pt in sub_channel.children + pt.value for pt in proof_types_by_parent.get(sub_channel.id, []) ] # Get brand guidelines