Refactor campaign delivery decision paths
This commit is contained in:
@@ -2712,8 +2712,7 @@ def _campaign_jobs_page_response(
|
||||
cursor: str | None = None,
|
||||
changed_job_ids: set[str] | None = None,
|
||||
) -> CampaignJobsResponse:
|
||||
total_unfiltered = int(session.query(func.count(CampaignJob.id)).filter(*base_filters).scalar() or 0)
|
||||
total = int(session.query(func.count(CampaignJob.id)).filter(*filtered).scalar() or 0)
|
||||
total_unfiltered, total = _campaign_jobs_page_counts(session, base_filters=base_filters, filtered=filtered)
|
||||
pages = (total + page_size - 1) // page_size if total else 0
|
||||
fingerprint = _campaign_jobs_cursor_fingerprint(
|
||||
campaign_id=campaign_id,
|
||||
@@ -2728,47 +2727,26 @@ def _campaign_jobs_page_response(
|
||||
sort_direction=sort_direction,
|
||||
)
|
||||
ordering = _campaign_jobs_ordering(sort_by, sort_direction)
|
||||
ordered_query = session.query(CampaignJob).filter(*filtered).order_by(*ordering)
|
||||
start_cursor: str | None = None
|
||||
effective_offset = 0
|
||||
if cursor:
|
||||
if sort_by != "number" or sort_direction != "asc":
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Campaign job cursors require number ascending order",
|
||||
)
|
||||
try:
|
||||
cursor_values = decode_keyset_cursor(CAMPAIGN_JOBS_CURSOR_SCOPE, cursor, fingerprint=fingerprint)
|
||||
if cursor_values is None:
|
||||
raise KeysetCursorError("Invalid pagination cursor")
|
||||
page_query = session.query(CampaignJob).filter(*filtered).filter(_campaign_jobs_cursor_condition(cursor_values))
|
||||
except KeysetCursorError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
|
||||
start_cursor = cursor
|
||||
else:
|
||||
effective_offset = (page - 1) * page_size
|
||||
page_query = session.query(CampaignJob).filter(*filtered)
|
||||
if effective_offset > 0 and sort_by == "number" and sort_direction == "asc":
|
||||
previous_row = ordered_query.offset(effective_offset - 1).limit(1).first()
|
||||
if previous_row is not None:
|
||||
start_cursor = _campaign_jobs_cursor_for_row(previous_row, fingerprint=fingerprint)
|
||||
|
||||
rows_plus_one = (
|
||||
page_query
|
||||
.order_by(*ordering)
|
||||
.offset(effective_offset)
|
||||
.limit(page_size + 1)
|
||||
.all()
|
||||
rows_plus_one, start_cursor = _campaign_jobs_page_rows(
|
||||
session,
|
||||
filtered=filtered,
|
||||
ordering=ordering,
|
||||
page=page,
|
||||
page_size=page_size,
|
||||
sort_by=sort_by,
|
||||
sort_direction=sort_direction,
|
||||
cursor=cursor,
|
||||
fingerprint=fingerprint,
|
||||
)
|
||||
jobs = rows_plus_one[:page_size]
|
||||
next_cursor = (
|
||||
_campaign_jobs_cursor_for_row(jobs[-1], fingerprint=fingerprint)
|
||||
if changed_job_ids is None
|
||||
and sort_by == "number"
|
||||
and sort_direction == "asc"
|
||||
and len(rows_plus_one) > page_size
|
||||
and jobs
|
||||
else None
|
||||
next_cursor = _campaign_jobs_next_cursor(
|
||||
jobs,
|
||||
rows_plus_one=rows_plus_one,
|
||||
page_size=page_size,
|
||||
sort_by=sort_by,
|
||||
sort_direction=sort_direction,
|
||||
changed_job_ids=changed_job_ids,
|
||||
fingerprint=fingerprint,
|
||||
)
|
||||
if changed_job_ids is not None:
|
||||
jobs = [job for job in jobs if job.id in changed_job_ids]
|
||||
@@ -2787,6 +2765,110 @@ def _campaign_jobs_page_response(
|
||||
)
|
||||
|
||||
|
||||
def _campaign_jobs_page_counts(
|
||||
session: Session,
|
||||
*,
|
||||
base_filters: list[object],
|
||||
filtered: list[object],
|
||||
) -> tuple[int, int]:
|
||||
total_unfiltered = int(session.query(func.count(CampaignJob.id)).filter(*base_filters).scalar() or 0)
|
||||
total = int(session.query(func.count(CampaignJob.id)).filter(*filtered).scalar() or 0)
|
||||
return total_unfiltered, total
|
||||
|
||||
|
||||
def _campaign_jobs_page_rows(
|
||||
session: Session,
|
||||
*,
|
||||
filtered: list[object],
|
||||
ordering: list[object],
|
||||
page: int,
|
||||
page_size: int,
|
||||
sort_by: str,
|
||||
sort_direction: str,
|
||||
cursor: str | None,
|
||||
fingerprint: str,
|
||||
) -> tuple[list[CampaignJob], str | None]:
|
||||
if cursor:
|
||||
page_query = _campaign_jobs_query_after_cursor(
|
||||
session,
|
||||
filtered=filtered,
|
||||
cursor=cursor,
|
||||
fingerprint=fingerprint,
|
||||
sort_by=sort_by,
|
||||
sort_direction=sort_direction,
|
||||
)
|
||||
return page_query.order_by(*ordering).limit(page_size + 1).all(), cursor
|
||||
|
||||
effective_offset = (page - 1) * page_size
|
||||
page_query = session.query(CampaignJob).filter(*filtered)
|
||||
start_cursor = _campaign_jobs_offset_cursor(
|
||||
page_query,
|
||||
ordering=ordering,
|
||||
effective_offset=effective_offset,
|
||||
sort_by=sort_by,
|
||||
sort_direction=sort_direction,
|
||||
fingerprint=fingerprint,
|
||||
)
|
||||
rows = page_query.order_by(*ordering).offset(effective_offset).limit(page_size + 1).all()
|
||||
return rows, start_cursor
|
||||
|
||||
|
||||
def _campaign_jobs_query_after_cursor(
|
||||
session: Session,
|
||||
*,
|
||||
filtered: list[object],
|
||||
cursor: str,
|
||||
fingerprint: str,
|
||||
sort_by: str,
|
||||
sort_direction: str,
|
||||
):
|
||||
if sort_by != "number" or sort_direction != "asc":
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Campaign job cursors require number ascending order",
|
||||
)
|
||||
try:
|
||||
cursor_values = decode_keyset_cursor(CAMPAIGN_JOBS_CURSOR_SCOPE, cursor, fingerprint=fingerprint)
|
||||
if cursor_values is None:
|
||||
raise KeysetCursorError("Invalid pagination cursor")
|
||||
except KeysetCursorError as exc:
|
||||
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc
|
||||
return session.query(CampaignJob).filter(*filtered).filter(_campaign_jobs_cursor_condition(cursor_values))
|
||||
|
||||
|
||||
def _campaign_jobs_offset_cursor(
|
||||
query,
|
||||
*,
|
||||
ordering: list[object],
|
||||
effective_offset: int,
|
||||
sort_by: str,
|
||||
sort_direction: str,
|
||||
fingerprint: str,
|
||||
) -> str | None:
|
||||
if effective_offset <= 0 or sort_by != "number" or sort_direction != "asc":
|
||||
return None
|
||||
previous_row = query.order_by(*ordering).offset(effective_offset - 1).limit(1).first()
|
||||
if previous_row is None:
|
||||
return None
|
||||
return _campaign_jobs_cursor_for_row(previous_row, fingerprint=fingerprint)
|
||||
|
||||
|
||||
def _campaign_jobs_next_cursor(
|
||||
jobs: list[CampaignJob],
|
||||
*,
|
||||
rows_plus_one: list[CampaignJob],
|
||||
page_size: int,
|
||||
sort_by: str,
|
||||
sort_direction: str,
|
||||
changed_job_ids: set[str] | None,
|
||||
fingerprint: str,
|
||||
) -> str | None:
|
||||
cursor_supported = sort_by == "number" and sort_direction == "asc"
|
||||
if changed_job_ids is not None or not cursor_supported or len(rows_plus_one) <= page_size or not jobs:
|
||||
return None
|
||||
return _campaign_jobs_cursor_for_row(jobs[-1], fingerprint=fingerprint)
|
||||
|
||||
|
||||
def _campaign_jobs_cursor_fingerprint(
|
||||
*,
|
||||
campaign_id: str,
|
||||
|
||||
Reference in New Issue
Block a user