graphql 2.6.13 → 2.6.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36d986ef7f7b1916194937668e714823fcc92844d9cbbd3adebad6fae134f9ff
4
- data.tar.gz: 84b4da9a3b9fc6c56cf6b8a5629567609a91c50eae60ac8ac825218cd0f73d4c
3
+ metadata.gz: 33d067b80170a8be730630eb60106962726899c114a50d397559d5ccbb274dd4
4
+ data.tar.gz: 5d5d69c98b1461f7e9d50e45b615a6078155c3b15e1af0dfc51d46d49364064d
5
5
  SHA512:
6
- metadata.gz: 2ecdf1096d357f3413087513d2076d2e6ed8d56c29cc9a535b24f2b8d16df88055abec49b2dbf423c315dbbfe0f58a30b0e9507c6a6d63152e77c949e53a3c70
7
- data.tar.gz: e19b69ee6bcf4db6f58f53e990ba8aa9ca5a70e0b8dce3174ae2ca10f62226d7fc12a75a3d3f74f521094453ab37f724c225477173bd42c8ede70269809a701b
6
+ metadata.gz: b77a04ebe1d0da2e9edd7e5af4f8218f6c25676893af1985cde457b99696345751c620fd803fedd78910bf9a8978aa34418898014c7393ea2f0e35b36b22594e
7
+ data.tar.gz: 3d3888e23a431bdbd67075eeacbdb082a461c46573946a8d46b228c2b53a686ccd5ba57f25919290e05240a60371063efa80eb8946459b5549c494e54fe5b407
@@ -8,7 +8,7 @@ module GraphQL
8
8
  def result
9
9
  return if subject.max_complexity.nil?
10
10
 
11
- total_complexity = max_possible_complexity
11
+ total_complexity = super
12
12
 
13
13
  if total_complexity > subject.max_complexity
14
14
  GraphQL::AnalysisError.new("Query has complexity of #{total_complexity}, which exceeds max complexity of #{subject.max_complexity}")
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
- # typed: false
2
+ # typed: true
3
3
  module GraphQL
4
4
  module Execution
5
5
  class FieldResolveStep
@@ -26,6 +26,8 @@ module GraphQL
26
26
  @finish_extension_idx = nil
27
27
  @was_scoped = nil
28
28
  @pending_steps = nil
29
+ @field_authorization_objects = @field_authorization_results = @field_authorization_errors = nil
30
+ @field_authorization_next_idx = @field_authorization_pending = nil
29
31
  @arguments_without_loads = @post_processors = @directive_finalizers = nil
30
32
  end
31
33
 
@@ -94,6 +96,12 @@ module GraphQL
94
96
  finish_extensions
95
97
  elsif @field_results
96
98
  build_results
99
+ elsif @field_authorization_results
100
+ if @field_authorization_next_idx < @field_authorization_objects.size
101
+ authorize_next_field_object
102
+ else
103
+ finish_field_authorizations
104
+ end
97
105
  elsif @arguments
98
106
  execute_field
99
107
  else
@@ -118,7 +126,7 @@ module GraphQL
118
126
  @runner.add_finalizer(@selections_step.query, result, key, err)
119
127
  if !err.is_a?(GraphQL::Execution::Skip)
120
128
  field_type = return_type
121
- should_propagate_null = field_type.non_null?
129
+ should_propagate_null = field_type.non_null? #: bool
122
130
  while (should_propagate_null == false && field_type.kind.wraps?)
123
131
  field_type = field_type.of_type
124
132
  should_propagate_null = field_type.non_null?
@@ -131,10 +139,10 @@ module GraphQL
131
139
  end
132
140
 
133
141
  def propagate_nulls
134
- propagating_null = true
142
+ propagating_null = true #: bool
135
143
  highest_nulled_depth = path.size
136
- highest_list_depth = nil
137
- current_field_step = self
144
+ highest_list_depth = nil #: Integer?
145
+ current_field_step = self #: FieldResolveStep?
138
146
  while current_field_step && current_field_step.field_definition
139
147
  return_type = current_field_step.field_definition.type
140
148
  if propagating_null && return_type.non_null?
