44 */
55import * as t from 'gql-ast' ;
66import { Kind , OperationTypeNode , print } from 'graphql' ;
7- import type { ArgumentNode , FieldNode , VariableDefinitionNode } from 'graphql' ;
7+ import type { ArgumentNode , FieldNode , TypeNode , VariableDefinitionNode } from 'graphql' ;
88
99import { TypedDocumentString } from '../client/typed-document' ;
1010import {
@@ -22,7 +22,7 @@ import type {
2222 QuerySelectionOptions ,
2323} from '../types' ;
2424import type { QueryOptions } from '../types/query' ;
25- import type { Table } from '../types/schema' ;
25+ import type { Table , TypeRef } from '../types/schema' ;
2626import type { FieldSelection } from '../types/selection' ;
2727import { convertToSelectionOptions , isRelationalField } from './field-selector' ;
2828import { fuzzyFindByName } from 'inflekt' ;
@@ -356,12 +356,14 @@ function generateSelectQueryAST(
356356) : string {
357357 const pluralName = toCamelCasePlural ( table . name , table ) ;
358358
359- // Generate field selections
359+ // Generate field selections, collecting any variable definitions from field args
360+ const fieldArgVarDefs : VariableDefinitionNode [ ] = [ ] ;
360361 const fieldSelections = generateFieldSelectionsFromOptions (
361362 table ,
362363 allTables ,
363364 selection ,
364365 relationFieldMap ,
366+ fieldArgVarDefs ,
365367 ) ;
366368
367369 // Build the query AST
@@ -505,7 +507,7 @@ function generateSelectQueryAST(
505507 t . operationDefinition ( {
506508 operation : OperationTypeNode . QUERY ,
507509 name : `${ pluralName } Query` ,
508- variableDefinitions,
510+ variableDefinitions : [ ... variableDefinitions , ... fieldArgVarDefs ] ,
509511 selectionSet : t . selectionSet ( {
510512 selections : [
511513 t . field ( {
@@ -524,6 +526,20 @@ function generateSelectQueryAST(
524526 return print ( ast ) ;
525527}
526528
529+ /**
530+ * Convert a TypeRef to a GraphQL AST type node for variable definitions
531+ */
532+ function typeRefToGqlAstType ( ref : TypeRef ) : TypeNode {
533+ if ( ref . kind === 'NON_NULL' && ref . ofType ) {
534+ const inner = typeRefToGqlAstType ( ref . ofType ) ;
535+ return t . nonNullType ( { type : inner as ReturnType < typeof t . namedType > } ) ;
536+ }
537+ if ( ref . kind === 'LIST' && ref . ofType ) {
538+ return t . listType ( { type : typeRefToGqlAstType ( ref . ofType ) as ReturnType < typeof t . namedType > } ) ;
539+ }
540+ return t . namedType ( { type : ref . name ?? 'String' } ) ;
541+ }
542+
527543/**
528544 * Generate field selections from SelectionOptions
529545 */
@@ -532,6 +548,7 @@ function generateFieldSelectionsFromOptions(
532548 allTables : Table [ ] ,
533549 selection : QuerySelectionOptions | null ,
534550 relationFieldMap ?: Record < string , string | null > ,
551+ collectedVarDefs ?: VariableDefinitionNode [ ] ,
535552) : FieldNode [ ] {
536553 const DEFAULT_NESTED_RELATION_FIRST = 20 ;
537554
@@ -570,6 +587,48 @@ function generateFieldSelectionsFromOptions(
570587 createFieldSelectionNode ( resolvedField . name , resolvedField . alias ) ,
571588 ) ;
572589 }
590+ } else if ( typeof fieldOptions === 'object' && fieldOptions . args ) {
591+ // Field with arguments (e.g. requestUploadUrl on bucket types)
592+ const fieldDef = table . fields . find ( ( f ) => f . name === fieldName ) ;
593+ const fieldArgDefs = fieldDef ?. args ?? [ ] ;
594+ const fieldArgNodes : ArgumentNode [ ] = [ ] ;
595+
596+ for ( const [ argName , _argValue ] of Object . entries ( fieldOptions . args ) ) {
597+ const varName = `${ fieldName } _${ argName } ` ;
598+ const argDef = fieldArgDefs . find ( ( a ) => a . name === argName ) ;
599+ const gqlType = argDef
600+ ? typeRefToGqlAstType ( argDef . type )
601+ : t . namedType ( { type : 'String' } ) ;
602+
603+ collectedVarDefs ?. push (
604+ t . variableDefinition ( {
605+ variable : t . variable ( { name : varName } ) ,
606+ type : gqlType ,
607+ } ) ,
608+ ) ;
609+ fieldArgNodes . push (
610+ t . argument ( {
611+ name : argName ,
612+ value : t . variable ( { name : varName } ) ,
613+ } ) ,
614+ ) ;
615+ }
616+
617+ const nestedSelectObj = fieldOptions . select ;
618+ const nestedFields : FieldNode [ ] = Object . entries ( nestedSelectObj )
619+ . filter ( ( [ , include ] ) => include )
620+ . map ( ( [ nestedField ] ) => t . field ( { name : nestedField } ) ) ;
621+
622+ fieldSelections . push (
623+ createFieldSelectionNode (
624+ resolvedField . name ,
625+ resolvedField . alias ,
626+ fieldArgNodes ,
627+ nestedFields . length > 0
628+ ? t . selectionSet ( { selections : nestedFields } )
629+ : undefined ,
630+ ) ,
631+ ) ;
573632 } else if ( typeof fieldOptions === 'object' && fieldOptions . select ) {
574633 // Nested field selection (for relation fields)
575634 const nestedSelections : FieldNode [ ] = [ ] ;
0 commit comments