@@ -42,10 +42,14 @@ defmodule GraphQL.Execution.Executor do
42
42
@ spec execute_operation ( ExecutionContext . t , operation , map ) :: result_data | { :error , String . t }
43
43
defp execute_operation ( context , operation , root_value ) do
44
44
type = operation_root_type ( context . schema , operation )
45
- % { fields: fields } = collect_fields ( context , type , operation . selectionSet )
45
+ { context , % { fields: fields } } = collect_fields ( context , type , operation . selectionSet )
46
46
case operation . operation do
47
- :query -> { :ok , execute_fields ( context , type , root_value , fields ) }
48
- :mutation -> { :ok , execute_fields_serially ( context , type , root_value , fields ) }
47
+ :query ->
48
+ { _ , result } = execute_fields ( context , type , root_value , fields )
49
+ { :ok , result }
50
+ :mutation ->
51
+ { _ , result } = execute_fields_serially ( context , type , root_value , fields )
52
+ { :ok , result }
49
53
:subscription -> { :error , "Subscriptions not currently supported" }
50
54
_ -> { :error , "Can only execute queries, mutations and subscriptions" }
51
55
end
@@ -57,12 +61,12 @@ defmodule GraphQL.Execution.Executor do
57
61
end
58
62
59
63
defp collect_fields ( context , runtime_type , selection_set , field_fragment_map \\ % { fields: % { } , fragments: % { } } ) do
60
- Enum . reduce selection_set [ :selections ] , field_fragment_map , fn ( selection , field_fragment_map ) ->
64
+ Enum . reduce selection_set [ :selections ] , { context , field_fragment_map } , fn ( selection , { context , field_fragment_map } ) ->
61
65
case selection do
62
66
% { kind: :Field } ->
63
67
field_name = field_entry_key ( selection )
64
68
fields = field_fragment_map . fields [ field_name ] || [ ]
65
- put_in ( field_fragment_map . fields [ field_name ] , [ selection | fields ] )
69
+ { context , put_in ( field_fragment_map . fields [ field_name ] , [ selection | fields ] ) }
66
70
% { kind: :InlineFragment } ->
67
71
collect_fragment ( context , runtime_type , selection , field_fragment_map )
68
72
% { kind: :FragmentSpread } ->
@@ -71,36 +75,37 @@ defmodule GraphQL.Execution.Executor do
71
75
field_fragment_map = put_in ( field_fragment_map . fragments [ fragment_name ] , true )
72
76
collect_fragment ( context , runtime_type , context . fragments [ fragment_name ] , field_fragment_map )
73
77
else
74
- field_fragment_map
78
+ { context , field_fragment_map }
75
79
end
76
- _ -> field_fragment_map
80
+ _ -> { context , field_fragment_map }
77
81
end
78
82
end
79
83
end
80
84
81
- @ spec execute_fields ( ExecutionContext . t , atom | Map , any , any ) :: any
85
+ @ spec execute_fields ( ExecutionContext . t , atom | Map , any , any ) :: { ExecutionContext . t , map }
82
86
defp execute_fields ( context , parent_type , source_value , fields ) when is_atom ( parent_type ) do
83
87
execute_fields ( context , apply ( parent_type , :type , [ ] ) , source_value , fields )
84
88
end
85
89
86
- @ spec execute_fields ( ExecutionContext . t , atom | Map , any , any ) :: any
90
+ @ spec execute_fields ( ExecutionContext . t , atom | Map , any , any ) :: { ExecutionContext . t , map }
87
91
defp execute_fields ( context , parent_type , source_value , fields ) do
88
- Enum . reduce fields , % { } , fn ( { field_name_ast , field_asts } , results ) ->
92
+ Enum . reduce fields , { context , % { } } , fn ( { field_name_ast , field_asts } , { context , results } ) ->
89
93
case resolve_field ( context , parent_type , source_value , field_asts ) do
90
- :undefined -> results
91
- value -> Map . put ( results , field_name_ast . value , value )
94
+ { context , :undefined } -> { context , results }
95
+ { context , value } -> { context , Map . put ( results , field_name_ast . value , value ) }
92
96
end
93
97
end
94
98
end
95
99
96
- @ spec execute_fields_serially ( ExecutionContext . t , atom , map , any ) :: any
100
+ @ spec execute_fields_serially ( ExecutionContext . t , atom , map , any ) :: { ExecutionContext . t , map }
97
101
defp execute_fields_serially ( context , parent_type , source_value , fields ) do
98
102
# call execute_fields because no async operations yet
99
103
execute_fields ( context , parent_type , source_value , fields )
100
104
end
101
105
102
106
defp resolve_field ( context , parent_type , source , field_asts ) do
103
107
field_ast = hd ( field_asts )
108
+ # FIXME: possible memory leak
104
109
field_name = String . to_atom ( field_ast . name . value )
105
110
106
111
if field_def = field_definition ( parent_type , field_name ) do
@@ -137,44 +142,46 @@ defmodule GraphQL.Execution.Executor do
137
142
end
138
143
complete_value_catching_error ( context , return_type , field_asts , info , result )
139
144
else
140
- :undefined
145
+ { context , :undefined }
141
146
end
142
147
end
143
148
149
+ @ spec complete_value_catching_error ( ExecutionContext . t , any , GraphQL.Document . t , any , map ) :: { ExecutionContext . t , map | nil }
144
150
defp complete_value_catching_error ( context , return_type , field_asts , info , result ) do
145
151
# TODO lots of error checking
146
152
complete_value ( context , return_type , field_asts , info , result )
147
153
end
148
154
149
- defp complete_value ( _ , _ , _ , _ , nil ) , do: nil
155
+ @ spec complete_value ( ExecutionContext . t , any , any , any , nil ) :: { ExecutionContext . t , nil }
156
+ defp complete_value ( context , _ , _ , _ , nil ) , do: { context , nil }
150
157
151
- @ spec complete_value ( ExecutionContext . t , % ObjectType { } , GraphQL.Document . t , any , map ) :: map
158
+ @ spec complete_value ( ExecutionContext . t , % ObjectType { } , GraphQL.Document . t , any , map ) :: { ExecutionContext . t , map }
152
159
defp complete_value ( context , % ObjectType { } = return_type , field_asts , _info , result ) do
153
- sub_field_asts = collect_sub_fields ( context , return_type , field_asts )
160
+ { context , sub_field_asts } = collect_sub_fields ( context , return_type , field_asts )
154
161
execute_fields ( context , return_type , result , sub_field_asts . fields )
155
162
end
156
163
157
164
defp complete_value ( context , % NonNull { ofType: inner_type } , field_asts , info , result ) when is_atom ( inner_type ) do
158
165
complete_value ( context , % NonNull { ofType: apply ( inner_type , :type , [ ] ) } , field_asts , info , result )
159
166
end
160
167
161
- @ spec complete_value ( ExecutionContext . t , % NonNull { } , GraphQL.Document . t , any , any ) :: map
168
+ @ spec complete_value ( ExecutionContext . t , % NonNull { } , GraphQL.Document . t , any , any ) :: { ExecutionContext . t , map }
162
169
defp complete_value ( context , % NonNull { ofType: inner_type } , field_asts , info , result ) do
163
170
# TODO: Null Checking
164
171
complete_value ( context , inner_type , field_asts , info , result )
165
172
end
166
173
167
- @ spec complete_value ( ExecutionContext . t , % Interface { } , GraphQL.Document . t , any , any ) :: map
174
+ @ spec complete_value ( ExecutionContext . t , % Interface { } , GraphQL.Document . t , any , any ) :: { ExecutionContext . t , map }
168
175
defp complete_value ( context , % Interface { } = return_type , field_asts , info , result ) do
169
176
runtime_type = AbstractType . get_object_type ( return_type , result , info . schema )
170
- sub_field_asts = collect_sub_fields ( context , runtime_type , field_asts )
177
+ { context , sub_field_asts } = collect_sub_fields ( context , runtime_type , field_asts )
171
178
execute_fields ( context , runtime_type , result , sub_field_asts . fields )
172
179
end
173
180
174
- @ spec complete_value ( ExecutionContext . t , % Union { } , GraphQL.Document . t , any , any ) :: map
181
+ @ spec complete_value ( ExecutionContext . t , % Union { } , GraphQL.Document . t , any , any ) :: { ExecutionContext . t , map }
175
182
defp complete_value ( context , % Union { } = return_type , field_asts , info , result ) do
176
183
runtime_type = AbstractType . get_object_type ( return_type , result , info . schema )
177
- sub_field_asts = collect_sub_fields ( context , runtime_type , field_asts )
184
+ { context , sub_field_asts } = collect_sub_fields ( context , runtime_type , field_asts )
178
185
execute_fields ( context , runtime_type , result , sub_field_asts . fields )
179
186
end
180
187
@@ -184,26 +191,28 @@ defmodule GraphQL.Execution.Executor do
184
191
185
192
@ spec complete_value ( ExecutionContext . t , % List { } , GraphQL.Document . t , any , any ) :: map
186
193
defp complete_value ( context , % List { ofType: list_type } , field_asts , info , result ) do
187
- Enum . map result , fn ( item ) ->
188
- complete_value_catching_error ( context , list_type , field_asts , info , item )
194
+ { context , result } = Enum . reduce result , { context , [ ] } , fn ( item , { context , acc } ) ->
195
+ { context , value } = complete_value_catching_error ( context , list_type , field_asts , info , item )
196
+ { context , [ value ] ++ acc }
189
197
end
198
+ { context , Enum . reverse ( result ) }
190
199
end
191
200
192
201
defp complete_value ( context , return_type , field_asts , info , result ) when is_atom ( return_type ) do
193
202
type = apply ( return_type , :type , [ ] )
194
203
complete_value ( context , type , field_asts , info , result )
195
204
end
196
205
197
- defp complete_value ( _context , return_type , _field_asts , _info , result ) do
198
- GraphQL.Types . serialize ( return_type , result )
206
+ defp complete_value ( context , return_type , _field_asts , _info , result ) do
207
+ { context , GraphQL.Types . serialize ( return_type , result ) }
199
208
end
200
209
201
210
defp collect_sub_fields ( context , return_type , field_asts ) do
202
- Enum . reduce field_asts , % { fields: % { } , fragments: % { } } , fn ( field_ast , field_fragment_map ) ->
211
+ Enum . reduce field_asts , { context , % { fields: % { } , fragments: % { } } } , fn ( field_ast , { context , field_fragment_map } ) ->
203
212
if selection_set = Map . get ( field_ast , :selectionSet ) do
204
213
collect_fields ( context , return_type , selection_set , field_fragment_map )
205
214
else
206
- field_fragment_map
215
+ { context , field_fragment_map }
207
216
end
208
217
end
209
218
end
@@ -293,7 +302,7 @@ defmodule GraphQL.Execution.Executor do
293
302
if condition_matches do
294
303
collect_fields ( context , runtime_type , selection . selectionSet , field_fragment_map )
295
304
else
296
- field_fragment_map
305
+ { context , field_fragment_map }
297
306
end
298
307
end
299
308
0 commit comments