@@ -42,10 +42,14 @@ defmodule GraphQL.Execution.Executor do
4242 @ spec execute_operation ( ExecutionContext . t , operation , map ) :: result_data | { :error , String . t }
4343 defp execute_operation ( context , operation , root_value ) do
4444 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 )
4646 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 }
4953 :subscription -> { :error , "Subscriptions not currently supported" }
5054 _ -> { :error , "Can only execute queries, mutations and subscriptions" }
5155 end
@@ -57,12 +61,12 @@ defmodule GraphQL.Execution.Executor do
5761 end
5862
5963 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 } ) ->
6165 case selection do
6266 % { kind: :Field } ->
6367 field_name = field_entry_key ( selection )
6468 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 ] ) }
6670 % { kind: :InlineFragment } ->
6771 collect_fragment ( context , runtime_type , selection , field_fragment_map )
6872 % { kind: :FragmentSpread } ->
@@ -71,36 +75,37 @@ defmodule GraphQL.Execution.Executor do
7175 field_fragment_map = put_in ( field_fragment_map . fragments [ fragment_name ] , true )
7276 collect_fragment ( context , runtime_type , context . fragments [ fragment_name ] , field_fragment_map )
7377 else
74- field_fragment_map
78+ { context , field_fragment_map }
7579 end
76- _ -> field_fragment_map
80+ _ -> { context , field_fragment_map }
7781 end
7882 end
7983 end
8084
81- @ spec execute_fields ( ExecutionContext . t , atom | Map , any , any ) :: any
85+ @ spec execute_fields ( ExecutionContext . t , atom | Map , any , any ) :: { ExecutionContext . t , map }
8286 defp execute_fields ( context , parent_type , source_value , fields ) when is_atom ( parent_type ) do
8387 execute_fields ( context , apply ( parent_type , :type , [ ] ) , source_value , fields )
8488 end
8589
86- @ spec execute_fields ( ExecutionContext . t , atom | Map , any , any ) :: any
90+ @ spec execute_fields ( ExecutionContext . t , atom | Map , any , any ) :: { ExecutionContext . t , map }
8791 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 } ) ->
8993 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 ) }
9296 end
9397 end
9498 end
9599
96- @ spec execute_fields_serially ( ExecutionContext . t , atom , map , any ) :: any
100+ @ spec execute_fields_serially ( ExecutionContext . t , atom , map , any ) :: { ExecutionContext . t , map }
97101 defp execute_fields_serially ( context , parent_type , source_value , fields ) do
98102 # call execute_fields because no async operations yet
99103 execute_fields ( context , parent_type , source_value , fields )
100104 end
101105
102106 defp resolve_field ( context , parent_type , source , field_asts ) do
103107 field_ast = hd ( field_asts )
108+ # FIXME: possible memory leak
104109 field_name = String . to_atom ( field_ast . name . value )
105110
106111 if field_def = field_definition ( parent_type , field_name ) do
@@ -137,44 +142,46 @@ defmodule GraphQL.Execution.Executor do
137142 end
138143 complete_value_catching_error ( context , return_type , field_asts , info , result )
139144 else
140- :undefined
145+ { context , :undefined }
141146 end
142147 end
143148
149+ @ spec complete_value_catching_error ( ExecutionContext . t , any , GraphQL.Document . t , any , map ) :: { ExecutionContext . t , map | nil }
144150 defp complete_value_catching_error ( context , return_type , field_asts , info , result ) do
145151 # TODO lots of error checking
146152 complete_value ( context , return_type , field_asts , info , result )
147153 end
148154
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 }
150157
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 }
152159 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 )
154161 execute_fields ( context , return_type , result , sub_field_asts . fields )
155162 end
156163
157164 defp complete_value ( context , % NonNull { ofType: inner_type } , field_asts , info , result ) when is_atom ( inner_type ) do
158165 complete_value ( context , % NonNull { ofType: apply ( inner_type , :type , [ ] ) } , field_asts , info , result )
159166 end
160167
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 }
162169 defp complete_value ( context , % NonNull { ofType: inner_type } , field_asts , info , result ) do
163170 # TODO: Null Checking
164171 complete_value ( context , inner_type , field_asts , info , result )
165172 end
166173
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 }
168175 defp complete_value ( context , % Interface { } = return_type , field_asts , info , result ) do
169176 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 )
171178 execute_fields ( context , runtime_type , result , sub_field_asts . fields )
172179 end
173180
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 }
175182 defp complete_value ( context , % Union { } = return_type , field_asts , info , result ) do
176183 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 )
178185 execute_fields ( context , runtime_type , result , sub_field_asts . fields )
179186 end
180187
@@ -184,26 +191,28 @@ defmodule GraphQL.Execution.Executor do
184191
185192 @ spec complete_value ( ExecutionContext . t , % List { } , GraphQL.Document . t , any , any ) :: map
186193 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 }
189197 end
198+ { context , Enum . reverse ( result ) }
190199 end
191200
192201 defp complete_value ( context , return_type , field_asts , info , result ) when is_atom ( return_type ) do
193202 type = apply ( return_type , :type , [ ] )
194203 complete_value ( context , type , field_asts , info , result )
195204 end
196205
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 ) }
199208 end
200209
201210 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 } ) ->
203212 if selection_set = Map . get ( field_ast , :selectionSet ) do
204213 collect_fields ( context , return_type , selection_set , field_fragment_map )
205214 else
206- field_fragment_map
215+ { context , field_fragment_map }
207216 end
208217 end
209218 end
@@ -293,7 +302,7 @@ defmodule GraphQL.Execution.Executor do
293302 if condition_matches do
294303 collect_fields ( context , runtime_type , selection . selectionSet , field_fragment_map )
295304 else
296- field_fragment_map
305+ { context , field_fragment_map }
297306 end
298307 end
299308
0 commit comments