perf: bound and batch visible poll listings

This commit is contained in:
2026-07-29 14:16:29 +02:00
parent 36ceb24954
commit fc0246b0f0
2 changed files with 59 additions and 9 deletions

View File

@@ -10,7 +10,7 @@ from typing import Any, Callable
from sqlalchemy import or_
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
from sqlalchemy.orm import Session, selectinload
from govoplan_core.db.base import utcnow
from govoplan_poll.backend.db.models import Poll, PollInvitation, PollLifecycleTransition, PollOption, PollResponse
@@ -366,13 +366,28 @@ def create_poll(
return poll
def list_polls(session: Session, *, tenant_id: str, status: str | None = None, kind: str | None = None) -> list[Poll]:
query = session.query(Poll).filter(Poll.tenant_id == tenant_id, Poll.deleted_at.is_(None))
def list_polls(
session: Session,
*,
tenant_id: str,
status: str | None = None,
kind: str | None = None,
limit: int = 100,
) -> list[Poll]:
query = (
session.query(Poll)
.options(selectinload(Poll.options))
.filter(Poll.tenant_id == tenant_id, Poll.deleted_at.is_(None))
)
if status:
query = query.filter(Poll.status == status)
if kind:
query = query.filter(Poll.kind == kind)
return query.order_by(Poll.created_at.desc(), Poll.title.asc()).all()
return (
query.order_by(Poll.created_at.desc(), Poll.title.asc())
.limit(max(1, min(limit, 200)))
.all()
)
def get_poll(session: Session, *, tenant_id: str, poll_id: str) -> Poll:
@@ -432,12 +447,45 @@ def list_visible_polls(
can_manage: bool = False,
status: str | None = None,
kind: str | None = None,
limit: int = 100,
) -> list[Poll]:
return [
poll
for poll in list_polls(session, tenant_id=tenant_id, status=status, kind=kind)
if poll_is_visible(session, poll=poll, actor_ids=actor_ids, can_manage=can_manage)
]
query = (
session.query(Poll)
.options(selectinload(Poll.options))
.filter(Poll.tenant_id == tenant_id, Poll.deleted_at.is_(None))
)
if status:
query = query.filter(Poll.status == status)
if kind:
query = query.filter(Poll.kind == kind)
if not can_manage:
ids = _actor_ids(actor_ids)
invitation_exists = (
session.query(PollInvitation.id)
.filter(
PollInvitation.tenant_id == tenant_id,
PollInvitation.poll_id == Poll.id,
PollInvitation.respondent_id.in_(ids or ("",)),
PollInvitation.revoked_at.is_(None),
or_(
PollInvitation.expires_at.is_(None),
PollInvitation.expires_at > _now(),
),
)
.exists()
)
query = query.filter(
or_(
Poll.created_by_user_id.in_(ids or ("",)),
Poll.visibility.in_(("tenant", "public")),
invitation_exists,
)
)
return (
query.order_by(Poll.created_at.desc(), Poll.title.asc())
.limit(max(1, min(limit, 200)))
.all()
)
def get_visible_poll(