@@ -27,21 +27,40 @@ def view_sinking_txs(
2727 limit : int | None = None ,
2828 order : Literal ['asc' , 'desc' ] = 'desc' ,
2929) -> pd .DataFrame :
30- stx_query = construct_stx_query (for_funder , for_recipient , from_date , before_date , finalized )
31-
30+ base_query = construct_stx_query (
31+ for_funder , for_recipient , from_date , before_date , finalized
32+ ).subquery ()
33+ subq_paging_token = base_query .c .paging_token
34+ # Determine order and cursor filter
3235 if order == 'asc' :
33- stx_query = stx_query .order_by (SinkingTx .paging_token .asc ())
34- if cursor :
35- stx_query = stx_query .where (SinkingTx .paging_token > cursor )
36- if order == 'desc' :
37- stx_query = stx_query .order_by (SinkingTx .paging_token .desc ())
38- if cursor :
39- stx_query = stx_query .where (SinkingTx .paging_token < cursor )
40-
41- if limit :
42- stx_query = stx_query .limit (limit )
36+ subq_order = subq_paging_token .asc ()
37+ stx_order = SinkingTx .paging_token .asc ()
38+ cursor_filter = subq_paging_token > (cursor or 0 )
39+ elif order == 'desc' :
40+ subq_order = subq_paging_token .desc ()
41+ stx_order = SinkingTx .paging_token .desc ()
42+ cursor_filter = subq_paging_token < (cursor or 0 )
4343
4444 with Session .begin () as session :
45+ # Step 1: Get unique paging_tokens for the page
46+ token_query = select (subq_paging_token ).select_from (base_query )
47+ if cursor and cursor > 0 :
48+ token_query = token_query .where (cursor_filter )
49+
50+ token_query = token_query .order_by (subq_order ).distinct ().limit (limit )
51+ paging_tokens = session .scalars (token_query ).all ()
52+
53+ if not paging_tokens :
54+ return pd .DataFrame ()
55+
56+ # Step 2: Fetch SinkingTxs for those paging_tokens, eager load statuses
57+ stx_query = (
58+ select (SinkingTx )
59+ .outerjoin (SinkStatus )
60+ .options (contains_eager (SinkingTx .statuses ))
61+ .where (SinkingTx .paging_token .in_ (paging_tokens ))
62+ .order_by (stx_order )
63+ )
4564 stx_records = session .scalars (stx_query ).unique ().all ()
4665 txdf = pd .DataFrame .from_records (stx .as_dict () for stx in stx_records )
4766
@@ -55,27 +74,30 @@ def construct_stx_query(
5574 before_date : dt .date | None ,
5675 finalized : bool | None ,
5776) -> Select [tuple [SinkingTx ]]:
58- q_txs = select (SinkingTx ).outerjoin (SinkStatus ).options (contains_eager (SinkingTx .statuses ))
77+ # Only build the base query and filters
78+ q_txs = select (SinkingTx )
5979 if for_funder :
6080 q_txs = q_txs .where (SinkingTx .funder == for_funder )
61-
81+
6282 if for_recipient :
6383 q_txs = q_txs .where (SinkingTx .recipient == for_recipient )
64-
84+
6585 if from_date :
6686 from_dt = dt .datetime (from_date .year , from_date .month , from_date .day )
6787 q_txs = q_txs .where (SinkingTx .created_at >= from_dt )
68-
88+
6989 if before_date :
7090 before_dt = dt .datetime (before_date .year , before_date .month , before_date .day )
7191 q_txs = q_txs .where (SinkingTx .created_at < before_dt )
72-
92+
93+ if finalized is not None :
94+ q_txs = q_txs .outerjoin (SinkStatus )
7395 if finalized is False :
7496 # not_ and in_ do not work here because NULL and false are treated differently
7597 q_txs = q_txs .where (or_ (SinkStatus .finalized == None , SinkStatus .finalized == False ))
7698 elif finalized is True :
7799 q_txs = q_txs .where (SinkStatus .finalized == True )
78-
100+
79101 return q_txs
80102
81103
0 commit comments