graphql 1.12.24 → 1.13.19

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.

Potentially problematic release.


This version of graphql might be problematic. Click here for more details.

Files changed (189) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +3 -8
  3. data/lib/generators/graphql/enum_generator.rb +4 -10
  4. data/lib/generators/graphql/field_extractor.rb +31 -0
  5. data/lib/generators/graphql/input_generator.rb +50 -0
  6. data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
  7. data/lib/generators/graphql/install_generator.rb +10 -3
  8. data/lib/generators/graphql/interface_generator.rb +7 -7
  9. data/lib/generators/graphql/mutation_create_generator.rb +22 -0
  10. data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
  11. data/lib/generators/graphql/mutation_generator.rb +5 -30
  12. data/lib/generators/graphql/mutation_update_generator.rb +22 -0
  13. data/lib/generators/graphql/object_generator.rb +8 -37
  14. data/lib/generators/graphql/orm_mutations_base.rb +40 -0
  15. data/lib/generators/graphql/scalar_generator.rb +4 -2
  16. data/lib/generators/graphql/templates/enum.erb +5 -1
  17. data/lib/generators/graphql/templates/input.erb +9 -0
  18. data/lib/generators/graphql/templates/interface.erb +4 -2
  19. data/lib/generators/graphql/templates/mutation.erb +1 -1
  20. data/lib/generators/graphql/templates/mutation_create.erb +20 -0
  21. data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
  22. data/lib/generators/graphql/templates/mutation_update.erb +21 -0
  23. data/lib/generators/graphql/templates/object.erb +4 -2
  24. data/lib/generators/graphql/templates/scalar.erb +3 -1
  25. data/lib/generators/graphql/templates/union.erb +4 -2
  26. data/lib/generators/graphql/type_generator.rb +46 -10
  27. data/lib/generators/graphql/union_generator.rb +5 -5
  28. data/lib/graphql/analysis/ast/field_usage.rb +2 -2
  29. data/lib/graphql/analysis/ast/query_complexity.rb +10 -14
  30. data/lib/graphql/analysis/ast/visitor.rb +5 -4
  31. data/lib/graphql/argument.rb +1 -1
  32. data/lib/graphql/backtrace/table.rb +1 -1
  33. data/lib/graphql/base_type.rb +5 -3
  34. data/lib/graphql/boolean_type.rb +1 -1
  35. data/lib/graphql/dataloader/source.rb +2 -2
  36. data/lib/graphql/dataloader.rb +55 -22
  37. data/lib/graphql/date_encoding_error.rb +16 -0
  38. data/lib/graphql/define/instance_definable.rb +15 -0
  39. data/lib/graphql/directive/deprecated_directive.rb +1 -1
  40. data/lib/graphql/directive/include_directive.rb +1 -1
  41. data/lib/graphql/directive/skip_directive.rb +1 -1
  42. data/lib/graphql/directive.rb +1 -5
  43. data/lib/graphql/enum_type.rb +7 -3
  44. data/lib/graphql/execution/errors.rb +1 -0
  45. data/lib/graphql/execution/interpreter/arguments.rb +1 -1
  46. data/lib/graphql/execution/interpreter/arguments_cache.rb +6 -4
  47. data/lib/graphql/execution/interpreter/runtime.rb +66 -38
  48. data/lib/graphql/execution/lookahead.rb +2 -2
  49. data/lib/graphql/execution/multiplex.rb +4 -1
  50. data/lib/graphql/field.rb +1 -1
  51. data/lib/graphql/float_type.rb +1 -1
  52. data/lib/graphql/id_type.rb +1 -1
  53. data/lib/graphql/input_object_type.rb +1 -1
  54. data/lib/graphql/int_type.rb +1 -1
  55. data/lib/graphql/interface_type.rb +1 -1
  56. data/lib/graphql/introspection/directive_location_enum.rb +2 -2
  57. data/lib/graphql/introspection/directive_type.rb +5 -3
  58. data/lib/graphql/introspection/entry_points.rb +2 -2
  59. data/lib/graphql/introspection/enum_value_type.rb +2 -2
  60. data/lib/graphql/introspection/field_type.rb +3 -3
  61. data/lib/graphql/introspection/input_value_type.rb +4 -4
  62. data/lib/graphql/introspection/schema_type.rb +9 -4
  63. data/lib/graphql/introspection/type_type.rb +18 -12
  64. data/lib/graphql/introspection.rb +4 -1
  65. data/lib/graphql/language/block_string.rb +2 -6
  66. data/lib/graphql/language/document_from_schema_definition.rb +11 -4
  67. data/lib/graphql/language/lexer.rb +50 -28
  68. data/lib/graphql/language/lexer.rl +2 -4
  69. data/lib/graphql/language/nodes.rb +4 -3
  70. data/lib/graphql/language/parser.rb +841 -820
  71. data/lib/graphql/language/parser.y +13 -6
  72. data/lib/graphql/language/printer.rb +10 -1
  73. data/lib/graphql/language/sanitized_printer.rb +5 -5
  74. data/lib/graphql/language/token.rb +0 -4
  75. data/lib/graphql/name_validator.rb +0 -4
  76. data/lib/graphql/object_type.rb +2 -2
  77. data/lib/graphql/pagination/active_record_relation_connection.rb +43 -6
  78. data/lib/graphql/pagination/relation_connection.rb +59 -29
  79. data/lib/graphql/query/arguments.rb +1 -1
  80. data/lib/graphql/query/arguments_cache.rb +1 -1
  81. data/lib/graphql/query/context.rb +15 -2
  82. data/lib/graphql/query/input_validation_result.rb +9 -0
  83. data/lib/graphql/query/literal_input.rb +1 -1
  84. data/lib/graphql/query/null_context.rb +12 -7
  85. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -1
  86. data/lib/graphql/query/validation_pipeline.rb +2 -3
  87. data/lib/graphql/query/variable_validation_error.rb +2 -2
  88. data/lib/graphql/query/variables.rb +35 -4
  89. data/lib/graphql/query.rb +0 -1
  90. data/lib/graphql/relay/connection_type.rb +15 -2
  91. data/lib/graphql/relay/edges_instrumentation.rb +0 -1
  92. data/lib/graphql/relay/global_id_resolve.rb +1 -2
  93. data/lib/graphql/relay/mutation.rb +1 -1
  94. data/lib/graphql/relay/page_info.rb +1 -1
  95. data/lib/graphql/relay/range_add.rb +4 -0
  96. data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
  97. data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
  98. data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
  99. data/lib/graphql/rubocop.rb +4 -0
  100. data/lib/graphql/scalar_type.rb +1 -1
  101. data/lib/graphql/schema/addition.rb +37 -28
  102. data/lib/graphql/schema/argument.rb +30 -15
  103. data/lib/graphql/schema/build_from_definition.rb +6 -5
  104. data/lib/graphql/schema/directive/feature.rb +1 -1
  105. data/lib/graphql/schema/directive/flagged.rb +2 -2
  106. data/lib/graphql/schema/directive/include.rb +1 -1
  107. data/lib/graphql/schema/directive/skip.rb +1 -1
  108. data/lib/graphql/schema/directive/transform.rb +1 -1
  109. data/lib/graphql/schema/directive.rb +23 -4
  110. data/lib/graphql/schema/enum.rb +61 -12
  111. data/lib/graphql/schema/enum_value.rb +6 -0
  112. data/lib/graphql/schema/field/connection_extension.rb +1 -1
  113. data/lib/graphql/schema/field.rb +261 -83
  114. data/lib/graphql/schema/field_extension.rb +89 -2
  115. data/lib/graphql/schema/find_inherited_value.rb +1 -0
  116. data/lib/graphql/schema/finder.rb +5 -5
  117. data/lib/graphql/schema/input_object.rb +24 -7
  118. data/lib/graphql/schema/interface.rb +11 -20
  119. data/lib/graphql/schema/introspection_system.rb +1 -1
  120. data/lib/graphql/schema/list.rb +21 -4
  121. data/lib/graphql/schema/loader.rb +3 -0
  122. data/lib/graphql/schema/member/accepts_definition.rb +15 -3
  123. data/lib/graphql/schema/member/base_dsl_methods.rb +1 -1
  124. data/lib/graphql/schema/member/build_type.rb +0 -4
  125. data/lib/graphql/schema/member/cached_graphql_definition.rb +29 -2
  126. data/lib/graphql/schema/member/has_arguments.rb +56 -14
  127. data/lib/graphql/schema/member/has_deprecation_reason.rb +1 -1
  128. data/lib/graphql/schema/member/has_fields.rb +76 -18
  129. data/lib/graphql/schema/member/has_interfaces.rb +100 -0
  130. data/lib/graphql/schema/member/validates_input.rb +2 -2
  131. data/lib/graphql/schema/member.rb +1 -0
  132. data/lib/graphql/schema/non_null.rb +9 -3
  133. data/lib/graphql/schema/object.rb +10 -75
  134. data/lib/graphql/schema/printer.rb +1 -1
  135. data/lib/graphql/schema/relay_classic_mutation.rb +37 -3
  136. data/lib/graphql/schema/resolver/has_payload_type.rb +27 -2
  137. data/lib/graphql/schema/resolver.rb +37 -17
  138. data/lib/graphql/schema/scalar.rb +15 -1
  139. data/lib/graphql/schema/subscription.rb +11 -1
  140. data/lib/graphql/schema/traversal.rb +1 -1
  141. data/lib/graphql/schema/type_expression.rb +1 -1
  142. data/lib/graphql/schema/type_membership.rb +18 -4
  143. data/lib/graphql/schema/union.rb +8 -1
  144. data/lib/graphql/schema/validator/format_validator.rb +0 -4
  145. data/lib/graphql/schema/validator/numericality_validator.rb +1 -0
  146. data/lib/graphql/schema/validator/required_validator.rb +29 -15
  147. data/lib/graphql/schema/validator.rb +4 -7
  148. data/lib/graphql/schema/warden.rb +126 -53
  149. data/lib/graphql/schema.rb +120 -24
  150. data/lib/graphql/static_validation/all_rules.rb +1 -0
  151. data/lib/graphql/static_validation/base_visitor.rb +6 -6
  152. data/lib/graphql/static_validation/definition_dependencies.rb +0 -1
  153. data/lib/graphql/static_validation/literal_validator.rb +1 -1
  154. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
  155. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
  156. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
  157. data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
  158. data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
  159. data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
  160. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +3 -3
  161. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -4
  162. data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +1 -1
  163. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +13 -7
  164. data/lib/graphql/static_validation/validation_context.rb +4 -0
  165. data/lib/graphql/string_type.rb +1 -1
  166. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +8 -4
  167. data/lib/graphql/subscriptions/event.rb +20 -12
  168. data/lib/graphql/subscriptions/serialize.rb +22 -2
  169. data/lib/graphql/subscriptions.rb +17 -19
  170. data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
  171. data/lib/graphql/tracing/data_dog_tracing.rb +24 -2
  172. data/lib/graphql/tracing/notifications_tracing.rb +59 -0
  173. data/lib/graphql/tracing/platform_tracing.rb +20 -10
  174. data/lib/graphql/types/iso_8601_date.rb +13 -5
  175. data/lib/graphql/types/iso_8601_date_time.rb +8 -1
  176. data/lib/graphql/types/relay/connection_behaviors.rb +28 -10
  177. data/lib/graphql/types/relay/default_relay.rb +5 -1
  178. data/lib/graphql/types/relay/edge_behaviors.rb +13 -2
  179. data/lib/graphql/types/relay/has_node_field.rb +1 -1
  180. data/lib/graphql/types/relay/has_nodes_field.rb +1 -1
  181. data/lib/graphql/types/relay/node_field.rb +2 -3
  182. data/lib/graphql/types/relay/nodes_field.rb +19 -3
  183. data/lib/graphql/types/string.rb +1 -1
  184. data/lib/graphql/union_type.rb +1 -1
  185. data/lib/graphql/version.rb +1 -1
  186. data/lib/graphql.rb +22 -32
  187. metadata +31 -11
  188. /data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +0 -0
  189. /data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +0 -0
