@@ -70,6 +70,62 @@ export function createGraphQLClient(config: GraphQLConfig): GraphQLClient {
7070 } ;
7171}
7272
73+ // Pagination utility for queries that return lists
74+ // Uses cursor-based pagination with 'after' parameter
75+ export async function queryAllPages < T extends { items : any [ ] } > (
76+ client : GraphQLClient ,
77+ query : string ,
78+ variables : Record < string , any > = { } ,
79+ pageSize : number = 100
80+ ) : Promise < T [ 'items' ] > {
81+ const allItems : T [ 'items' ] = [ ] ;
82+ let afterCursor : string | undefined = undefined ;
83+ let hasMore = true ;
84+ let totalFetched = 0 ;
85+
86+ while ( hasMore ) {
87+ // Add pagination variables
88+ const paginatedVariables : Record < string , any > = {
89+ ...variables ,
90+ limit : pageSize ,
91+ ...( afterCursor ? { after : afterCursor } : { } )
92+ } ;
93+
94+ const result : { [ key : string ] : T } = await client . query < { [ key : string ] : T } > ( query , paginatedVariables ) ;
95+
96+ // Find the first result that has an items array
97+ const resultKey = Object . keys ( result ) . find ( key =>
98+ result [ key ] && Array . isArray ( ( result [ key ] as any ) . items )
99+ ) ;
100+
101+ if ( ! resultKey ) {
102+ logger . error ( { result } , 'No items array found in query result' ) ;
103+ break ;
104+ }
105+
106+ const items : T [ 'items' ] = ( result [ resultKey ] as T ) . items ;
107+ allItems . push ( ...items ) ;
108+ totalFetched += items . length ;
109+
110+ // Check if we got less than a full page
111+ hasMore = items . length === pageSize ;
112+
113+ // Get the last item's ID as the cursor for the next page
114+ if ( hasMore && items . length > 0 ) {
115+ const lastItem : any = items [ items . length - 1 ] ;
116+ afterCursor = lastItem . id || lastItem . address || JSON . stringify ( lastItem ) ;
117+ }
118+
119+ // Safety check to prevent infinite loops
120+ if ( totalFetched > 10000 ) {
121+ logger . warn ( 'Pagination safety limit reached (10000 items)' ) ;
122+ break ;
123+ }
124+ }
125+
126+ return allItems ;
127+ }
128+
73129// GraphQL types based on schema introspection
74130export enum PartyState {
75131 CREATED ,
@@ -144,11 +200,13 @@ export interface Ziggurat {
144200}
145201
146202// Query helpers
203+ // NOTE: All queries that return lists use cursor-based pagination with $limit and $after parameters
204+ // Use the queryAllPages utility function when you need to fetch all results
147205export const GraphQLQueries = {
148206 // Ziggurat queries
149207 getPartiesByZigguratWithStateDoorChosen : `
150- query GetPartiesByZiggurat($zigguratAddress: String!) {
151- partys(where: { zigguratAddress: $zigguratAddress, state: "1" }) {
208+ query GetPartiesByZiggurat($zigguratAddress: String!, $limit: Int, $after: String ) {
209+ partys(where: { zigguratAddress: $zigguratAddress, state: "1" }, limit: $limit, after: $after ) {
152210 items {
153211 id
154212 zigguratAddress
@@ -264,13 +322,27 @@ export const GraphQLQueries = {
264322 }
265323 ` ,
266324
325+ getBattleById : `
326+ query GetBattleById($battleId: String!) {
327+ battle(id: $battleId) {
328+ id
329+ gameStartedAt
330+ currentTurn
331+ teamAStarts
332+ turnDuration
333+ winner
334+ }
335+ }
336+ ` ,
337+
267338 getBattlePlayers : `
268- query GetBattlePlayers($battleId: String!) {
269- battlePlayers(where: { id_starts_with: $battleId }) {
339+ query GetBattlePlayers($battleId: String!, $limit: Int = 100, $after: String ) {
340+ battlePlayers(where: { id_starts_with: $battleId }, limit: $limit, after: $after ) {
270341 items {
271342 id
272343 playerId
273344 teamA
345+ eliminated
274346 character {
275347 id
276348 name
@@ -282,6 +354,23 @@ export const GraphQLQueries = {
282354 }
283355 ` ,
284356
357+ getActiveEnemyPlayers : `
358+ query GetActiveEnemyPlayers($battleId: String!, $isTeamA: Boolean!) {
359+ battlePlayers(where: { id_starts_with: $battleId, teamA_not: $isTeamA, eliminated: false }) {
360+ items {
361+ id
362+ playerId
363+ teamA
364+ eliminated
365+ character {
366+ id
367+ name
368+ }
369+ }
370+ }
371+ }
372+ ` ,
373+
285374 getBattleTurns : `
286375 query GetBattleTurns($battleId: String!) {
287376 battleTurns(where: { id_starts_with: $battleId }, orderBy: "turn", orderDirection: "desc", limit: 1) {
@@ -298,15 +387,16 @@ export const GraphQLQueries = {
298387
299388 // OperatorManager queries
300389 getBattlesWithOperator : `
301- query GetBattlesWithOperator($operator: String!) {
302- battles(where: { operator: $operator }, limit: 1000 ) {
390+ query GetBattlesWithOperator($operator: String!, $limit: Int = 100, $after: String ) {
391+ battles(where: { operator: $operator, winner: null }, limit: $limit, after: $after ) {
303392 items {
304393 id
305394 operator
306395 gameStartedAt
307396 currentTurn
308397 teamAStarts
309398 turnDuration
399+ winner
310400 }
311401 }
312402 }
@@ -340,8 +430,8 @@ export const GraphQLQueries = {
340430 ` ,
341431
342432 getCharactersByOwner : `
343- query GetCharactersByOwner($owner: String!) {
344- characters(where: { owner: $owner }) {
433+ query GetCharactersByOwner($owner: String!, $limit: Int = 100, $after: String ) {
434+ characters(where: { owner: $owner }, limit: $limit, after: $after ) {
345435 items {
346436 id
347437 name
0 commit comments