@@ -151,7 +159,7 @@ module GraphQL
151
159
  end
152
160
 
153
161
  if highest_list_depth.nil? || highest_nulled_depth <= highest_list_depth
154
- kill_field_step = self
162
+ kill_field_step = self #: FieldResolveStep?
155
163
  while kill_field_step && kill_field_step.field_definition && highest_nulled_depth <= kill_field_step.path.size
156
164
  kill_field_step.selections_step.killed = true
157
165
  kill_field_step = kill_field_step.selections_step.field_resolve_step
@@ -243,153 +251,30 @@ module GraphQL
243
251
  end
244
252
 
245
253
  if @runner.authorizes?(@field_definition, ctx)
246
- authorized_objects = []
247
- authorized_results = []
248
- l = objects.size
249
- i = 0
250
- while i < l
251
- o = objects[i]
252
- err = nil
253
- begin
254
- field_authed = @field_definition.authorized?(o, @arguments, ctx)
255
- if @runner.resolves_lazies && @runner.lazy?(field_authed)
256
- # TODO batch this properly...
257
- field_authed = sync(field_authed)
258
- end
259
- rescue GraphQL::UnauthorizedFieldError => field_auth_err
260
- err = field_auth_err
261
- err.field ||= @field_definition
262
- field_authed = false
263
- end
264
-
265
- if field_authed
266
- authorized_results << @results[i]
267
- authorized_objects << o
268
- else
269
- begin
270
- err ||= GraphQL::UnauthorizedFieldError.new(object: o, type: @parent_type, context: ctx, field: @field_definition)
271
- new_obj = query.schema.unauthorized_field(err)
272
- if !new_obj.nil?
273
- authorized_objects << new_obj
274
- authorized_results << @results[i]
275
- end
276
- rescue GraphQL::ExecutionError => exec_err
277
- add_graphql_error(@results[i], key, exec_err)
278
- end
279
- end
280
- i += 1
281
- end
282
-
283
- if authorized_objects.size == 0
254
+ @field_authorization_objects = objects
255
+ @field_authorization_results = Array.new(objects.size)
256
+ @field_authorization_next_idx = 0
257
+ if objects.size > 1 && !@runner.dataloader.is_a?(GraphQL::Dataloader::NullDataloader)
258
+ # Enqueue this step once per object, so Dataloader sources loaded by `authorized?` batch across objects.
259
+ # Each call authorizes the next object; see `authorize_next_field_object`.
260
+ @field_authorization_pending = objects.size
261
+ objects.size.times { @runner.dataloader.append_job(self) }
284
262
  return
285
263
  end
286
- @results = authorized_results
264
+ objects.size.times { |idx| authorize_field_at(idx, ctx) }
265
+ authorized_objects = collect_field_authorizations
266
+ return if authorized_objects.nil?
287
267
  else
288
268
  authorized_objects = objects
289
269
  end
290
270
 