@@ -159,7 +159,8 @@ module GraphQL
159
159
  # Identify runtime directives by checking which of this schema's directives have overridden `def self.resolve`
160
160
  @runtime_directive_names = []
161
161
  noop_resolve_owner = GraphQL::Schema::Directive.singleton_class
162
- schema.directives.each do |name, dir_defn|
162
+ @schema_directives = schema.directives
163
+ @schema_directives.each do |name, dir_defn|
163
164
  if dir_defn.method(:resolve).owner != noop_resolve_owner
164
165
  @runtime_directive_names << name
165
166
  end
@@ -206,7 +207,7 @@ module GraphQL
206
207
  # Root .authorized? returned false.
207
208
  @response = nil
208
209
  else
209
- resolve_with_directives(object_proxy, root_operation.directives) do # execute query level directives
210
+ call_method_on_directives(:resolve, object_proxy, root_operation.directives) do # execute query level directives
210
211
  gathered_selections = gather_selections(object_proxy, root_type, root_operation.selections)
211
212
  # This is kind of a hack -- `gathered_selections` is an Array if any of the selections
212
213
  # require isolation during execution (because of runtime directives). In that case,
@@ -226,7 +227,7 @@ module GraphQL
226
227
 
227
228
  @dataloader.append_job {
228
229
  set_all_interpreter_context(query.root_value, nil, nil, path)
229
- resolve_with_directives(object_proxy, selections.graphql_directives) do
230
+ call_method_on_directives(:resolve, object_proxy, selections.graphql_directives) do
230
231
  evaluate_selections(
231
232
  path,
232
233
  context.scoped_context,
@@ -314,7 +315,7 @@ module GraphQL
314
315
  case node
315
316
  when GraphQL::Language::Nodes::InlineFragment
316
317
  if node.type
317
- type_defn = schema.get_type(node.type.name)
318
+ type_defn = schema.get_type(node.type.name, context)
318
319
 
319
320
  # Faster than .map{}.include?()
320
321
  query.warden.possible_types(type_defn).each do |t|
@@ -329,7 +330,7 @@ module GraphQL
329
330
  end
330
331
  when GraphQL::Language::Nodes::FragmentSpread
331
332
  fragment_def = query.fragments[node.name]
332
- type_defn = schema.get_type(fragment_def.type.name)
333
+ type_defn = query.get_type(fragment_def.type.name)
333
334
  possible_types = query.warden.possible_types(type_defn)
334
335
  possible_types.each do |t|
335
336
  if t == owner_type
@@ -384,7 +385,9 @@ module GraphQL
384
385
  ast_node = field_ast_nodes_or_ast_node
385
386
  end
386
387
  field_name = ast_node.name
387
- field_defn = @fields_cache[owner_type][field_name] ||= owner_type.get_field(field_name)
388
+ # This can't use `query.get_field` because it gets confused on introspection below if `field_defn` isn't `nil`,
389
+ # because of how `is_introspection` is used to call `.authorized_new` later on.
390
+ field_defn = @fields_cache[owner_type][field_name] ||= owner_type.get_field(field_name, @context)
388
391
  is_introspection = false
389
392
  if field_defn.nil?
390
393
  field_defn = if owner_type == schema.query && (entry_point_field = schema.introspection_system.entry_point(name: field_name))
@@ -397,6 +400,7 @@ module GraphQL
397
400
  raise "Invariant: no field for #{owner_type}.#{field_name}"
398
401
  end
399
402
  end
403
+
400
404
  return_type = field_defn.type
401
405
 
402
406
  next_path = path.dup
@@ -419,22 +423,21 @@ module GraphQL
419
423
  object = authorized_new(field_defn.owner, object, context)
420
424
  end
421
425
 
422
- total_args_count = field_defn.arguments.size
426
+ total_args_count = field_defn.arguments(context).size
423
427
  if total_args_count == 0
424
- kwarg_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
425
- evaluate_selection_with_args(kwarg_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selections_result, parent_object)
428
+ resolved_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
429
+ evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selections_result, parent_object, return_type)
426
430
  else
427
431
  # TODO remove all arguments(...) usages?
428
432
  @query.arguments_cache.dataload_for(ast_node, field_defn, object) do |resolved_arguments|
429
- evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selections_result, parent_object)
433
+ evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selections_result, parent_object, return_type)
430
434
  end
