1
1
import { sortBy } from "es-toolkit" ;
2
2
import { get , isArray , isEmpty , set } from "es-toolkit/compat" ;
3
3
import type { TadaDocumentNode } from "gql.tada" ;
4
- import { type ArgumentNode , type DocumentNode , Kind , type SelectionNode , visit } from "graphql" ;
5
- import type { GraphQLClient , Variables } from "graphql-request" ;
4
+ import { type ArgumentNode , type DocumentNode , Kind , parse , type SelectionNode , visit } from "graphql" ;
5
+ import type { GraphQLClient , RequestDocument , RequestOptions , Variables } from "graphql-request" ;
6
6
7
7
// Constants for TheGraph limits
8
8
const THE_GRAPH_LIMIT = 500 ;
@@ -14,7 +14,6 @@ interface ListField {
14
14
path : string [ ] ;
15
15
fieldName : string ;
16
16
alias ?: string ;
17
- hasFirstArg : boolean ;
18
17
firstValue ?: number ;
19
18
skipValue ?: number ;
20
19
otherArgs : ArgumentNode [ ] ;
@@ -35,13 +34,13 @@ interface ListField {
35
34
* - Removes the directive from the AST (The Graph doesn't recognize it)
36
35
* - Returns both the cleaned document and a list of fields to auto-paginate
37
36
*/
38
- function stripFetchAllDirective ( document : DocumentNode ) : {
37
+ function stripFetchAllDirective ( document : DocumentNode | RequestDocument ) : {
39
38
document : DocumentNode ;
40
39
fetchAllFields : Set < string > ;
41
40
} {
42
41
const fetchAllFields = new Set < string > ( ) ;
43
-
44
- const strippedDocument = visit ( document , {
42
+ const documentNode = typeof document === "string" ? parse ( document ) : document ;
43
+ const strippedDocument = visit ( documentNode , {
45
44
Field ( node ) {
46
45
// Check if this field has the @fetchAll directive
47
46
if ( node . directives && node . directives . length > 0 ) {
@@ -132,41 +131,27 @@ function extractFetchAllFields(
132
131
}
133
132
134
133
// Check if this field has pagination arguments (first or skip)
135
- let hasFirstArg = false ;
136
- let hasSkipArg = false ;
137
134
let firstValue : number | undefined ;
138
135
let skipValue : number | undefined ;
139
- let firstValueIsDefault = false ;
140
136
const otherArgs : ArgumentNode [ ] = [ ] ;
141
137
142
138
if ( node . arguments ) {
143
139
for ( const arg of node . arguments ) {
144
140
if ( arg . name . value === FIRST_ARG ) {
145
- hasFirstArg = true ;
146
141
if ( arg . value . kind === Kind . INT ) {
147
142
firstValue = Number . parseInt ( arg . value . value ) ;
148
143
} else if ( arg . value . kind === Kind . VARIABLE && variables ) {
149
144
const varName = arg . value . name . value ;
150
145
const varValue = ( variables as Record < string , unknown > ) [ varName ] ;
151
146
firstValue = typeof varValue === "number" ? varValue : undefined ;
152
- // If variable is defined in query but not passed in input, check if it's a standard pagination variable
153
- if ( firstValue === undefined && varName === arg . value . name . value ) {
154
- firstValue = THE_GRAPH_LIMIT ; // Default to THE_GRAPH_LIMIT
155
- firstValueIsDefault = true ; // Mark that this was defaulted
156
- }
157
147
}
158
148
} else if ( arg . name . value === SKIP_ARG ) {
159
- hasSkipArg = true ;
160
149
if ( arg . value . kind === Kind . INT ) {
161
150
skipValue = Number . parseInt ( arg . value . value ) ;
162
151
} else if ( arg . value . kind === Kind . VARIABLE && variables ) {
163
152
const varName = arg . value . name . value ;
164
153
const varValue = ( variables as Record < string , unknown > ) [ varName ] ;
165
154
skipValue = typeof varValue === "number" ? varValue : undefined ;
166
- // If variable is defined in query but not passed in input, check if it's a standard pagination variable
167
- if ( skipValue === undefined && varName === arg . value . name . value ) {
168
- skipValue = 0 ; // Default to 0
169
- }
170
155
}
171
156
} else {
172
157
otherArgs . push ( arg ) ;
@@ -190,13 +175,12 @@ function extractFetchAllFields(
190
175
path : [ ...pathStack ] ,
191
176
fieldName : node . name . value ,
192
177
alias : node . alias ?. value ,
193
- hasFirstArg,
194
- firstValue : hasFetchAllDirective && ! hasFirstArg ? THE_GRAPH_LIMIT : firstValue ,
195
- skipValue : hasFetchAllDirective && ! hasSkipArg ? 0 : skipValue ,
178
+ firstValue : hasFetchAllDirective && ( firstValue ?? THE_GRAPH_LIMIT ) ,
179
+ skipValue : hasFetchAllDirective && ( skipValue ?? 0 ) ,
196
180
otherArgs,
197
181
selections : node . selectionSet ?. selections ,
198
182
hasFetchAllDirective,
199
- firstValueIsDefault,
183
+ firstValueIsDefault : hasFetchAllDirective ? firstValue === undefined : false ,
200
184
} ) ;
201
185
}
202
186
} ,
@@ -398,9 +382,20 @@ export function createTheGraphClientWithPagination(theGraphClient: Pick<GraphQLC
398
382
399
383
return {
400
384
async query < TResult , TVariables extends Variables > (
401
- document : TadaDocumentNode < TResult , TVariables > ,
402
- variables : Omit < TVariables , "skip" | "first" > ,
385
+ documentOrOptions : TadaDocumentNode < TResult , TVariables > | RequestDocument | RequestOptions < TVariables , TResult > ,
386
+ variablesRaw ? : Omit < TVariables , "skip" | "first" > ,
403
387
) : Promise < TResult > {
388
+ let document : TadaDocumentNode < TResult , TVariables > | RequestDocument ;
389
+ let variables : Omit < TVariables , "skip" | "first" > ;
390
+
391
+ if ( isRequestOptions ( documentOrOptions ) ) {
392
+ document = documentOrOptions . document ;
393
+ variables = documentOrOptions . variables as TVariables ;
394
+ } else {
395
+ document = documentOrOptions ;
396
+ variables = variablesRaw ?? ( { } as TVariables ) ;
397
+ }
398
+
404
399
// First, detect and strip @fetchAll directives
405
400
const { document : processedDocument , fetchAllFields } = stripFetchAllDirective ( document ) ;
406
401
@@ -450,3 +445,7 @@ export function createTheGraphClientWithPagination(theGraphClient: Pick<GraphQLC
450
445
} ,
451
446
} as const ;
452
447
}
448
+
449
+ function isRequestOptions ( args : unknown ) : args is RequestOptions < Variables , unknown > {
450
+ return typeof args === "object" && args !== null && "document" in args && "variables" in args ;
451
+ }
0 commit comments