291
- if @parent_type.default_relay? && SCOPED_RELAY_FIELD_NAMES.include?(@field_definition.original_name) && authorized_objects.all? { |o| o.respond_to?(:was_authorized_by_scope_items?) && o.was_authorized_by_scope_items? }
292
- @was_scoped = true
293
- end
294
-
295
- query.current_trace.begin_execute_field(@field_definition, authorized_objects, @arguments, query)
296
-
297
- if @runner.uses_runtime_directives
298
- if @ast_nodes.nil? || @ast_nodes.size == 1
299
- directives = if !@ast_node.directives.empty?
300
- @ast_node.directives
301
- else
302
- nil
303
- end
304
- else
305
- directives = nil
306
- @ast_nodes.each do |n|
307
- if (d = n.directives).any? # rubocop:disable Development/NoneWithoutBlockCop
308
- directives ||= []
309
- directives.concat(d)
310
- end
311
- end
312
- end
313
-
314
- if directives
315
- directives.each do |dir_node|
316
- if (dir_defn = @runner.runtime_directives[dir_node.name])
317
- dir_args, errors = @runner.input_values[query].argument_values(dir_defn, dir_node.arguments, self) # rubocop:disable Development/ContextIsPassedCop
318
- if errors
319
- @results.each { |r| r.delete(@key) }
320
- errors.each { |e| e.ast_node = dir_node }
321
- build_errors_result(errors, nil)
322
- return
323
- else
324
- begin
325
- dir_defn.validate!(dir_args, query.context)
326
- if !(result = dir_defn.resolve_field(ast_nodes, @parent_type, field_definition, authorized_objects, dir_args, ctx)).nil?
327
- if result.is_a?(Finalizer)
328
- result.path = path
329
- @directive_finalizers ||= []
330
- @directive_finalizers << result
331
- end
332
-
333
- if result.is_a?(PostProcessor)
334
- @post_processors ||= []
335
- @post_processors << result
336
- end
337
-
338
- if result.is_a?(HaltExecution)
339
- @directive_finalizers&.each { |f|
340
- @selections_step.results.each { |r| @runner.add_finalizer(query, r, key, f) }
341
- }
342
- return
343
- end
344
- end
345
- rescue GraphQL::RuntimeError => err
346
- err.ast_node = dir_node
347
- raise
348
- end
349
- end
350
- end
351
- end
352
- end
353
- end
354
-
355
- has_extensions = @field_definition.extensions.size > 0
356
- if has_extensions
357
- @extended = GraphQL::Schema::Field::ExtendedState.new(@arguments, authorized_objects)
358
- @field_results = @field_definition.run_next_extensions_before_resolve(authorized_objects, @arguments, ctx, @extended) do |objs, args|
359
- if (added_extras = @extended.added_extras)
360
- args = args.dup
361
- added_extras.each { |e| args.delete(e) }
362
- end
363
- resolve_batch(objs, ctx, args)
364
- end
365
- @finish_extension_idx = 0
366
- else
367
- @field_results = resolve_batch(authorized_objects, ctx, @arguments)
368
- end
369
-
370
- query.current_trace.end_execute_field(@field_definition, authorized_objects, @arguments, query, @field_results)
371
-
372
- if any_lazy_results?
373
- @runner.dataloader.lazy_at_depth(path.size, self)
374
- elsif @pending_steps.nil? || @pending_steps.empty?
375
- if has_extensions
376
- finish_extensions
377
- else
378
- build_results
379
- end
380
- end
381
- rescue GraphQL::ExecutionError => err
382
- build_errors_result(nil, err)
383
- rescue StandardError => stderr
384
- begin
385
- @selections_step.query.handle_or_reraise(stderr, field: @field_definition, arguments: @arguments, object: nil)
386
- rescue GraphQL::ExecutionError => err
387
- add_graphql_error(@results[0], key, err)
388
- end
271
+ execute_authorized_field(authorized_objects)
272
+ rescue StandardError => err
273
+ handle_execute_field_error(err)
389
274
  end
390
275
 
391
276
  def any_lazy_results?
392
- lazies = false
277
+ lazies = false #: bool
393
278
  if @runner.resolves_lazies # TODO extract this
394
279
  @field_results.each do |field_result|
395
280
  if @runner.lazy?(field_result)
@@ -621,7 +506,7 @@ module GraphQL
621
506
  # Preserve existing messages for single-level lists.
622
507
  element_type = return_type.of_type if list_type.of_type.list?
623
508
  end
624
- err = @parent_type::InvalidNullError.new(@parent_type, @field_definition, ast_nodes, is_from_array: is_from_array, path: path, element_type: element_type)
509
+ err = @parent_type.const_get(:InvalidNullError).new(@parent_type, @field_definition, ast_nodes, is_from_array: is_from_array, path: path, element_type: element_type)
625
510
  nn_result = @runner.schema.type_error(err, @selections_step.query.context)
626
511
  if nn_result.nil?
627
512
  propagate_nulls
@@ -635,6 +520,207 @@ module GraphQL
635
520
 
636
521
  private
637
522
 