431
435
  end
432
436
  end
433
437
 
434
- def evaluate_selection_with_args(kwarg_arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selection_result, parent_object) # rubocop:disable Metrics/ParameterLists
438
+ def evaluate_selection_with_args(arguments, field_defn, next_path, ast_node, field_ast_nodes, scoped_context, owner_type, object, is_eager_field, result_name, selection_result, parent_object, return_type) # rubocop:disable Metrics/ParameterLists
435
439
  context.scoped_context = scoped_context
436
- return_type = field_defn.type
437
- after_lazy(kwarg_arguments, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, scoped_context: context.scoped_context, owner_object: object, arguments: kwarg_arguments, result_name: result_name, result: selection_result) do |resolved_arguments|
440
+ after_lazy(arguments, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, scoped_context: context.scoped_context, owner_object: object, arguments: arguments, result_name: result_name, result: selection_result) do |resolved_arguments|
438
441
  if resolved_arguments.is_a?(GraphQL::ExecutionError) || resolved_arguments.is_a?(GraphQL::UnauthorizedError)
439
442
  continue_value(next_path, resolved_arguments, owner_type, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
440
443
  next
@@ -485,7 +488,7 @@ module GraphQL
485
488
  resolved_arguments.keyword_arguments
486
489
  end
487
490
 
488
- set_all_interpreter_context(nil, nil, kwarg_arguments, nil)
491
+ set_all_interpreter_context(nil, nil, resolved_arguments, nil)
489
492
 
490
493
  # Optimize for the case that field is selected only once
491
494
  if field_ast_nodes.nil? || field_ast_nodes.size == 1
@@ -500,7 +503,7 @@ module GraphQL
500
503
  }
