@@ -45,7 +45,10 @@ func constructOptions(options []Option) (*constructOptionsOutput, error) {
45
45
46
46
// ConstructQuery build GraphQL query string from struct and variables
47
47
func ConstructQuery (v interface {}, variables map [string ]interface {}, options ... Option ) (string , error ) {
48
- query := query (v )
48
+ query , err := query (v )
49
+ if err != nil {
50
+ return "" , err
51
+ }
49
52
50
53
optionsOutput , err := constructOptions (options )
51
54
if err != nil {
@@ -65,7 +68,10 @@ func ConstructQuery(v interface{}, variables map[string]interface{}, options ...
65
68
66
69
// ConstructQuery build GraphQL mutation string from struct and variables
67
70
func ConstructMutation (v interface {}, variables map [string ]interface {}, options ... Option ) (string , error ) {
68
- query := query (v )
71
+ query , err := query (v )
72
+ if err != nil {
73
+ return "" , err
74
+ }
69
75
optionsOutput , err := constructOptions (options )
70
76
if err != nil {
71
77
return "" , err
@@ -83,7 +89,10 @@ func ConstructMutation(v interface{}, variables map[string]interface{}, options
83
89
84
90
// ConstructSubscription build GraphQL subscription string from struct and variables
85
91
func ConstructSubscription (v interface {}, variables map [string ]interface {}, options ... Option ) (string , error ) {
86
- query := query (v )
92
+ query , err := query (v )
93
+ if err != nil {
94
+ return "" , err
95
+ }
87
96
optionsOutput , err := constructOptions (options )
88
97
if err != nil {
89
98
return "" , err
@@ -171,22 +180,28 @@ func writeArgumentType(w io.Writer, t reflect.Type, value bool) {
171
180
// a minified query string from the provided struct v.
172
181
//
173
182
// E.g., struct{Foo Int, BarBaz *Boolean} -> "{foo,barBaz}".
174
- func query (v interface {}) string {
183
+ func query (v interface {}) ( string , error ) {
175
184
var buf bytes.Buffer
176
- writeQuery (& buf , reflect .TypeOf (v ), reflect .ValueOf (v ), false )
177
- return buf .String ()
185
+ err := writeQuery (& buf , reflect .TypeOf (v ), reflect .ValueOf (v ), false )
186
+ if err != nil {
187
+ return "" , fmt .Errorf ("failed to write query: %w" , err )
188
+ }
189
+ return buf .String (), nil
178
190
}
179
191
180
192
// writeQuery writes a minified query for t to w.
181
193
// If inline is true, the struct fields of t are inlined into parent struct.
182
- func writeQuery (w io.Writer , t reflect.Type , v reflect.Value , inline bool ) {
194
+ func writeQuery (w io.Writer , t reflect.Type , v reflect.Value , inline bool ) error {
183
195
switch t .Kind () {
184
196
case reflect .Ptr :
185
- writeQuery (w , t .Elem (), ElemSafe (v ), false )
197
+ err := writeQuery (w , t .Elem (), ElemSafe (v ), false )
198
+ if err != nil {
199
+ return fmt .Errorf ("failed to write query for ptr `%v`: %w" , t , err )
200
+ }
186
201
case reflect .Struct :
187
202
// If the type implements json.Unmarshaler, it's a scalar. Don't expand it.
188
203
if reflect .PtrTo (t ).Implements (jsonUnmarshaler ) {
189
- return
204
+ return nil
190
205
}
191
206
if ! inline {
192
207
io .WriteString (w , "{" )
@@ -216,20 +231,25 @@ func writeQuery(w io.Writer, t reflect.Type, v reflect.Value, inline bool) {
216
231
if isTrue (f .Tag .Get ("scalar" )) {
217
232
continue
218
233
}
219
- writeQuery (w , f .Type , FieldSafe (v , i ), inlineField )
234
+ err := writeQuery (w , f .Type , FieldSafe (v , i ), inlineField )
235
+ if err != nil {
236
+ return fmt .Errorf ("failed to write query for struct field `%v`: %w" , f .Name , err )
237
+ }
220
238
}
221
239
if ! inline {
222
240
io .WriteString (w , "}" )
223
241
}
224
242
case reflect .Slice :
225
243
if t .Elem ().Kind () != reflect .Array {
226
- writeQuery (w , t .Elem (), IndexSafe (v , 0 ), false )
227
- return
244
+ err := writeQuery (w , t .Elem (), IndexSafe (v , 0 ), false )
245
+ if err != nil {
246
+ return fmt .Errorf ("failed to write query for slice item `%v`: %w" , t , err )
247
+ }
248
+ return nil
228
249
}
229
250
// handle [][2]interface{} like an ordered map
230
251
if t .Elem ().Len () != 2 {
231
- err := fmt .Errorf ("only arrays of len 2 are supported, got %v" , t .Elem ())
232
- panic (err .Error ())
252
+ return fmt .Errorf ("only arrays of len 2 are supported, got %v" , t .Elem ())
233
253
}
234
254
sliceOfPairs := v
235
255
_ , _ = io .WriteString (w , "{" )
@@ -238,14 +258,22 @@ func writeQuery(w io.Writer, t reflect.Type, v reflect.Value, inline bool) {
238
258
// it.Value() returns interface{}, so we need to use reflect.ValueOf
239
259
// to cast it away
240
260
key , val := pair .Index (0 ), reflect .ValueOf (pair .Index (1 ).Interface ())
241
- _ , _ = io .WriteString (w , key .Interface ().(string ))
242
- writeQuery (w , val .Type (), val , false )
261
+ keyString , ok := key .Interface ().(string )
262
+ if ! ok {
263
+ return fmt .Errorf ("expected pair (string, %v), got (%v, %v)" ,
264
+ val .Type (), key .Type (), val .Type ())
265
+ }
266
+ _ , _ = io .WriteString (w , keyString )
267
+ err := writeQuery (w , val .Type (), val , false )
268
+ if err != nil {
269
+ return fmt .Errorf ("failed to write query for pair[1] `%v`: %w" , val .Type (), err )
270
+ }
243
271
}
244
272
_ , _ = io .WriteString (w , "}" )
245
273
case reflect .Map :
246
- err := fmt .Errorf ("type %v is not supported, use [][2]interface{} instead" , t )
247
- panic (err .Error ())
274
+ return fmt .Errorf ("type %v is not supported, use [][2]interface{} instead" , t )
248
275
}
276
+ return nil
249
277
}
250
278
251
279
func IndexSafe (v reflect.Value , i int ) reflect.Value {
0 commit comments