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 <noreply@anthropic.com>
This commit is contained in:
michael 2026-01-23 13:01:39 -06:00
parent d2d01aaea7
commit 3b868f7415
2 changed files with 39 additions and 10 deletions

View file

@ -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"
)

View file

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