@@ -12,10 +12,15 @@ import {
1212 SanitizedEvidenceDto ,
1313 VoteTalliesDto ,
1414} from './dto/claim.dto' ;
15+ import {
16+ buildKeysetWhere ,
17+ buildNextCursor ,
18+ clampLimit ,
19+ } from '../helpers/pagination' ;
1520
1621interface ListClaimsParams {
17- page : number ;
18- limit : number ;
22+ after ?: string ;
23+ limit ? : number ;
1924 status ?: string ;
2025}
2126
@@ -47,9 +52,9 @@ export class ClaimsService {
4752 }
4853
4954 async listClaims ( params : ListClaimsParams ) : Promise < ClaimsListResponseDto > {
50- const { page , limit , status } = params ;
51- const skip = ( page - 1 ) * limit ;
52- const cacheKey = `claims:list:${ page } :${ limit } :${ status || 'all' } ` ;
55+ const { after , status } = params ;
56+ const limit = clampLimit ( params . limit ) ;
57+ const cacheKey = `claims:list:${ after ?? 'start' } :${ limit } :${ status ?? 'all' } ` ;
5358 const cached = await this . redis . get < ClaimsListResponseDto > ( cacheKey ) ;
5459
5560 if ( cached ) {
@@ -58,33 +63,30 @@ export class ClaimsService {
5863 }
5964
6065 const lastLedger = await this . getLastLedger ( ) ;
61- const where : Prisma . ClaimWhereInput | undefined = status
66+ const statusFilter = status
6267 ? { status : status . toUpperCase ( ) as 'PENDING' | 'APPROVED' | 'PAID' | 'REJECTED' }
63- : undefined ;
68+ : { } ;
69+ const keysetWhere = buildKeysetWhere ( after ) ;
70+ const where : Prisma . ClaimWhereInput = {
71+ ...statusFilter ,
72+ ...( keysetWhere ?? { } ) ,
73+ } ;
6474
6575 const [ claims , total ] = await Promise . all ( [
6676 this . prisma . claim . findMany ( {
6777 where,
68- include : {
69- votes : {
70- select : { vote : true } ,
71- } ,
72- } ,
73- orderBy : { createdAt : 'desc' } ,
74- skip,
78+ include : { votes : { select : { vote : true } } } ,
79+ orderBy : [ { createdAt : 'desc' } , { id : 'desc' } ] ,
7580 take : limit ,
7681 } ) ,
77- this . prisma . claim . count ( { where } ) ,
82+ this . prisma . claim . count ( { where : statusFilter } ) ,
7883 ] ) ;
7984
8085 const response : ClaimsListResponseDto = {
8186 data : claims . map ( ( claim ) => this . transformClaim ( claim , lastLedger ) ) ,
8287 pagination : {
83- page,
84- limit,
88+ next_cursor : buildNextCursor ( claims , limit , total ) ,
8589 total,
86- totalPages : Math . ceil ( total / limit ) ,
87- hasNext : skip + claims . length < total ,
8890 } ,
8991 } ;
9092
@@ -96,42 +98,41 @@ export class ClaimsService {
9698 walletAddress : string ,
9799 params : ListClaimsParams ,
98100 ) : Promise < ClaimsListResponseDto > {
99- const { page , limit } = params ;
100- const skip = ( page - 1 ) * limit ;
101+ const { after } = params ;
102+ const limit = clampLimit ( params . limit ) ;
101103 const lastLedger = await this . getLastLedger ( ) ;
102104
103105 const votedClaimIds = await this . prisma . vote . findMany ( {
104106 where : { voterAddress : walletAddress . toLowerCase ( ) } ,
105107 select : { claimId : true } ,
106108 } ) ;
107- const votedIds = votedClaimIds . map ( ( vote ) => vote . claimId ) ;
109+ const votedIds = votedClaimIds . map ( ( v ) => v . claimId ) ;
110+ const keysetWhere = buildKeysetWhere ( after ) ;
108111
109- const pendingClaims = await this . prisma . claim . findMany ( {
110- where : {
111- status : 'PENDING' ,
112- ...( votedIds . length > 0 ? { id : { notIn : votedIds } } : { } ) ,
113- } ,
114- include : {
115- votes : {
116- select : { vote : true } ,
117- } ,
118- } ,
119- orderBy : { createdAt : 'desc' } ,
120- } ) ;
112+ const baseWhere : Prisma . ClaimWhereInput = {
113+ status : 'PENDING' ,
114+ ...( votedIds . length > 0 ? { id : { notIn : votedIds } } : { } ) ,
115+ } ;
116+
117+ const [ allOpen , page ] = await Promise . all ( [
118+ this . prisma . claim . count ( { where : baseWhere } ) ,
119+ this . prisma . claim . findMany ( {
120+ where : { ...baseWhere , ...( keysetWhere ?? { } ) } ,
121+ include : { votes : { select : { vote : true } } } ,
122+ orderBy : [ { createdAt : 'desc' } , { id : 'desc' } ] ,
123+ take : limit ,
124+ } ) ,
125+ ] ) ;
121126
122- const openClaims = pendingClaims . filter (
127+ const openClaims = page . filter (
123128 ( claim ) => this . getVotingDeadlineLedger ( claim . createdAtLedger ) > lastLedger ,
124129 ) ;
125- const paginatedClaims = openClaims . slice ( skip , skip + limit ) ;
126130
127131 return {
128- data : paginatedClaims . map ( ( claim ) => this . transformClaim ( claim , lastLedger ) ) ,
132+ data : openClaims . map ( ( claim ) => this . transformClaim ( claim , lastLedger ) ) ,
129133 pagination : {
130- page,
131- limit,
132- total : openClaims . length ,
133- totalPages : Math . ceil ( openClaims . length / limit ) ,
134- hasNext : skip + paginatedClaims . length < openClaims . length ,
134+ next_cursor : buildNextCursor ( openClaims , limit , allOpen ) ,
135+ total : allOpen ,
135136 } ,
136137 } ;
137138 }
0 commit comments