523
+ def execute_authorized_field(authorized_objects)
524
+ query = @selections_step.query
525
+ ctx = query.context
526
+
527
+ if @parent_type.default_relay? && SCOPED_RELAY_FIELD_NAMES.include?(@field_definition.original_name) && authorized_objects.all? { |o| o.respond_to?(:was_authorized_by_scope_items?) && o.was_authorized_by_scope_items? }
528
+ @was_scoped = true
529
+ end
530
+
531
+ query.current_trace.begin_execute_field(@field_definition, authorized_objects, @arguments, query)
532
+
533
+ if @runner.uses_runtime_directives
534
+ if @ast_nodes.nil? || @ast_nodes.size == 1
535
+ directives = if !@ast_node.directives.empty?
536
+ @ast_node.directives
537
+ else
538
+ nil
539
+ end
540
+ else
541
+ directives = nil #: Array[untyped]?
542
+ @ast_nodes.each do |n|
543
+ if (d = n.directives).any? # rubocop:disable Development/NoneWithoutBlockCop
544
+ directives ||= []
545
+ directives.concat(d)
546
+ end
547
+ end
548
+ end
549
+
550
+ if directives
551
+ directives.each do |dir_node|
552
+ if (dir_defn = @runner.runtime_directives[dir_node.name])
553
+ dir_args, errors = @runner.input_values[query].argument_values(dir_defn, dir_node.arguments, self) # rubocop:disable Development/ContextIsPassedCop
554
+ if errors
555
+ @results.each { |r| r.delete(@key) }
556
+ errors.each { |e| e.ast_node = dir_node }
557
+ build_errors_result(errors, nil)
558
+ return
559
+ else
560
+ begin
561
+ dir_defn.validate!(dir_args, query.context)
562
+ if !(result = dir_defn.resolve_field(ast_nodes, @parent_type, field_definition, authorized_objects, dir_args, ctx)).nil?
563
+ if result.is_a?(Finalizer)
564
+ result.path = path
565
+ @directive_finalizers ||= []
566
+ @directive_finalizers << result
567
+ end
568
+
569
+ if result.is_a?(PostProcessor)
570
+ @post_processors ||= []
571
+ @post_processors << result
572
+ end
573
+
574
+ if result.is_a?(HaltExecution)
575
+ @directive_finalizers&.each { |f|
576
+ @selections_step.results.each { |r| @runner.add_finalizer(query, r, key, f) }
577
+ }
578
+ return
579
+ end
580
+ end
581
+ rescue GraphQL::RuntimeError => err
582
+ err.ast_node = dir_node
583
+ raise
584
+ end
585
+ end
586
+ end
587
+ end
588
+ end
589
+ end
590
+
591
+ has_extensions = @field_definition.extensions.size > 0
592
+ if has_extensions
593
+ @extended = GraphQL::Schema::Field::ExtendedState.new(@arguments, authorized_objects)
594
+ @field_results = @field_definition.run_next_extensions_before_resolve(authorized_objects, @arguments, ctx, @extended) do |objs, args|
595
+ if (added_extras = @extended.added_extras)
596
+ args = args.dup
597
+ added_extras.each { |e| args.delete(e) }
598
+ end
599
+ resolve_batch(objs, ctx, args)
600
+ end
601
+ @finish_extension_idx = 0
602
+ else
603
+ @field_results = resolve_batch(authorized_objects, ctx, @arguments)
604
+ end
605
+
606
+ query.current_trace.end_execute_field(@field_definition, authorized_objects, @arguments, query, @field_results)
607
+
608
+ if any_lazy_results?
609
+ @runner.dataloader.lazy_at_depth(path.size, self)
610
+ elsif @pending_steps.nil? || @pending_steps.empty?
611
+ if has_extensions
612
+ finish_extensions
613
+ else
614
+ build_results
615
+ end
616
+ end
617
+ rescue StandardError => err
618
+ handle_execute_field_error(err)
619
+ end
620
+
621
+ def handle_execute_field_error(err)
622
+ if @field_authorization_objects
623
+ clear_field_authorizations
624
+ end
625
+ if err.is_a?(GraphQL::ExecutionError)
626
+ build_errors_result(nil, err)
627
+ else
628
+ begin
629
+ @selections_step.query.handle_or_reraise(err, field: @field_definition, arguments: @arguments, object: nil)
630
+ rescue GraphQL::ExecutionError => exec_err
631
+ add_graphql_error(@results[0], key, exec_err)
632
+ end
633
+ end
634
+ end
635
+
636
+ # Stores the (possibly synced) +authorized?+ result for the object at +idx+.
637
+ # A GraphQL::UnauthorizedFieldError raised by +authorized?+ is stored in +@field_authorization_errors+.
638
+ def authorize_field_at(idx, ctx)
639
+ field_authed = @field_definition.authorized?(@field_authorization_objects[idx], @arguments, ctx)
640
+ if @runner.resolves_lazies && @runner.lazy?(field_authed)
641
+ field_authed = sync(field_authed)
642
+ end
643
+ @field_authorization_results[idx] = field_authed
644
+ rescue GraphQL::UnauthorizedFieldError => field_auth_err
645
+ field_auth_err.field ||= @field_definition
646
+ (@field_authorization_errors ||= {})[idx] = field_auth_err
647
+ end
648
+
649
+ # Runs once for each time this step was enqueued for field authorization.
650
+ # The index is taken before +authorized?+ runs, so it's still correct if this Fiber pauses.
651
+ # When the last object is done, the step is enqueued again to call +finish_field_authorizations+.
652
+ def authorize_next_field_object
653
+ idx = @field_authorization_next_idx
654
+ @field_authorization_next_idx += 1
655
+ begin
656
+ authorize_field_at(idx, @selections_step.query.context)
657
+ rescue StandardError => err
658
+ (@field_authorization_errors ||= {})[idx] = err
659
+ end
660
+ @field_authorization_pending -= 1
661
+ if @field_authorization_pending == 0
662
+ @runner.add_step(self)
663
+ end
664
+ end
665
+
666
+ def finish_field_authorizations
667
+ if (errors = @field_authorization_errors)
668
+ @field_authorization_objects.size.times do |idx|
669
+ err = errors[idx]
670
+ if err && !err.is_a?(GraphQL::UnauthorizedFieldError)
671
+ raise err
672
+ end
673
+ end
674
+ end
675
+ authorized_objects = collect_field_authorizations
676
+ if authorized_objects
677
+ execute_authorized_field(authorized_objects)
678
+ end
679
+ rescue StandardError => err
680
+ handle_execute_field_error(err)
681
+ end
682
+
683
+ def clear_field_authorizations
684
+ @field_authorization_objects = @field_authorization_results = @field_authorization_errors = nil
685
+ @field_authorization_next_idx = @field_authorization_pending = nil
686
+ end
687
+
688
+ # Applies +unauthorized_field+ for denied objects, in object order.
689
+ # Returns the objects to resolve, or +nil+ if none are left.
690
+ def collect_field_authorizations
691
+ objects = @field_authorization_objects
692
+ auth_results = @field_authorization_results
693
+ errors = @field_authorization_errors
694
+ clear_field_authorizations
695
+ ctx = @selections_step.query.context
696
+ authorized_objects = []
697
+ authorized_results = []
698
+ objects.each_with_index do |o, i|
699
+ err = errors && errors[i]
700
+ if !err && auth_results[i]
701
+ authorized_results << @results[i]
702
+ authorized_objects << o
703
+ else
704
+ begin
705
+ err ||= GraphQL::UnauthorizedFieldError.new(object: o, type: @parent_type, context: ctx, field: @field_definition)
706
+ new_obj = ctx.schema.unauthorized_field(err)
707
+ if !new_obj.nil?
708
+ authorized_objects << new_obj
709
+ authorized_results << @results[i]
710
+ end
711
+ rescue GraphQL::ExecutionError => exec_err
712
+ add_graphql_error(@results[i], key, exec_err)
713
+ end
714
+ end
715
+ end
716
+
717
+ if authorized_objects.size == 0
718
+ return nil
719
+ end
720
+ @results = authorized_results
721
+ authorized_objects
722
+ end
723
+
638
724
  def build_graphql_result(graphql_result, key, field_result, return_type, is_nn, is_list, is_from_array) # rubocop:disable Metrics/ParameterLists
