1- import { ExecutionRequest , serializeInputValue } from '@graphql-tools/utils' ;
1+ import {
2+ asArray ,
3+ astFromArg ,
4+ astFromValueUntyped ,
5+ ExecutionRequest ,
6+ } from '@graphql-tools/utils' ;
27import {
38 ArgumentNode ,
49 DefinitionNode ,
@@ -7,21 +12,18 @@ import {
712 GraphQLInputType ,
813 GraphQLObjectType ,
914 GraphQLSchema ,
15+ isInputObjectType ,
16+ isListType ,
17+ isNonNullType ,
1018 Kind ,
11- NamedTypeNode ,
1219 NameNode ,
1320 OperationDefinitionNode ,
1421 OperationTypeNode ,
1522 SelectionNode ,
1623 SelectionSetNode ,
17- typeFromAST ,
1824 VariableDefinitionNode ,
1925} from 'graphql' ;
2026import { ICreateRequest } from './types.js' ;
21- import {
22- createVariableNameGenerator ,
23- updateArgument ,
24- } from './updateArguments.js' ;
2527
2628export function getDelegatingOperation (
2729 parentType : GraphQLObjectType ,
@@ -38,23 +40,19 @@ export function getDelegatingOperation(
3840
3941export function createRequest ( {
4042 subgraphName,
41- sourceSchema,
42- sourceParentType,
43- sourceFieldName,
4443 fragments,
45- variableDefinitions,
46- variableValues,
47- targetRootValue,
44+ rootValue,
4845 targetOperationName,
4946 targetOperation,
47+ targetSchema,
5048 targetFieldName,
5149 selectionSet,
5250 fieldNodes,
5351 context,
5452 info,
53+ args,
5554} : ICreateRequest ) : ExecutionRequest {
5655 let newSelectionSet : SelectionSetNode | undefined ;
57- const argumentNodeMap : Record < string , ArgumentNode > = Object . create ( null ) ;
5856
5957 if ( selectionSet != null ) {
6058 newSelectionSet = selectionSet ;
@@ -74,45 +72,8 @@ export function createRequest({
7472 selections,
7573 }
7674 : undefined ;
77-
78- const args = fieldNodes ?. [ 0 ] ?. arguments ;
79- if ( args ) {
80- for ( const argNode of args ) {
81- argumentNodeMap [ argNode . name . value ] = argNode ;
82- }
83- }
8475 }
8576
86- const newVariables = Object . create ( null ) ;
87- const variableDefinitionMap = Object . create ( null ) ;
88-
89- if ( sourceSchema != null && variableDefinitions != null ) {
90- for ( const def of variableDefinitions ) {
91- const varName = def . variable . name . value ;
92- variableDefinitionMap [ varName ] = def ;
93- const varType = typeFromAST (
94- sourceSchema ,
95- def . type as NamedTypeNode ,
96- ) as GraphQLInputType ;
97- const serializedValue = serializeInputValue (
98- varType ,
99- variableValues ?. [ varName ] ,
100- ) ;
101- if ( serializedValue !== undefined ) {
102- newVariables [ varName ] = serializedValue ;
103- }
104- }
105- }
106-
107- if ( sourceParentType != null && sourceFieldName != null ) {
108- updateArgumentsWithDefaults (
109- sourceParentType ,
110- sourceFieldName ,
111- argumentNodeMap ,
112- variableDefinitionMap ,
113- newVariables ,
114- ) ;
115- }
11677 const fieldNode = fieldNodes ?. [ 0 ] ;
11778 const rootFieldName = targetFieldName ?? fieldNode ?. name . value ;
11879
@@ -122,9 +83,81 @@ export function createRequest({
12283 ) ;
12384 }
12485
86+ const newVariables = Object . create ( null ) ;
87+ const variableDefinitions : VariableDefinitionNode [ ] = [ ] ;
88+ const argNodes : ArgumentNode [ ] = [ ] ;
89+
90+ if ( args != null ) {
91+ const rootType = targetSchema ?. getRootType ( targetOperation ) ;
92+ const rootField = rootType ?. getFields ( ) [ rootFieldName ] ;
93+ const rootFieldArgs = rootField ?. args ;
94+ for ( const argName in args ) {
95+ const argValue = args [ argName ] ;
96+ const argInstance = rootFieldArgs ?. find ( ( arg ) => arg . name === argName ) ;
97+ if ( argInstance ) {
98+ const argAst = astFromArg ( argInstance , targetSchema ) ;
99+ const varExists = ( varName : string ) =>
100+ variableDefinitions . some (
101+ ( varDef ) => varDef . variable . name . value === varName ,
102+ ) ;
103+ let varName = argName ;
104+ // Try `<argName>`, then `<rootFieldName>_<argName>`, then `_0_<rootFieldName>_<argName>`, etc.
105+ if ( varExists ( varName ) ) {
106+ varName = `_${ rootFieldName } _${ argName } ` ;
107+ let i = 0 ;
108+ while ( varExists ( varName ) ) {
109+ varName = `_${ i ++ } _${ rootFieldName } _${ argName } ` ;
110+ }
111+ }
112+ variableDefinitions . push ( {
113+ kind : Kind . VARIABLE_DEFINITION ,
114+ variable : {
115+ kind : Kind . VARIABLE ,
116+ name : {
117+ kind : Kind . NAME ,
118+ value : varName ,
119+ } ,
120+ } ,
121+ type : argAst . type ,
122+ } ) ;
123+ newVariables [ varName ] = projectArgumentValue (
124+ argValue ,
125+ argInstance . type ,
126+ ) ;
127+ argNodes . push ( {
128+ kind : Kind . ARGUMENT ,
129+ name : {
130+ kind : Kind . NAME ,
131+ value : argName ,
132+ } ,
133+ value : {
134+ kind : Kind . VARIABLE ,
135+ name : {
136+ kind : Kind . NAME ,
137+ value : varName ,
138+ } ,
139+ } ,
140+ } ) ;
141+ } else {
142+ // For arguments that are not defined in the target schema, we inline them.
143+ const valueNode = astFromValueUntyped ( argValue ) ;
144+ if ( valueNode != null ) {
145+ argNodes . push ( {
146+ kind : Kind . ARGUMENT ,
147+ name : {
148+ kind : Kind . NAME ,
149+ value : argName ,
150+ } ,
151+ value : valueNode ,
152+ } ) ;
153+ }
154+ }
155+ }
156+ }
157+
125158 const rootfieldNode : FieldNode = {
126159 kind : Kind . FIELD ,
127- arguments : Object . values ( argumentNodeMap ) ,
160+ arguments : argNodes ,
128161 name : {
129162 kind : Kind . NAME ,
130163 value : rootFieldName ,
@@ -144,7 +177,7 @@ export function createRequest({
144177 kind : Kind . OPERATION_DEFINITION ,
145178 name : operationName ,
146179 operation : targetOperation ,
147- variableDefinitions : Object . values ( variableDefinitionMap ) ,
180+ variableDefinitions,
148181 selectionSet : {
149182 kind : Kind . SELECTION_SET ,
150183 selections : [ rootfieldNode ] ,
@@ -154,12 +187,7 @@ export function createRequest({
154187 const definitions : Array < DefinitionNode > = [ operationDefinition ] ;
155188
156189 if ( fragments != null ) {
157- for ( const fragmentName in fragments ) {
158- const fragment = fragments [ fragmentName ] ;
159- if ( fragment ) {
160- definitions . push ( fragment ) ;
161- }
162- }
190+ definitions . push ( ...fragments ) ;
163191 }
164192
165193 const document : DocumentNode = {
@@ -171,49 +199,48 @@ export function createRequest({
171199 subgraphName,
172200 document,
173201 variables : newVariables ,
174- rootValue : targetRootValue ,
202+ rootValue,
175203 operationName : targetOperationName ,
176204 context,
177205 info,
178206 operationType : targetOperation ,
179207 } ;
180208}
181209
182- function updateArgumentsWithDefaults (
183- sourceParentType : GraphQLObjectType ,
184- sourceFieldName : string ,
185- argumentNodeMap : Record < string , ArgumentNode > ,
186- variableDefinitionMap : Record < string , VariableDefinitionNode > ,
187- variableValues : Record < string , any > ,
188- ) : void {
189- const generateVariableName = createVariableNameGenerator (
190- variableDefinitionMap ,
191- ) ;
192-
193- const sourceField = sourceParentType . getFields ( ) [ sourceFieldName ] ;
194- if ( ! sourceField ) {
195- throw new Error (
196- `Field "${ sourceFieldName } " was not found in type "${ sourceParentType } ".` ,
210+ function projectArgumentValue ( argValue : any , argType : GraphQLInputType ) : any {
211+ if ( isNonNullType ( argType ) ) {
212+ return projectArgumentValue ( argValue , argType . ofType ) ;
213+ }
214+ if ( isListType ( argType ) ) {
215+ return asArray ( argValue ) . map ( ( item : any ) =>
216+ projectArgumentValue ( item , argType . ofType ) ,
197217 ) ;
198218 }
199- for ( const argument of sourceField . args ) {
200- const argName = argument . name ;
201- const sourceArgType = argument . type ;
202-
203- if ( argumentNodeMap [ argName ] === undefined ) {
204- const defaultValue = argument . defaultValue ;
205-
206- if ( defaultValue !== undefined ) {
207- updateArgument (
208- argumentNodeMap ,
209- variableDefinitionMap ,
210- variableValues ,
211- argName ,
212- generateVariableName ( argName ) ,
213- sourceArgType ,
214- serializeInputValue ( sourceArgType , defaultValue ) ,
215- ) ;
219+ if (
220+ isInputObjectType ( argType ) &&
221+ typeof argValue === 'object' &&
222+ argValue !== null
223+ ) {
224+ const projectedValue : any = { } ;
225+ const fields = argType . getFields ( ) ;
226+ for ( const key in argValue ) {
227+ const field = fields [ key ] ;
228+ if ( field ) {
229+ projectedValue [ key ] = projectArgumentValue ( argValue [ key ] , field . type ) ;
216230 }
217231 }
232+ return projectedValue ;
233+ }
234+ if ( argValue != null ) {
235+ if ( argType . name === 'Boolean' ) {
236+ return Boolean ( argValue ) ;
237+ }
238+ if ( argType . name === 'Int' || argType . name === 'Float' ) {
239+ return Number ( argValue ) ;
240+ }
241+ if ( argType . name === 'String' ) {
242+ return String ( argValue ) ;
243+ }
218244 }
245+ return argValue ;
219246}
0 commit comments