@@ -88,16 +88,18 @@ func writeArgumentType(w io.Writer, t reflect.Type, value bool) {
88
88
// E.g., struct{Foo Int, BarBaz *Boolean} -> "{foo,barBaz}".
89
89
func query (v interface {}) string {
90
90
var buf bytes.Buffer
91
- writeQuery (& buf , reflect .TypeOf (v ), false )
91
+ writeQuery (& buf , reflect .TypeOf (v ), reflect . ValueOf ( v ), false )
92
92
return buf .String ()
93
93
}
94
94
95
95
// writeQuery writes a minified query for t to w.
96
96
// If inline is true, the struct fields of t are inlined into parent struct.
97
- func writeQuery (w io.Writer , t reflect.Type , inline bool ) {
97
+ func writeQuery (w io.Writer , t reflect.Type , v reflect. Value , inline bool ) {
98
98
switch t .Kind () {
99
- case reflect .Ptr , reflect .Slice :
100
- writeQuery (w , t .Elem (), false )
99
+ case reflect .Ptr :
100
+ writeQuery (w , t .Elem (), ElemSafe (v ), false )
101
+ case reflect .Slice :
102
+ writeQuery (w , t .Elem (), IndexSafe (v , 0 ), false )
101
103
case reflect .Struct :
102
104
// If the type implements json.Unmarshaler, it's a scalar. Don't expand it.
103
105
if reflect .PtrTo (t ).Implements (jsonUnmarshaler ) {
@@ -120,12 +122,51 @@ func writeQuery(w io.Writer, t reflect.Type, inline bool) {
120
122
io .WriteString (w , ident .ParseMixedCaps (f .Name ).ToLowerCamelCase ())
121
123
}
122
124
}
123
- writeQuery (w , f .Type , inlineField )
125
+ writeQuery (w , f .Type , FieldSafe ( v , i ), inlineField )
124
126
}
125
127
if ! inline {
126
128
io .WriteString (w , "}" )
127
129
}
130
+ case reflect .Map : // handle map[string]interface{}
131
+ it := v .MapRange ()
132
+ _ , _ = io .WriteString (w , "{" )
133
+ for it .Next () {
134
+ // it.Value() returns interface{}, so we need to use reflect.ValueOf
135
+ // to cast it away
136
+ key , val := it .Key (), reflect .ValueOf (it .Value ().Interface ())
137
+ _ , _ = io .WriteString (w , key .String ())
138
+ writeQuery (w , val .Type (), val , false )
139
+ }
140
+ _ , _ = io .WriteString (w , "}" )
141
+ }
142
+ }
143
+
144
+ func IndexSafe (v reflect.Value , i int ) reflect.Value {
145
+ if v .IsValid () && i < v .Len () {
146
+ return v .Index (i )
147
+ }
148
+ return reflect .ValueOf (nil )
149
+ }
150
+
151
+ func TypeSafe (v reflect.Value ) reflect.Type {
152
+ if v .IsValid () {
153
+ return v .Type ()
154
+ }
155
+ return reflect .TypeOf ((interface {})(nil ))
156
+ }
157
+
158
+ func ElemSafe (v reflect.Value ) reflect.Value {
159
+ if v .IsValid () {
160
+ return v .Elem ()
161
+ }
162
+ return reflect .ValueOf (nil )
163
+ }
164
+
165
+ func FieldSafe (valStruct reflect.Value , i int ) reflect.Value {
166
+ if valStruct .IsValid () {
167
+ return valStruct .Field (i )
128
168
}
169
+ return reflect .ValueOf (nil )
129
170
}
130
171
131
172
var jsonUnmarshaler = reflect .TypeOf ((* json .Unmarshaler )(nil )).Elem ()
0 commit comments