639
725
  if field_result.nil?
640
726
  if is_nn
@@ -712,25 +798,25 @@ module GraphQL
712
798
  when :resolve_batch
713
799
  begin
714
800
  method_receiver.public_send(@field_definition.execution_mode_key, objects, context, **args_hash)
715
- rescue GraphQL::ExecutionError => exec_err
716
- error_instance_array(objects.size, exec_err)
717
- rescue StandardError => stderr
801
+ rescue GraphQL::ExecutionError => batch_err
802
+ error_instance_array(objects.size, batch_err)
803
+ rescue StandardError => batch_stderr
718
804
  begin
719
- context.query.handle_or_reraise(stderr, field: @field_definition, arguments: @arguments, object: nil)
720
- rescue GraphQL::ExecutionError => exec_err
721
- error_instance_array(objects.size, exec_err)
805
+ context.query.handle_or_reraise(batch_stderr, field: @field_definition, arguments: @arguments, object: nil)
806
+ rescue GraphQL::ExecutionError => batch_err
807
+ error_instance_array(objects.size, batch_err)
722
808
  end
723
809
  end
724
810
  when :resolve_static
725
811
  result = begin
726
812
  method_receiver.public_send(@field_definition.execution_mode_key, context, **args_hash)
727
- rescue GraphQL::ExecutionError => err
728
- err
729
- rescue StandardError => stderr
813
+ rescue GraphQL::ExecutionError => static_err
814
+ static_err
815
+ rescue StandardError => static_stderr
730
816
  begin
