@@ -10,6 +10,7 @@ def initialize(parent_type:, runner:, key:, selections_step:)
1010 @ast_node = @ast_nodes = nil
1111 @runner = runner
1212 @field_definition = nil
13+ @arguments = nil
1314 @field_results = nil
1415 @path = nil
1516 @enqueued_authorization = false
@@ -18,9 +19,10 @@ def initialize(parent_type:, runner:, key:, selections_step:)
1819 @all_next_results = nil
1920 @static_type = nil
2021 @next_selections = nil
22+ @object_is_authorized = nil
2123 end
2224
23- attr_reader :ast_node , :key , :parent_type , :selections_step , :runner , :field_definition
25+ attr_reader :ast_node , :key , :parent_type , :selections_step , :runner , :field_definition , :object_is_authorized , :arguments
2426
2527 def path
2628 @path ||= [ *@selections_step . path , @key ] . freeze
@@ -103,7 +105,16 @@ def coerce_argument_value(arg_t, arg_value)
103105 arg_value . map { |v | coerce_argument_value ( inner_t , v ) }
104106 end
105107 elsif arg_t . kind . leaf?
106- arg_t . coerce_input ( arg_value , @selections_step . query . context )
108+ begin
109+ ctx = @selections_step . query . context
110+ arg_t . coerce_input ( arg_value , ctx )
111+ rescue GraphQL ::UnauthorizedEnumValueError => enum_err
112+ begin
113+ @runner . schema . unauthorized_object ( enum_err )
114+ rescue GraphQL ::ExecutionError => ex_err
115+ ex_err
116+ end
117+ end
107118 elsif arg_t . kind . input_object?
108119 coerce_arguments ( arg_t , arg_value )
109120 else
@@ -124,11 +135,9 @@ def sync(lazy)
124135 else
125136 @runner . schema . sync_lazy ( lazy )
126137 end
127- rescue GraphQL ::UnauthorizedError => err
128- @runner . schema . unauthorized_object ( err )
138+ rescue GraphQL ::UnauthorizedError => auth_err
139+ @runner . schema . unauthorized_object ( auth_err )
129140 rescue GraphQL ::ExecutionError => err
130- err . path = path
131- err . ast_nodes = ast_nodes
132141 err
133142 end
134143
@@ -142,19 +151,51 @@ def call
142151 end
143152 end
144153
154+ def add_graphql_error ( err )
155+ err . path = path
156+ err . ast_nodes = ast_nodes
157+ @selections_step . query . context . add_error ( err )
158+ err
159+ end
160+
161+ module AlwaysAuthorized
162+ def self . []( _key )
163+ true
164+ end
165+ end
166+
145167 def execute_field
146168 field_name = @ast_node . name
147169 @field_definition = @selections_step . query . get_field ( @parent_type , field_name ) || raise ( "Invariant: no field found for #{ @parent_type . to_type_signature } .#{ ast_node . name } " )
148170 objects = @selections_step . objects
149171 if field_name == "__typename"
172+ # TODO handle custom introspection
150173 @field_results = Array . new ( objects . size , @parent_type . graphql_name )
174+ @object_is_authorized = AlwaysAuthorized
151175 build_results
152176 return
153177 end
154178
155- arguments = coerce_arguments ( @field_definition , @ast_node . arguments ) # rubocop:disable Development/ContextIsPassedCop
179+ @ arguments = coerce_arguments ( @field_definition , @ast_node . arguments ) # rubocop:disable Development/ContextIsPassedCop
156180
157- @field_results = @field_definition . resolve_batch ( self , objects , @selections_step . query . context , arguments )
181+
182+ ctx = @selections_step . query . context
183+
184+ if ( @runner . authorizes . fetch ( @field_definition ) { @runner . authorizes [ @field_definition ] = @field_definition . authorizes? ( ctx ) } )
185+ authorized_objects = [ ]
186+ @object_is_authorized = objects . map { |o |
187+ is_authed = @field_definition . authorized? ( o , @arguments , ctx )
188+ if is_authed
189+ authorized_objects << o
190+ end
191+ is_authed
192+ }
193+ else
194+ authorized_objects = objects
195+ @object_is_authorized = AlwaysAuthorized
196+ end
197+
198+ @field_results = @field_definition . resolve_batch ( self , authorized_objects , ctx , @arguments )
158199
159200 if @runner . resolves_lazies # TODO extract this
160201 lazies = false
@@ -205,8 +246,14 @@ def build_results
205246 is_list = return_type . list?
206247 is_non_null = return_type . non_null?
207248 results = @selections_step . results
208- @field_results . each_with_index do |result , i |
209- result_h = results [ i ]
249+ field_result_idx = 0
250+ results . each_with_index do |result_h , i |
251+ if @object_is_authorized [ i ]
252+ result = @field_results [ field_result_idx ]
253+ field_result_idx += 1
254+ else
255+ result = nil
256+ end
210257 build_graphql_result ( result_h , @key , result , return_type , is_non_null , is_list , false )
211258 end
212259 @enqueued_authorization = true
@@ -219,22 +266,25 @@ def build_results
219266 else
220267 results = @selections_step . results
221268 ctx = @selections_step . query . context
222- @field_results . each_with_index do |result , i |
223- result_h = results [ i ]
224- result_h [ @key ] = if result . nil?
269+ field_result_idx = 0
270+ results . each_with_index do |result_h , i |
271+ if @object_is_authorized [ i ]
272+ field_result = @field_results [ field_result_idx ]
273+ field_result_idx += 1
274+ else
275+ field_result = nil
276+ end
277+ result_h [ @key ] = if field_result . nil?
225278 if return_type . non_null?
226279 add_non_null_error ( false )
227280 else
228281 nil
229282 end
230- elsif result . is_a? ( GraphQL ::Error )
231- result . path = path
232- result . ast_nodes = ast_nodes
233- ctx . add_error ( result )
234- result
283+ elsif field_result . is_a? ( GraphQL ::Error )
284+ add_graphql_error ( field_result )
235285 else
236286 # TODO `nil`s in [T!] types aren't handled
237- return_type . coerce_result ( result , ctx )
287+ return_type . coerce_result ( field_result , ctx )
238288 end
239289 end
240290 end
@@ -308,10 +358,7 @@ def build_graphql_result(graphql_result, key, field_result, return_type, is_nn,
308358 graphql_result [ key ] = nil
309359 end
310360 elsif field_result . is_a? ( GraphQL ::Error )
311- field_result . path = path
312- field_result . ast_nodes = ast_nodes
313- @selections_step . query . context . add_error ( field_result )
314- graphql_result [ key ] = field_result
361+ graphql_result [ key ] = add_graphql_error ( field_result )
315362 elsif is_list
316363 if is_nn
317364 return_type = return_type . of_type
0 commit comments