501
504
  end
502
505
 
503
- field_result = resolve_with_directives(object, directives) do
506
+ field_result = call_method_on_directives(:resolve, object, directives) do
504
507
  # Actually call the field resolver and capture the result
505
508
  app_result = begin
506
509
  query.with_error_handling do
@@ -511,10 +514,10 @@ module GraphQL
511
514
  rescue GraphQL::ExecutionError => err
512
515
  err
513
516
  end
514
- after_lazy(app_result, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, scoped_context: context.scoped_context, owner_object: object, arguments: kwarg_arguments, result_name: result_name, result: selection_result) do |inner_result|
517
+ after_lazy(app_result, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, scoped_context: context.scoped_context, owner_object: object, arguments: resolved_arguments, result_name: result_name, result: selection_result) do |inner_result|
515
518
  continue_value = continue_value(next_path, inner_result, owner_type, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
516
519
  if HALT != continue_value
517
- continue_field(next_path, continue_value, owner_type, field_defn, return_type, ast_node, next_selections, false, object, kwarg_arguments, result_name, selection_result)
520
+ continue_field(next_path, continue_value, owner_type, field_defn, return_type, ast_node, next_selections, false, object, resolved_arguments, result_name, selection_result)
518
521
  end
519
522
  end
520
523
  end
@@ -637,14 +640,20 @@ module GraphQL
637
640
  when Array
638
641
  # It's an array full of execution errors; add them all.
639
642
  if value.any? && value.all? { |v| v.is_a?(GraphQL::ExecutionError) }
643
+ list_type_at_all = (field && (field.type.list?))
640
644
  if selection_result.nil? || !dead_result?(selection_result)
641
645
  value.each_with_index do |error, index|
642
646
  error.ast_node ||= ast_node
643
- error.path ||= path + ((field && field.type.list?) ? [index] : [])
647
+ error.path ||= path + (list_type_at_all ? [index] : [])
644
648
  context.errors << error
645
649
  end
646
650
  if selection_result
647
- set_result(selection_result, result_name, nil)
651
+ if list_type_at_all
652
+ result_without_errors = value.map { |v| v.is_a?(GraphQL::ExecutionError) ? nil : v }
653
+ set_result(selection_result, result_name, result_without_errors)
654
+ else
655
+ set_result(selection_result, result_name, nil)
656
+ end
648
657
  end
649
658
  end
650
659
  HALT
@@ -726,7 +735,7 @@ module GraphQL
726
735
  final_result = nil
727
736
  end
728
737
  set_all_interpreter_context(continue_value, nil, nil, path) # reset this mutable state
729
- resolve_with_directives(continue_value, selections.graphql_directives) do
738
+ call_method_on_directives(:resolve, continue_value, selections.graphql_directives) do
730
739
  evaluate_selections(
731
740
  path,
732
741
  context.scoped_context,
@@ -745,6 +754,8 @@ module GraphQL
745
754
  end
746
755
  when "LIST"
747
756
  inner_type = current_type.of_type
757
+ # This is true for objects, unions, and interfaces
758
+ use_dataloader_job = !inner_type.unwrap.kind.input?
748
759
  response_list = GraphQLResultArray.new(result_name, selection_result)
749
760
  response_list.graphql_non_null_list_items = inner_type.non_null?
750
761
  set_result(selection_result, result_name, response_list)
@@ -759,12 +770,12 @@ module GraphQL
759
770
  this_idx = idx
760
771
  next_path.freeze
761
772
  idx += 1
762
- # This will update `response_list` with the lazy
763
- after_lazy(inner_value, owner: inner_type, path: next_path, ast_node: ast_node, scoped_context: scoped_context, field: field, owner_object: owner_object, arguments: arguments, result_name: this_idx, result: response_list) do |inner_inner_value|
764
- continue_value = continue_value(next_path, inner_inner_value, owner_type, field, inner_type.non_null?, ast_node, this_idx, response_list)
765
- if HALT != continue_value
766
- continue_field(next_path, continue_value, owner_type, field, inner_type, ast_node, next_selections, false, owner_object, arguments, this_idx, response_list)
773
+ if use_dataloader_job
774
+ @dataloader.append_job do
775
+ resolve_list_item(inner_value, inner_type, next_path, ast_node, scoped_context, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type)
767
776
  end
777
+ else
778
+ resolve_list_item(inner_value, inner_type, next_path, ast_node, scoped_context, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type)
768
779
  end
769
780
  end
770
781
  rescue NoMethodError => err
@@ -784,17 +795,30 @@ module GraphQL
784
795
  end
785
796
  end
786
797
 
787
- def resolve_with_directives(object, directives, &block)
798
+ def resolve_list_item(inner_value, inner_type, next_path, ast_node, scoped_context, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type) # rubocop:disable Metrics/ParameterLists
799
+ set_all_interpreter_context(nil, nil, nil, next_path)
800
+ call_method_on_directives(:resolve_each, owner_object, ast_node.directives) do
801
+ # This will update `response_list` with the lazy
802
+ after_lazy(inner_value, owner: inner_type, path: next_path, ast_node: ast_node, scoped_context: scoped_context, field: field, owner_object: owner_object, arguments: arguments, result_name: this_idx, result: response_list) do |inner_inner_value|
803
+ continue_value = continue_value(next_path, inner_inner_value, owner_type, field, inner_type.non_null?, ast_node, this_idx, response_list)
804
+ if HALT != continue_value
805
+ continue_field(next_path, continue_value, owner_type, field, inner_type, ast_node, next_selections, false, owner_object, arguments, this_idx, response_list)
806
+ end
807
+ end
808
+ end
809
+ end
810
+
811
+ def call_method_on_directives(method_name, object, directives, &block)
788
812
  return yield if directives.nil? || directives.empty?
789
- run_directive(object, directives, 0, &block)
813
+ run_directive(method_name, object, directives, 0, &block)
790
814
  end
791
815
 
792
- def run_directive(object, directives, idx, &block)
816
+ def run_directive(method_name, object, directives, idx, &block)
793
817
  dir_node = directives[idx]
794
818
  if !dir_node
795
819
  yield
796
820
  else
797
- dir_defn = schema.directives.fetch(dir_node.name)
821
+ dir_defn = @schema_directives.fetch(dir_node.name)
798
822
  if !dir_defn.is_a?(Class)
799
823
  dir_defn = dir_defn.type_class || raise("Only class-based directives are supported (not `@#{dir_node.name}`)")
800
824
  end
@@ -813,8 +837,8 @@ module GraphQL
813
837
  if dir_args == HALT
814
838
  nil
815
839
  else
816
- dir_defn.resolve(object, dir_args, context) do
817
- run_directive(object, directives, idx + 1, &block)
840
+ dir_defn.public_send(method_name, object, dir_args, context) do
841
+ run_directive(method_name, object, directives, idx + 1, &block)
818
842
  end
819
843
  end
820
844
  end
@@ -823,7 +847,7 @@ module GraphQL
823
847
  # Check {Schema::Directive.include?} for each directive that's present
824
848
  def directives_include?(node, graphql_object, parent_type)
825
849
  node.directives.each do |dir_node|
826
- dir_defn = schema.directives.fetch(dir_node.name).type_class || raise("Only class-based directives are supported (not #{dir_node.name.inspect})")
850
+ dir_defn = @schema_directives.fetch(dir_node.name).type_class || raise("Only class-based directives are supported (not #{dir_node.name.inspect})")
827
851
  args = arguments(graphql_object, dir_defn, dir_node)
828
852
  if !dir_defn.include?(graphql_object, args, context)
829
853
  return false
@@ -862,16 +886,20 @@ module GraphQL
862
886
  # but don't wrap the continuation below
863
887
  inner_obj = begin
864
888
  query.with_error_handling do
865
- if trace
866
- query.trace("execute_field_lazy", {owner: owner, field: field, path: path, query: query, object: owner_object, arguments: arguments, ast_node: ast_node}) do
889
+ begin
890
+ if trace
891
+ query.trace("execute_field_lazy", {owner: owner, field: field, path: path, query: query, object: owner_object, arguments: arguments, ast_node: ast_node}) do
892
+ schema.sync_lazy(lazy_obj)
893
+ end
894
+ else
867
895
  schema.sync_lazy(lazy_obj)
868
896
  end
869
- else
870
- schema.sync_lazy(lazy_obj)
897
+ rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => err
898
+ err
871
899
  end
872
900
  end
873
- rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => err
874
- err
901
+ rescue GraphQL::ExecutionError => ex_err
902
+ ex_err
875
903
  end
876
904
  yield(inner_obj)
877
905
  end
@@ -254,14 +254,14 @@ module GraphQL
254
254
  subselections_on_type = selections_on_type
255
255
  if (t = ast_selection.type)
256
256
  # Assuming this is valid, that `t` will be found.
257
- on_type = @query.schema.get_type(t.name).type_class
257
+ on_type = @query.get_type(t.name).type_class
258
258
  subselections_on_type = subselections_by_type[on_type] ||= {}
259
259
  end
260
260
  find_selections(subselections_by_type, subselections_on_type, on_type, ast_selection.selections, arguments)
261
261
  when GraphQL::Language::Nodes::FragmentSpread
262
262
  frag_defn = @query.fragments[ast_selection.name] || raise("Invariant: Can't look ahead to nonexistent fragment #{ast_selection.name} (found: #{@query.fragments.keys})")
263
263
  # Again, assuming a valid AST
264
- on_type = @query.schema.get_type(frag_defn.type.name).type_class
264
+ on_type = @query.get_type(frag_defn.type.name).type_class
265
265
  subselections_on_type = subselections_by_type[on_type] ||= {}
266
266
  find_selections(subselections_by_type, subselections_on_type, on_type, frag_defn.selections, arguments)
267
267
  else
@@ -35,7 +35,7 @@ module GraphQL
35
35
  @queries = queries
36
36
  @queries.each { |q| q.multiplex = self }
37
37
  @context = context
38
- @context[:dataloader] = @dataloader = @schema.dataloader_class.new
38
+ @dataloader = @context[:dataloader] ||= @schema.dataloader_class.new
39
39
  @tracers = schema.tracers + (context[:tracers] || [])
40
40
  # Support `context: {backtrace: true}`
41
41
  if context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
@@ -151,6 +151,9 @@ module GraphQL
151
151
 
152
152
  result
153
153
  end
154
+ if query.context.namespace?(:__query_result_extensions__)
155
+ query.result_values["extensions"] = query.context.namespace(:__query_result_extensions__)
156
+ end
154
157
  end
155
158
 
156
159
  # use the old `query_execution_strategy` etc to run this query
data/lib/graphql/field.rb CHANGED
@@ -5,7 +5,7 @@ module GraphQL
5
5
  # @api deprecated
6
6
  class Field
7
7
  include GraphQL::Define::InstanceDefinable
8
- accepts_definitions :name, :description, :deprecation_reason,
8
+ deprecated_accepts_definitions :name, :description, :deprecation_reason,
9
9
  :resolve, :lazy_resolve,
10
10
  :type, :arguments,
11
11
  :property, :hash_key, :complexity,
@@ -1,2 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::FLOAT_TYPE = GraphQL::Types::Float.graphql_definition
2
+ GraphQL::FLOAT_TYPE = GraphQL::Types::Float.graphql_definition(silence_deprecation_warning: true)
@@ -1,2 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::ID_TYPE = GraphQL::Types::ID.graphql_definition
2
+ GraphQL::ID_TYPE = GraphQL::Types::ID.graphql_definition(silence_deprecation_warning: true)
@@ -4,7 +4,7 @@ module GraphQL
4
4
  class InputObjectType < GraphQL::BaseType
5
5
  extend Define::InstanceDefinable::DeprecatedDefine
6
6
 
7
- accepts_definitions(
7
+ deprecated_accepts_definitions(
8
8
  :arguments, :mutation,
9
9
  input_field: GraphQL::Define::AssignArgument,
10
10
  argument: GraphQL::Define::AssignArgument
@@ -1,2 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::INT_TYPE = GraphQL::Types::Int.graphql_definition
2
+ GraphQL::INT_TYPE = GraphQL::Types::Int.graphql_definition(silence_deprecation_warning: true)
@@ -4,7 +4,7 @@ module GraphQL
4
4
  class InterfaceType < GraphQL::BaseType
5
5
  extend Define::InstanceDefinable::DeprecatedDefine
6
6
 
7
- accepts_definitions :fields, :orphan_types, :resolve_type, field: GraphQL::Define::AssignObjectField
7
+ deprecated_accepts_definitions :fields, :orphan_types, :resolve_type, field: GraphQL::Define::AssignObjectField
8
8
 
9
9
  attr_accessor :fields, :orphan_types, :resolve_type_proc
10
10
  attr_writer :type_membership_class
@@ -6,8 +6,8 @@ module GraphQL
6
6
  description "A Directive can be adjacent to many parts of the GraphQL language, "\
7
7
  "a __DirectiveLocation describes one such possible adjacencies."
8
8
 
9
- GraphQL::Directive::LOCATIONS.each do |location|
10
- value(location.to_s, GraphQL::Directive::LOCATION_DESCRIPTIONS[location], value: location)
9
+ GraphQL::Schema::Directive::LOCATIONS.each do |location|
10
+ value(location.to_s, GraphQL::Schema::Directive::LOCATION_DESCRIPTIONS[location], value: location)
11
11
  end
12
12
  introspection true
13
13
  end
@@ -10,15 +10,17 @@ module GraphQL
10
10
  "skipping a field. Directives provide this by describing additional information "\
11
11
  "to the executor."
12
12
  field :name, String, null: false, method: :graphql_name
13
- field :description, String, null: true
14
- field :locations, [GraphQL::Schema::LateBoundType.new("__DirectiveLocation")], null: false
15
- field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false do
13
+ field :description, String
14
+ field :locations, [GraphQL::Schema::LateBoundType.new("__DirectiveLocation")], null: false, scope: false
15
+ field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false, scope: false do
16
16
  argument :include_deprecated, Boolean, required: false, default_value: false
17
17
  end
18
18
  field :on_operation, Boolean, null: false, deprecation_reason: "Use `locations`.", method: :on_operation?
19
19
  field :on_fragment, Boolean, null: false, deprecation_reason: "Use `locations`.", method: :on_fragment?
20
20
  field :on_field, Boolean, null: false, deprecation_reason: "Use `locations`.", method: :on_field?
21
21
 
22
+ field :is_repeatable, Boolean, method: :repeatable?
23
+
22
24
  def args(include_deprecated:)
23
25
  args = @context.warden.arguments(@object)
24
26
  args = args.reject(&:deprecation_reason) unless include_deprecated
@@ -3,8 +3,8 @@ module GraphQL
3
3
  module Introspection
4
4
  class EntryPoints < Introspection::BaseObject
5
5
  field :__schema, GraphQL::Schema::LateBoundType.new("__Schema"), "This GraphQL schema", null: false
6
- field :__type, GraphQL::Schema::LateBoundType.new("__Type"), "A type in the GraphQL system", null: true do
7
- argument :name, String, required: true
6
+ field :__type, GraphQL::Schema::LateBoundType.new("__Type"), "A type in the GraphQL system" do
7
+ argument :name, String
8
8
  end
9
9
 
10
10
  def __schema
@@ -7,9 +7,9 @@ module GraphQL
7
7
  "placeholder for a string or numeric value. However an Enum value is returned in "\
8
8
  "a JSON response as a string."
9
9
  field :name, String, null: false
10
- field :description, String, null: true
10
+ field :description, String
11
11
  field :is_deprecated, Boolean, null: false
12
- field :deprecation_reason, String, null: true
12
+ field :deprecation_reason, String
13
13
 
14
14
  def name
15
15
  object.graphql_name
@@ -6,13 +6,13 @@ module GraphQL
6
6
  description "Object and Interface types are described by a list of Fields, each of which has "\
7
7
  "a name, potentially a list of arguments, and a return type."
8
8
  field :name, String, null: false
9
- field :description, String, null: true
10
- field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false do
9
+ field :description, String
10
+ field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false, scope: false do
11
11
  argument :include_deprecated, Boolean, required: false, default_value: false
12
12
  end
13
13
  field :type, GraphQL::Schema::LateBoundType.new("__Type"), null: false
14
14
  field :is_deprecated, Boolean, null: false
15
- field :deprecation_reason, String, null: true
15
+ field :deprecation_reason, String
16
16
 
17
17
  def is_deprecated
18
18
  !!@object.deprecation_reason
@@ -7,11 +7,11 @@ module GraphQL
7
7
  "InputObject are represented as Input Values which describe their type and "\
8
8
  "optionally a default value."
9
9
  field :name, String, null: false
10
- field :description, String, null: true
10
+ field :description, String
11
11
  field :type, GraphQL::Schema::LateBoundType.new("__Type"), null: false
12
- field :default_value, String, "A GraphQL-formatted string representing the default value for this input value.", null: true
12
+ field :default_value, String, "A GraphQL-formatted string representing the default value for this input value."
13
13
  field :is_deprecated, Boolean, null: false
14
- field :deprecation_reason, String, null: true
14
+ field :deprecation_reason, String
15
15
 
16
16
  def is_deprecated
17
17
  !!@object.deprecation_reason
@@ -54,7 +54,7 @@ module GraphQL
54
54
  elsif type.kind.input_object?
55
55
  "{" +
56
56
  value.map do |k, v|
57
- arg_defn = type.arguments[k]
57
+ arg_defn = type.get_argument(k, context)
58
58
  "#{k}: #{serialize_default_value(v, arg_defn.type)}"
59
59
  end.join(", ") +
60
60
  "}"
@@ -8,11 +8,16 @@ module GraphQL
8
8
  "available types and directives on the server, as well as the entry points for "\
9
9
  "query, mutation, and subscription operations."
10
10
 
11
- field :types, [GraphQL::Schema::LateBoundType.new("__Type")], "A list of all types supported by this server.", null: false
11
+ field :types, [GraphQL::Schema::LateBoundType.new("__Type")], "A list of all types supported by this server.", null: false, scope: false
12
12
  field :query_type, GraphQL::Schema::LateBoundType.new("__Type"), "The type that query operations will be rooted at.", null: false
13
- field :mutation_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server supports mutation, the type that mutation operations will be rooted at.", null: true
14
- field :subscription_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server support subscription, the type that subscription operations will be rooted at.", null: true
15
- field :directives, [GraphQL::Schema::LateBoundType.new("__Directive")], "A list of all directives supported by this server.", null: false
13
+ field :mutation_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server supports mutation, the type that mutation operations will be rooted at."
14
+ field :subscription_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server support subscription, the type that subscription operations will be rooted at."
15
+ field :directives, [GraphQL::Schema::LateBoundType.new("__Directive")], "A list of all directives supported by this server.", null: false, scope: false
16
+ field :description, String, resolver_method: :schema_description
17
+
18
+ def schema_description
19
+ context.schema.description
20
+ end
16
21
 
17
22
  def types
18
23
  @context.warden.reachable_types.sort_by(&:graphql_name)
@@ -12,23 +12,29 @@ module GraphQL
12
12
  "possible at runtime. List and NonNull types compose other types."
13
13
 
14
14
  field :kind, GraphQL::Schema::LateBoundType.new("__TypeKind"), null: false
15
- field :name, String, null: true
16
- field :description, String, null: true
17
- field :fields, [GraphQL::Schema::LateBoundType.new("__Field")], null: true do
15
+ field :name, String, method: :graphql_name
16
+ field :description, String
17
+ field :fields, [GraphQL::Schema::LateBoundType.new("__Field")], scope: false do
18
18
  argument :include_deprecated, Boolean, required: false, default_value: false
19
19
  end
20
- field :interfaces, [GraphQL::Schema::LateBoundType.new("__Type")], null: true
21
- field :possible_types, [GraphQL::Schema::LateBoundType.new("__Type")], null: true
22
- field :enum_values, [GraphQL::Schema::LateBoundType.new("__EnumValue")], null: true do
20
+ field :interfaces, [GraphQL::Schema::LateBoundType.new("__Type")], scope: false
21
+ field :possible_types, [GraphQL::Schema::LateBoundType.new("__Type")], scope: false
22
+ field :enum_values, [GraphQL::Schema::LateBoundType.new("__EnumValue")], scope: false do
23
23
  argument :include_deprecated, Boolean, required: false, default_value: false
24
24
  end
25
- field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: true do
25
+ field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")], scope: false do
26
26
  argument :include_deprecated, Boolean, required: false, default_value: false
27
27
  end
28
- field :of_type, GraphQL::Schema::LateBoundType.new("__Type"), null: true
28
+ field :of_type, GraphQL::Schema::LateBoundType.new("__Type")
29
29
 
30
- def name
31
- object.graphql_name
30
+ field :specified_by_url, String
31
+
32
+ def specified_by_url
33
+ if object.kind.scalar?
34
+ object.specified_by_url
35
+ else
36
+ nil
37
+ end
32
38
  end
33
39
 
34
40
  def kind
@@ -50,8 +56,8 @@ module GraphQL
50
56
  end
51
57
 
52
58
  def interfaces
53
- if @object.kind == GraphQL::TypeKinds::OBJECT
54
- @context.warden.interfaces(@object)
59
+ if @object.kind.object? || @object.kind.interface?
60
+ @context.warden.interfaces(@object).sort_by(&:graphql_name)
55
61
  else
56
62
  nil
57
63
  end
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
3
  module Introspection
4
- def self.query(include_deprecated_args: false)
4
+ def self.query(include_deprecated_args: false, include_schema_description: false, include_is_repeatable: false, include_specified_by_url: false)
5
5
  # The introspection query to end all introspection queries, copied from
6
6
  # https://github.com/graphql/graphql-js/blob/master/src/utilities/introspectionQuery.js
7
7
  <<-QUERY
8
8
  query IntrospectionQuery {
9
9
  __schema {
10
+ #{include_schema_description ? "description" : ""}
10
11
  queryType { name }
11
12
  mutationType { name }
12
13
  subscriptionType { name }
@@ -17,6 +18,7 @@ query IntrospectionQuery {
17
18
  name
18
19
  description
19
20
  locations
21
+ #{include_is_repeatable ? "isRepeatable" : ""}
20
22
  args#{include_deprecated_args ? '(includeDeprecated: true)' : ''} {
21
23
  ...InputValue
22
24
  }
@@ -27,6 +29,7 @@ fragment FullType on __Type {
27
29
  kind
28
30
  name
29
31
  description
32
+ #{include_specified_by_url ? "specifiedByUrl" : ""}
30
33
  fields(includeDeprecated: true) {
31
34
  name
32
35
  description
@@ -2,16 +2,12 @@
2
2
  module GraphQL
3
3
  module Language
4
4
  module BlockString
5
- if !String.method_defined?(:match?)
6
- using GraphQL::StringMatchBackport
7
- end
8
-
9
5
  # Remove leading and trailing whitespace from a block string.
10
6
  # See "Block Strings" in https://github.com/facebook/graphql/blob/master/spec/Section%202%20--%20Language.md
11
7
  def self.trim_whitespace(str)
12
8
  # Early return for the most common cases:
13
9
  if str == ""
14
- return ""
10
+ return "".dup
15
11
  elsif !(has_newline = str.include?("\n")) && !(str.start_with?(" "))
16
12
  return str
17
13
  end
@@ -59,7 +55,7 @@ module GraphQL
59
55
  end
60
56
 
61
57
  # Rebuild the string
62
- lines.size > 1 ? lines.join("\n") : (lines.first || "")
58
+ lines.size > 1 ? lines.join("\n") : (lines.first || "".dup)
63
59
  end
64
60
 
65
61
  def self.print(str, indent: '')
@@ -34,6 +34,7 @@ module GraphQL
34
34
  schema: @schema,
35
35
  context: schema_context,
36
36
  )
37
+ schema_context.warden = @warden
37
38
  end
38
39
 
39
40
  def document
@@ -87,6 +88,7 @@ module GraphQL
87
88
  def build_interface_type_node(interface_type)
88
89
  GraphQL::Language::Nodes::InterfaceTypeDefinition.new(
89
90
  name: interface_type.graphql_name,
91
+ interfaces: warden.interfaces(interface_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
90
92
  description: interface_type.description,
91
93
  fields: build_field_nodes(warden.fields(interface_type)),
92
94
  directives: directives(interface_type),
@@ -150,6 +152,7 @@ module GraphQL
150
152
  def build_directive_node(directive)
151
153
  GraphQL::Language::Nodes::DirectiveDefinition.new(
152
154
  name: directive.graphql_name,
155
+ repeatable: directive.repeatable?,
153
156
  arguments: build_argument_nodes(warden.arguments(directive)),
154
157
  locations: build_directive_location_nodes(directive.locations),
155
158
  description: directive.description,
@@ -194,10 +197,14 @@ module GraphQL
194
197
  when "INPUT_OBJECT"
195
198
  GraphQL::Language::Nodes::InputObject.new(
196
199
  arguments: default_value.to_h.map do |arg_name, arg_value|
197
- arg_type = type.arguments.fetch(arg_name.to_s).type
200
+ args = @warden.arguments(type)
201
+ arg = args.find { |a| a.keyword.to_s == arg_name.to_s }
202
+ if arg.nil?
203
+ raise ArgumentError, "No argument definition on #{type.graphql_name} for argument: #{arg_name.inspect} (expected one of: #{args.map(&:keyword)})"
204
+ end
198
205
  GraphQL::Language::Nodes::Argument.new(
199
- name: arg_name.to_s,
200
- value: build_default_value(arg_value, arg_type)
206
+ name: arg.graphql_name.to_s,
207
+ value: build_default_value(arg_value, arg.type)
201
208
  )
202
209
  end
203
210
  )
@@ -295,7 +302,7 @@ module GraphQL
295
302
  else
296
303
  member.directives.map do |dir|
297
304
  args = []
298
- dir.arguments.argument_values.each_value do |arg_value|
305
+ dir.arguments.argument_values.each_value do |arg_value| # rubocop:disable Development/ContextIsPassedCop -- directive instance method
299
306
  arg_defn = arg_value.definition
300
307
  if arg_defn.default_value? && arg_value.value == arg_defn.default_value
301
308
  next