731
- context.query.handle_or_reraise(stderr, field: @field_definition, arguments: @arguments, object: nil)
732
- rescue GraphQL::ExecutionError => err
733
- err
817
+ context.query.handle_or_reraise(static_stderr, field: @field_definition, arguments: @arguments, object: nil)
818
+ rescue GraphQL::ExecutionError => static_err
819
+ static_err
734
820
  end
735
821
  end
736
822
  Array.new(objects.size, result)
@@ -183,7 +183,9 @@ module GraphQL
183
183
  arg_value = begin
184
184
  argument_definition.prepare_value(nil, arg_value, context: @query.context)
185
185
  rescue StandardError => err
186
- @runner.schema.handle_or_reraise(@query.context, err, object: nil, arguments: argument_values, field: field_resolve_step&.field_definition)
186
+ handled_err = @runner.schema.handle_or_reraise(@query.context, err, object: nil, arguments: argument_values, field: field_resolve_step&.field_definition)
187
+ raise handled_err if handled_err.is_a?(GraphQL::RuntimeError)
188
+ handled_err
187
189
  end
188
190
  end
189
191
 
@@ -14,6 +14,7 @@ module GraphQL
14
14
  @resolved_type = nil
15
15
  @authorized_value = nil
16
16
  @authorization_error = nil
17
+ @execution_error = nil
17
18
  @key = key
18
19
  @next_step = :resolve_type
19
20
  @is_from_array = is_from_array
@@ -24,7 +25,12 @@ module GraphQL
24
25
  if @authorized_value
25
26
  query = @field_resolve_step.selections_step.query
26
27
  query.current_trace.begin_authorized(@resolved_type, @object, query.context)
27
- @authorized_value = @field_resolve_step.sync(@authorized_value)
28
+ begin
29
+ @authorized_value = @runner.schema.sync_lazy(@authorized_value)
30
+ rescue StandardError => err
31
+ @authorized_value = nil
32
+ handle_authorization_error(err, query)
33
+ end
28
34
  query.current_trace.end_authorized(@resolved_type, @object, query.context, @authorized_value)
29
35
  elsif @resolved_type
30
36
  ctx = @field_resolve_step.selections_step.query.context
@@ -90,8 +96,9 @@ module GraphQL
90
96
  query.current_trace.begin_authorized(@resolved_type, @object, query.context)
91
97
  @authorized_value = @resolved_type.authorized?(@object, query.context)
92
98
  query.current_trace.end_authorized(@resolved_type, @object, query.context, @authorized_value)
93
- rescue GraphQL::UnauthorizedError => auth_err
94
- @authorization_error = auth_err
99
+ rescue StandardError => err
100
+ @authorized_value = nil
101
+ handle_authorization_error(err, query)
95
102
  end
96
103
 
97
104
  if @runner.resolves_lazies && @runner.lazy?(@authorized_value)
@@ -100,19 +107,14 @@ module GraphQL
100
107
  else
101
108
  create_result
102
109
  end
103
- rescue GraphQL::RuntimeError => err
104
- @graphql_result[@key] = add_field_error(err)
105
- rescue StandardError => err
106
- query ||= @field_resolve_step.selections_step.query
107
- begin
108
- query.handle_or_reraise(err, field: @field_resolve_step.field_definition, arguments: @field_resolve_step.arguments, object: @object) # rubocop:disable Development/ContextIsPassedCop
109
- rescue GraphQL::RuntimeError => err
110
- @graphql_result[@key] = add_field_error(err)
111
- end
112
110
  end
113
111
 
114
112
  def create_result
115
- if !@authorized_value
113
+ if @execution_error
114
+ # `.authorized?` raised (or its lazy value raised) an error other than UnauthorizedError:
115
+ # it isn't an authorization decision, so don't call `unauthorized_object`.
116
+ @graphql_result[@key] = add_field_error(@execution_error)
117
+ elsif !@authorized_value
116
118
  @authorization_error ||= GraphQL::UnauthorizedError.new(object: @object, type: @resolved_type, context: @field_resolve_step.selections_step.query.context)
117
119
  end
118
120
 
@@ -147,6 +149,28 @@ module GraphQL
147
149
 
148
150
  @field_resolve_step.authorized_finished(self)
149
151
  end
152
+
153
+ private
154
+
155
+ # Errors raised by `.authorized?` (or by syncing its lazy return value):
156
+ #
157
+ # - `UnauthorizedError` is equivalent to returning `false`, so it goes to `unauthorized_object`
158
+ # - Other `GraphQL::RuntimeError`s are added to the response for this field
159
+ # - Other errors go to `rescue_from` handlers, which might return a `GraphQL::RuntimeError`, or else re-raise
160
+ def handle_authorization_error(err, query)
161
+ case err
162
+ when GraphQL::UnauthorizedError
163
+ @authorization_error = err
164
+ when GraphQL::RuntimeError
165
+ @execution_error = err
166
+ else
167
+ begin
168
+ @authorized_value = query.handle_or_reraise(err, field: @field_resolve_step.field_definition, arguments: @field_resolve_step.arguments, object: @object) # rubocop:disable Development/ContextIsPassedCop
169
+ rescue GraphQL::RuntimeError => runtime_err
170
+ handle_authorization_error(runtime_err, query)
171
+ end
172
+ end
173
+ end
150
174
  end
151
175
  end
152
176
  end
@@ -197,7 +197,7 @@ module GraphQL
197
197
  raise GraphQL::ParseError.new(message, line, col, @string, filename: @filename)
198
198
  end
199
199
 
200
- IGNORE_REGEXP = /[, \c\r\n\t]+/
200
+ IGNORE_REGEXP = /[, \r\n\t\uFEFF]+/
201
201
  COMMENT_REGEXP = /\#[^\n]*/
202
202
  IDENTIFIER_REGEXP = /[_A-Za-z][_0-9A-Za-z]*/
203
203
  INT_REGEXP = /-?(?:[0]|[1-9][0-9]*)/
@@ -370,7 +370,11 @@ module GraphQL
370
370
  input_fields_definition = parse_input_object_field_definitions
371
371
  InputObjectTypeDefinition.new(pos: loc, definition_pos: defn_loc, description: desc, name: name, directives: directives, fields: input_fields_definition, filename: @filename, source: self)
372
372
  else
373
- expect_one_of([:SCHEMA, :SCALAR, :TYPE, :ENUM, :INPUT, :UNION, :INTERFACE])
373
+ expected_tokens = [:SCHEMA, :SCALAR, :TYPE, :ENUM, :INPUT, :UNION, :INTERFACE, :DIRECTIVE]
374
+ if desc.nil?
375
+ expected_tokens.unshift(:QUERY, :MUTATION, :SUBSCRIPTION, :FRAGMENT, :LCURLY, :EXTEND, :STRING)
376
+ end
377
+ expect_one_of(expected_tokens)
374
378
  end
375
379
  end
376
380
  end