graphql 1.9.17 → 1.11.7

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 (230) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +18 -2
  3. data/lib/generators/graphql/install_generator.rb +27 -0
  4. data/lib/generators/graphql/object_generator.rb +52 -8
  5. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  6. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  7. data/lib/generators/graphql/templates/base_field.erb +2 -0
  8. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  9. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  10. data/lib/generators/graphql/templates/base_mutation.erb +2 -0
  11. data/lib/generators/graphql/templates/base_object.erb +2 -0
  12. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  13. data/lib/generators/graphql/templates/base_union.erb +2 -0
  14. data/lib/generators/graphql/templates/enum.erb +2 -0
  15. data/lib/generators/graphql/templates/graphql_controller.erb +14 -10
  16. data/lib/generators/graphql/templates/interface.erb +2 -0
  17. data/lib/generators/graphql/templates/loader.erb +2 -0
  18. data/lib/generators/graphql/templates/mutation.erb +2 -0
  19. data/lib/generators/graphql/templates/mutation_type.erb +2 -0
  20. data/lib/generators/graphql/templates/object.erb +2 -0
  21. data/lib/generators/graphql/templates/query_type.erb +2 -0
  22. data/lib/generators/graphql/templates/scalar.erb +2 -0
  23. data/lib/generators/graphql/templates/schema.erb +10 -0
  24. data/lib/generators/graphql/templates/union.erb +3 -1
  25. data/lib/graphql/analysis/ast/field_usage.rb +1 -1
  26. data/lib/graphql/analysis/ast/query_complexity.rb +178 -67
  27. data/lib/graphql/analysis/ast/visitor.rb +3 -3
  28. data/lib/graphql/analysis/ast.rb +12 -11
  29. data/lib/graphql/argument.rb +10 -38
  30. data/lib/graphql/backtrace/table.rb +10 -2
  31. data/lib/graphql/backtrace/tracer.rb +2 -1
  32. data/lib/graphql/base_type.rb +4 -0
  33. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
  34. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +5 -9
  35. data/lib/graphql/define/assign_enum_value.rb +1 -1
  36. data/lib/graphql/define/assign_global_id_field.rb +2 -2
  37. data/lib/graphql/define/assign_object_field.rb +3 -3
  38. data/lib/graphql/define/defined_object_proxy.rb +3 -0
  39. data/lib/graphql/define/instance_definable.rb +18 -108
  40. data/lib/graphql/directive/deprecated_directive.rb +1 -12
  41. data/lib/graphql/directive.rb +8 -1
  42. data/lib/graphql/enum_type.rb +5 -71
  43. data/lib/graphql/execution/directive_checks.rb +2 -2
  44. data/lib/graphql/execution/errors.rb +2 -3
  45. data/lib/graphql/execution/execute.rb +1 -1
  46. data/lib/graphql/execution/instrumentation.rb +1 -1
  47. data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
  48. data/lib/graphql/execution/interpreter/arguments.rb +51 -0
  49. data/lib/graphql/execution/interpreter/arguments_cache.rb +79 -0
  50. data/lib/graphql/execution/interpreter/handles_raw_value.rb +25 -0
  51. data/lib/graphql/execution/interpreter/runtime.rb +227 -254
  52. data/lib/graphql/execution/interpreter.rb +34 -11
  53. data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
  54. data/lib/graphql/execution/lookahead.rb +39 -114
  55. data/lib/graphql/execution/multiplex.rb +14 -5
  56. data/lib/graphql/field.rb +14 -118
  57. data/lib/graphql/filter.rb +1 -1
  58. data/lib/graphql/function.rb +1 -30
  59. data/lib/graphql/input_object_type.rb +6 -24
  60. data/lib/graphql/integer_decoding_error.rb +17 -0
  61. data/lib/graphql/interface_type.rb +7 -23
  62. data/lib/graphql/internal_representation/scope.rb +2 -2
  63. data/lib/graphql/internal_representation/visit.rb +2 -2
  64. data/lib/graphql/introspection/base_object.rb +2 -5
  65. data/lib/graphql/introspection/directive_type.rb +1 -1
  66. data/lib/graphql/introspection/entry_points.rb +7 -7
  67. data/lib/graphql/introspection/field_type.rb +7 -3
  68. data/lib/graphql/introspection/input_value_type.rb +33 -9
  69. data/lib/graphql/introspection/introspection_query.rb +6 -92
  70. data/lib/graphql/introspection/schema_type.rb +4 -9
  71. data/lib/graphql/introspection/type_type.rb +11 -7
  72. data/lib/graphql/introspection.rb +96 -0
  73. data/lib/graphql/invalid_null_error.rb +18 -0
  74. data/lib/graphql/language/block_string.rb +24 -5
  75. data/lib/graphql/language/definition_slice.rb +21 -10
  76. data/lib/graphql/language/document_from_schema_definition.rb +89 -64
  77. data/lib/graphql/language/lexer.rb +7 -3
  78. data/lib/graphql/language/lexer.rl +7 -3
  79. data/lib/graphql/language/nodes.rb +52 -91
  80. data/lib/graphql/language/parser.rb +719 -717
  81. data/lib/graphql/language/parser.y +104 -98
  82. data/lib/graphql/language/printer.rb +1 -1
  83. data/lib/graphql/language/sanitized_printer.rb +222 -0
  84. data/lib/graphql/language/visitor.rb +2 -2
  85. data/lib/graphql/language.rb +2 -1
  86. data/lib/graphql/name_validator.rb +6 -7
  87. data/lib/graphql/non_null_type.rb +0 -10
  88. data/lib/graphql/object_type.rb +45 -56
  89. data/lib/graphql/pagination/active_record_relation_connection.rb +41 -0
  90. data/lib/graphql/pagination/array_connection.rb +77 -0
  91. data/lib/graphql/pagination/connection.rb +208 -0
  92. data/lib/graphql/pagination/connections.rb +145 -0
  93. data/lib/graphql/pagination/mongoid_relation_connection.rb +25 -0
  94. data/lib/graphql/pagination/relation_connection.rb +185 -0
  95. data/lib/graphql/pagination/sequel_dataset_connection.rb +28 -0
  96. data/lib/graphql/pagination.rb +6 -0
  97. data/lib/graphql/query/arguments.rb +4 -2
  98. data/lib/graphql/query/context.rb +36 -9
  99. data/lib/graphql/query/fingerprint.rb +26 -0
  100. data/lib/graphql/query/input_validation_result.rb +23 -6
  101. data/lib/graphql/query/literal_input.rb +30 -10
  102. data/lib/graphql/query/null_context.rb +5 -1
  103. data/lib/graphql/query/validation_pipeline.rb +4 -1
  104. data/lib/graphql/query/variable_validation_error.rb +1 -1
  105. data/lib/graphql/query/variables.rb +16 -7
  106. data/lib/graphql/query.rb +64 -15
  107. data/lib/graphql/rake_task/validate.rb +3 -0
  108. data/lib/graphql/rake_task.rb +9 -9
  109. data/lib/graphql/relay/array_connection.rb +10 -12
  110. data/lib/graphql/relay/base_connection.rb +23 -13
  111. data/lib/graphql/relay/connection_type.rb +2 -1
  112. data/lib/graphql/relay/edge_type.rb +1 -0
  113. data/lib/graphql/relay/edges_instrumentation.rb +1 -1
  114. data/lib/graphql/relay/mutation.rb +1 -86
  115. data/lib/graphql/relay/node.rb +2 -2
  116. data/lib/graphql/relay/range_add.rb +14 -5
  117. data/lib/graphql/relay/relation_connection.rb +8 -10
  118. data/lib/graphql/scalar_type.rb +15 -59
  119. data/lib/graphql/schema/argument.rb +113 -11
  120. data/lib/graphql/schema/base_64_encoder.rb +2 -0
  121. data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -1
  122. data/lib/graphql/schema/build_from_definition/resolve_map.rb +13 -5
  123. data/lib/graphql/schema/build_from_definition.rb +212 -190
  124. data/lib/graphql/schema/built_in_types.rb +5 -5
  125. data/lib/graphql/schema/default_type_error.rb +2 -0
  126. data/lib/graphql/schema/directive/deprecated.rb +18 -0
  127. data/lib/graphql/schema/directive/include.rb +1 -1
  128. data/lib/graphql/schema/directive/skip.rb +1 -1
  129. data/lib/graphql/schema/directive.rb +34 -3
  130. data/lib/graphql/schema/enum.rb +52 -4
  131. data/lib/graphql/schema/enum_value.rb +6 -1
  132. data/lib/graphql/schema/field/connection_extension.rb +44 -20
  133. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  134. data/lib/graphql/schema/field.rb +200 -129
  135. data/lib/graphql/schema/find_inherited_value.rb +13 -0
  136. data/lib/graphql/schema/finder.rb +13 -11
  137. data/lib/graphql/schema/input_object.rb +131 -22
  138. data/lib/graphql/schema/interface.rb +26 -8
  139. data/lib/graphql/schema/introspection_system.rb +108 -37
  140. data/lib/graphql/schema/late_bound_type.rb +3 -2
  141. data/lib/graphql/schema/list.rb +47 -0
  142. data/lib/graphql/schema/loader.rb +134 -96
  143. data/lib/graphql/schema/member/base_dsl_methods.rb +29 -12
  144. data/lib/graphql/schema/member/build_type.rb +19 -5
  145. data/lib/graphql/schema/member/cached_graphql_definition.rb +5 -0
  146. data/lib/graphql/schema/member/has_arguments.rb +105 -5
  147. data/lib/graphql/schema/member/has_ast_node.rb +20 -0
  148. data/lib/graphql/schema/member/has_fields.rb +20 -10
  149. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  150. data/lib/graphql/schema/member/type_system_helpers.rb +2 -2
  151. data/lib/graphql/schema/member/validates_input.rb +33 -0
  152. data/lib/graphql/schema/member.rb +6 -0
  153. data/lib/graphql/schema/mutation.rb +5 -1
  154. data/lib/graphql/schema/non_null.rb +30 -0
  155. data/lib/graphql/schema/object.rb +65 -12
  156. data/lib/graphql/schema/possible_types.rb +9 -4
  157. data/lib/graphql/schema/printer.rb +0 -15
  158. data/lib/graphql/schema/relay_classic_mutation.rb +5 -3
  159. data/lib/graphql/schema/resolver/has_payload_type.rb +5 -2
  160. data/lib/graphql/schema/resolver.rb +26 -18
  161. data/lib/graphql/schema/scalar.rb +27 -3
  162. data/lib/graphql/schema/subscription.rb +8 -18
  163. data/lib/graphql/schema/timeout.rb +29 -15
  164. data/lib/graphql/schema/traversal.rb +1 -1
  165. data/lib/graphql/schema/type_expression.rb +21 -13
  166. data/lib/graphql/schema/type_membership.rb +2 -2
  167. data/lib/graphql/schema/union.rb +37 -3
  168. data/lib/graphql/schema/unique_within_type.rb +1 -2
  169. data/lib/graphql/schema/validation.rb +10 -2
  170. data/lib/graphql/schema/warden.rb +115 -29
  171. data/lib/graphql/schema.rb +903 -195
  172. data/lib/graphql/static_validation/all_rules.rb +1 -0
  173. data/lib/graphql/static_validation/base_visitor.rb +10 -6
  174. data/lib/graphql/static_validation/literal_validator.rb +52 -27
  175. data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +43 -83
  176. data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +17 -5
  177. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +33 -25
  178. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +1 -1
  179. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
  180. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +5 -5
  181. data/lib/graphql/static_validation/rules/fields_will_merge.rb +29 -21
  182. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  183. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  184. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  185. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +2 -2
  186. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -5
  187. data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +12 -13
  188. data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +5 -6
  189. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
  190. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +5 -3
  191. data/lib/graphql/static_validation/type_stack.rb +2 -2
  192. data/lib/graphql/static_validation/validation_context.rb +1 -1
  193. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  194. data/lib/graphql/static_validation/validator.rb +30 -8
  195. data/lib/graphql/static_validation.rb +1 -0
  196. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +89 -19
  197. data/lib/graphql/subscriptions/broadcast_analyzer.rb +84 -0
  198. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
  199. data/lib/graphql/subscriptions/event.rb +23 -5
  200. data/lib/graphql/subscriptions/instrumentation.rb +10 -5
  201. data/lib/graphql/subscriptions/serialize.rb +22 -4
  202. data/lib/graphql/subscriptions/subscription_root.rb +15 -5
  203. data/lib/graphql/subscriptions.rb +108 -35
  204. data/lib/graphql/tracing/active_support_notifications_tracing.rb +14 -10
  205. data/lib/graphql/tracing/appoptics_tracing.rb +171 -0
  206. data/lib/graphql/tracing/appsignal_tracing.rb +8 -0
  207. data/lib/graphql/tracing/data_dog_tracing.rb +8 -0
  208. data/lib/graphql/tracing/new_relic_tracing.rb +9 -12
  209. data/lib/graphql/tracing/platform_tracing.rb +53 -9
  210. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  211. data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
  212. data/lib/graphql/tracing/scout_tracing.rb +19 -0
  213. data/lib/graphql/tracing/skylight_tracing.rb +8 -0
  214. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  215. data/lib/graphql/tracing.rb +14 -34
  216. data/lib/graphql/types/big_int.rb +1 -1
  217. data/lib/graphql/types/int.rb +9 -2
  218. data/lib/graphql/types/iso_8601_date.rb +3 -3
  219. data/lib/graphql/types/iso_8601_date_time.rb +25 -10
  220. data/lib/graphql/types/relay/base_connection.rb +11 -7
  221. data/lib/graphql/types/relay/base_edge.rb +2 -1
  222. data/lib/graphql/types/string.rb +7 -1
  223. data/lib/graphql/unauthorized_error.rb +1 -1
  224. data/lib/graphql/union_type.rb +13 -28
  225. data/lib/graphql/unresolved_type_error.rb +2 -2
  226. data/lib/graphql/version.rb +1 -1
  227. data/lib/graphql.rb +31 -6
  228. data/readme.md +1 -1
  229. metadata +34 -9
  230. data/lib/graphql/literal_validation_error.rb +0 -6
@@ -1,8 +1,12 @@
1
1
  # frozen_string_literal: true
2
+ require "graphql/execution/interpreter/argument_value"
3
+ require "graphql/execution/interpreter/arguments"
4
+ require "graphql/execution/interpreter/arguments_cache"
2
5
  require "graphql/execution/interpreter/execution_errors"
3
6
  require "graphql/execution/interpreter/hash_response"
4
7
  require "graphql/execution/interpreter/runtime"
5
8
  require "graphql/execution/interpreter/resolve"
9
+ require "graphql/execution/interpreter/handles_raw_value"
6
10
 
7
11
  module GraphQL
8
12
  module Execution
@@ -17,17 +21,13 @@ module GraphQL
17
21
  runtime.final_value
18
22
  end
19
23
 
20
- def self.use(schema_defn)
21
- schema_defn.target.interpreter = true
22
- # Reach through the legacy objects for the actual class defn
23
- schema_class = schema_defn.target.class
24
- # This is not good, since both of these are holding state now,
25
- # we have to update both :(
26
- [schema_class, schema_defn].each do |schema_config|
27
- schema_config.query_execution_strategy(GraphQL::Execution::Interpreter)
28
- schema_config.mutation_execution_strategy(GraphQL::Execution::Interpreter)
29
- schema_config.subscription_execution_strategy(GraphQL::Execution::Interpreter)
30
- end
24
+ def self.use(schema_class)
25
+ schema_class.interpreter = true
26
+ schema_class.query_execution_strategy(GraphQL::Execution::Interpreter)
27
+ schema_class.mutation_execution_strategy(GraphQL::Execution::Interpreter)
28
+ schema_class.subscription_execution_strategy(GraphQL::Execution::Interpreter)
29
+ schema_class.add_subscription_extension_if_necessary
30
+ GraphQL::Schema::Object.include(HandlesRawValue)
31
31
  end
32
32
 
33
33
  def self.begin_multiplex(multiplex)
@@ -93,6 +93,29 @@ module GraphQL
93
93
  tracer.trace("execute_query_lazy", {multiplex: multiplex, query: query}) do
94
94
  Interpreter::Resolve.resolve_all(final_values)
95
95
  end
96
+ queries.each do |query|
97
+ runtime = query.context.namespace(:interpreter)[:runtime]
98
+ if runtime
99
+ runtime.delete_interpreter_context(:current_path)
100
+ runtime.delete_interpreter_context(:current_field)
101
+ runtime.delete_interpreter_context(:current_object)
102
+ runtime.delete_interpreter_context(:current_arguments)
103
+ end
104
+ end
105
+ nil
106
+ end
107
+
108
+ class ListResultFailedError < GraphQL::Error
109
+ def initialize(value:, path:, field:)
110
+ message = "Failed to build a GraphQL list result for field `#{field.path}` at path `#{path.join(".")}`.\n".dup
111
+
112
+ message << "Expected `#{value.inspect}` to implement `.each` to satisfy the GraphQL return type `#{field.type.to_type_signature}`.\n"
113
+
114
+ if field.connection?
115
+ message << "\nThis field was treated as a Relay-style connection; add `connection: false` to the `field(...)` to disable this behavior."
116
+ end
117
+ super(message)
118
+ end
96
119
  end
97
120
  end
98
121
  end
@@ -36,6 +36,10 @@ module GraphQL
36
36
  @storage.compute_if_absent(value.class) { find_superclass_method(value.class) }
37
37
  end
38
38
 
39
+ def each
40
+ @storage.each_pair { |k, v| yield(k, v) }
41
+ end
42
+
39
43
  protected
40
44
 
41
45
  attr_reader :storage
@@ -51,7 +51,17 @@ module GraphQL
51
51
 
52
52
  # @return [Hash<Symbol, Object>]
53
53
  def arguments
54
- @arguments ||= @field && ArgumentHelpers.arguments(@query, nil, @field, ast_nodes.first)
54
+ if defined?(@arguments)
55
+ @arguments
56
+ else
57
+ @arguments = if @field
58
+ @query.schema.after_lazy(@query.arguments_for(@ast_nodes.first, @field)) do |args|
59
+ args.is_a?(Execution::Interpreter::Arguments) ? args.keyword_arguments : args
60
+ end
61
+ else
62
+ nil
63
+ end
64
+ end
55
65
  end
56
66
 
57
67
  # True if this node has a selection on `field_name`.
@@ -81,7 +91,7 @@ module GraphQL
81
91
  def selection(field_name, selected_type: @selected_type, arguments: nil)
82
92
  next_field_name = normalize_name(field_name)
83
93
 
84
- next_field_defn = FieldHelpers.get_field(@query.schema, selected_type, next_field_name)
94
+ next_field_defn = get_class_based_field(selected_type, next_field_name)
85
95
  if next_field_defn
86
96
  next_nodes = []
87
97
  @ast_nodes.each do |ast_node|
@@ -127,7 +137,7 @@ module GraphQL
127
137
 
128
138
  subselections_by_type.each do |type, ast_nodes_by_response_key|
129
139
  ast_nodes_by_response_key.each do |response_key, ast_nodes|
130
- field_defn = FieldHelpers.get_field(@query.schema, type, ast_nodes.first.name)
140
+ field_defn = get_class_based_field(type, ast_nodes.first.name)
131
141
  lookahead = Lookahead.new(query: @query, ast_nodes: ast_nodes, field: field_defn, owner_type: type)
132
142
  subselections.push(lookahead)
133
143
  end
@@ -203,8 +213,29 @@ module GraphQL
203
213
  end
204
214
  end
205
215
 
216
+ # Wrap get_field and ensure that it returns a GraphQL::Schema::Field.
217
+ # Remove this when legacy execution is removed.
218
+ def get_class_based_field(type, name)
219
+ f = @query.get_field(type, name)
220
+ f && f.type_class
221
+ end
222
+
223
+ def skipped_by_directive?(ast_selection)
224
+ ast_selection.directives.each do |directive|
225
+ dir_defn = @query.schema.directives.fetch(directive.name)
226
+ directive_class = dir_defn.type_class
227
+ if directive_class
228
+ dir_args = @query.arguments_for(directive, dir_defn)
229
+ return true unless directive_class.static_include?(dir_args, @query.context)
230
+ end
231
+ end
232
+ false
233
+ end
234
+
206
235
  def find_selections(subselections_by_type, selections_on_type, selected_type, ast_selections, arguments)
207
236
  ast_selections.each do |ast_selection|
237
+ next if skipped_by_directive?(ast_selection)
238
+
208
239
  case ast_selection
209
240
  when GraphQL::Language::Nodes::Field
210
241
  response_key = ast_selection.alias || ast_selection.name
@@ -213,7 +244,7 @@ module GraphQL
213
244
  elsif arguments.nil? || arguments.empty?
214
245
  selections_on_type[response_key] = [ast_selection]
215
246
  else
216
- field_defn = FieldHelpers.get_field(@query.schema, selected_type, ast_selection.name)
247
+ field_defn = get_class_based_field(selected_type, ast_selection.name)
217
248
  if arguments_match?(arguments, field_defn, ast_selection)
218
249
  selections_on_type[response_key] = [ast_selection]
219
250
  end
@@ -223,14 +254,14 @@ module GraphQL
223
254
  subselections_on_type = selections_on_type
224
255
  if (t = ast_selection.type)
225
256
  # Assuming this is valid, that `t` will be found.
226
- on_type = @query.schema.types[t.name].metadata[:type_class]
257
+ on_type = @query.schema.get_type(t.name).type_class
227
258
  subselections_on_type = subselections_by_type[on_type] ||= {}
228
259
  end
229
260
  find_selections(subselections_by_type, subselections_on_type, on_type, ast_selection.selections, arguments)
230
261
  when GraphQL::Language::Nodes::FragmentSpread
231
262
  frag_defn = @query.fragments[ast_selection.name] || raise("Invariant: Can't look ahead to nonexistent fragment #{ast_selection.name} (found: #{@query.fragments.keys})")
232
263
  # Again, assuming a valid AST
233
- on_type = @query.schema.types[frag_defn.type.name].metadata[:type_class]
264
+ on_type = @query.schema.get_type(frag_defn.type.name).type_class
234
265
  subselections_on_type = subselections_by_type[on_type] ||= {}
235
266
  find_selections(subselections_by_type, subselections_on_type, on_type, frag_defn.selections, arguments)
236
267
  else
@@ -242,6 +273,7 @@ module GraphQL
242
273
  # If a selection on `node` matches `field_name` (which is backed by `field_defn`)
243
274
  # and matches the `arguments:` constraints, then add that node to `matches`
244
275
  def find_selected_nodes(node, field_name, field_defn, arguments:, matches:)
276
+ return if skipped_by_directive?(node)
245
277
  case node
246
278
  when GraphQL::Language::Nodes::Field
247
279
  if node.name == field_name
@@ -263,120 +295,13 @@ module GraphQL
263
295
  end
264
296
 
265
297
  def arguments_match?(arguments, field_defn, field_node)
266
- query_kwargs = ArgumentHelpers.arguments(@query, nil, field_defn, field_node)
298
+ query_kwargs = @query.arguments_for(field_node, field_defn)
267
299
  arguments.all? do |arg_name, arg_value|
268
300
  arg_name = normalize_keyword(arg_name)
269
301
  # Make sure the constraint is present with a matching value
270
302
  query_kwargs.key?(arg_name) && query_kwargs[arg_name] == arg_value
271
303
  end
272
304
  end
273
-
274
- # TODO Dedup with interpreter
275
- module ArgumentHelpers
276
- module_function
277
-
278
- def arguments(query, graphql_object, arg_owner, ast_node)
279
- kwarg_arguments = {}
280
- arg_defns = arg_owner.arguments
281
- ast_node.arguments.each do |arg|
282
- arg_defn = arg_defns[arg.name] || raise("Invariant: missing argument definition for #{arg.name.inspect} in #{arg_defns.keys} from #{arg_owner}")
283
- # Need to distinguish between client-provided `nil`
284
- # and nothing-at-all
285
- is_present, value = arg_to_value(query, graphql_object, arg_defn.type, arg.value)
286
- if is_present
287
- # This doesn't apply to directives, which are legacy
288
- # Can remove this when Skip and Include use classes or something.
289
- if graphql_object
290
- value = arg_defn.prepare_value(graphql_object, value)
291
- end
292
- kwarg_arguments[arg_defn.keyword] = value
293
- end
294
- end
295
- arg_defns.each do |name, arg_defn|
296
- if arg_defn.default_value? && !kwarg_arguments.key?(arg_defn.keyword)
297
- kwarg_arguments[arg_defn.keyword] = arg_defn.default_value
298
- end
299
- end
300
- kwarg_arguments
301
- end
302
-
303
- # Get a Ruby-ready value from a client query.
304
- # @param graphql_object [Object] The owner of the field whose argument this is
305
- # @param arg_type [Class, GraphQL::Schema::NonNull, GraphQL::Schema::List]
306
- # @param ast_value [GraphQL::Language::Nodes::VariableIdentifier, String, Integer, Float, Boolean]
307
- # @return [Array(is_present, value)]
308
- def arg_to_value(query, graphql_object, arg_type, ast_value)
309
- if ast_value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
310
- # If it's not here, it will get added later
311
- if query.variables.key?(ast_value.name)
312
- return true, query.variables[ast_value.name]
313
- else
314
- return false, nil
315
- end
316
- elsif ast_value.is_a?(GraphQL::Language::Nodes::NullValue)
317
- return true, nil
318
- elsif arg_type.is_a?(GraphQL::Schema::NonNull)
319
- arg_to_value(query, graphql_object, arg_type.of_type, ast_value)
320
- elsif arg_type.is_a?(GraphQL::Schema::List)
321
- # Treat a single value like a list
322
- arg_value = Array(ast_value)
323
- list = []
324
- arg_value.map do |inner_v|
325
- _present, value = arg_to_value(query, graphql_object, arg_type.of_type, inner_v)
326
- list << value
327
- end
328
- return true, list
329
- elsif arg_type.is_a?(Class) && arg_type < GraphQL::Schema::InputObject
330
- # For these, `prepare` is applied during `#initialize`.
331
- # Pass `nil` so it will be skipped in `#arguments`.
332
- # What a mess.
333
- args = arguments(query, nil, arg_type, ast_value)
334
- # We're not tracking defaults_used, but for our purposes
335
- # we compare the value to the default value.
336
- return true, arg_type.new(ruby_kwargs: args, context: query.context, defaults_used: nil)
337
- else
338
- flat_value = flatten_ast_value(query, ast_value)
339
- return true, arg_type.coerce_input(flat_value, query.context)
340
- end
341
- end
342
-
343
- def flatten_ast_value(query, v)
344
- case v
345
- when GraphQL::Language::Nodes::Enum
346
- v.name
347
- when GraphQL::Language::Nodes::InputObject
348
- h = {}
349
- v.arguments.each do |arg|
350
- h[arg.name] = flatten_ast_value(query, arg.value)
351
- end
352
- h
353
- when Array
354
- v.map { |v2| flatten_ast_value(query, v2) }
355
- when GraphQL::Language::Nodes::VariableIdentifier
356
- flatten_ast_value(query.variables[v.name])
357
- else
358
- v
359
- end
360
- end
361
- end
362
-
363
- # TODO dedup with interpreter
364
- module FieldHelpers
365
- module_function
366
-
367
- def get_field(schema, owner_type, field_name)
368
- field_defn = owner_type.get_field(field_name)
369
- field_defn ||= if owner_type == schema.query.metadata[:type_class] && (entry_point_field = schema.introspection_system.entry_point(name: field_name))
370
- entry_point_field.metadata[:type_class]
371
- elsif (dynamic_field = schema.introspection_system.dynamic_field(name: field_name))
372
- dynamic_field.metadata[:type_class]
373
- else
374
- nil
375
- end
376
-
377
- field_defn
378
- end
379
- end
380
305
  end
381
306
  end
382
307
  end
@@ -34,8 +34,7 @@ module GraphQL
34
34
  @schema = schema
35
35
  @queries = queries
36
36
  @context = context
37
- # TODO remove support for global tracers
38
- @tracers = schema.tracers + GraphQL::Tracing.tracers + (context[:tracers] || [])
37
+ @tracers = schema.tracers + (context[:tracers] || [])
39
38
  # Support `context: {backtrace: true}`
40
39
  if context[:backtrace] && !@tracers.include?(GraphQL::Backtrace::Tracer)
41
40
  @tracers << GraphQL::Backtrace::Tracer
@@ -44,9 +43,9 @@ module GraphQL
44
43
  end
45
44
 
46
45
  class << self
47
- def run_all(schema, query_options, *args)
48
- queries = query_options.map { |opts| GraphQL::Query.new(schema, nil, opts) }
49
- run_queries(schema, queries, *args)
46
+ def run_all(schema, query_options, **kwargs)
47
+ queries = query_options.map { |opts| GraphQL::Query.new(schema, nil, **opts) }
48
+ run_queries(schema, queries, **kwargs)
50
49
  end
51
50
 
52
51
  # @param schema [GraphQL::Schema]
@@ -95,6 +94,7 @@ module GraphQL
95
94
  query.result
96
95
  end
97
96
  rescue Exception
97
+ # TODO rescue at a higher level so it will catch errors in analysis, too
98
98
  # Assign values here so that the query's `@executed` becomes true
99
99
  queries.map { |q| q.result_values ||= {} }
100
100
  raise
@@ -173,6 +173,15 @@ module GraphQL
173
173
  def instrument_and_analyze(multiplex)
174
174
  GraphQL::Execution::Instrumentation.apply_instrumenters(multiplex) do
175
175
  schema = multiplex.schema
176
+ if schema.interpreter? && schema.analysis_engine != GraphQL::Analysis::AST
177
+ raise <<-ERR
178
+ Can't use `GraphQL::Execution::Interpreter` without `GraphQL::Analysis::AST`, please add this plugin to your schema:
179
+
180
+ use GraphQL::Analysis::AST
181
+
182
+ For information about the new analysis engine: https://graphql-ruby.org/queries/ast_analysis.html
183
+ ERR
184
+ end
176
185
  multiplex_analyzers = schema.multiplex_analyzers
177
186
  if multiplex.max_complexity
178
187
  multiplex_analyzers += if schema.using_ast_analysis?
data/lib/graphql/field.rb CHANGED
@@ -2,123 +2,7 @@
2
2
  require "graphql/field/resolve"
3
3
 
4
4
  module GraphQL
5
- # {Field}s belong to {ObjectType}s and {InterfaceType}s.
6
- #
7
- # They're usually created with the `field` helper. If you create it by hand, make sure {#name} is a String.
8
- #
9
- # A field must have a return type, but if you want to defer the return type calculation until later,
10
- # you can pass a proc for the return type. That proc will be called when the schema is defined.
11
- #
12
- # @example Lazy type resolution
13
- # # If the field's type isn't defined yet, you can pass a proc
14
- # field :city, -> { TypeForModelName.find("City") }
15
- #
16
- # For complex field definition, you can pass a block to the `field` helper, eg `field :name do ... end`.
17
- # This block is equivalent to calling `GraphQL::Field.define { ... }`.
18
- #
19
- # @example Defining a field with a block
20
- # field :city, CityType do
21
- # # field definition continues inside the block
22
- # end
23
- #
24
- # ## Resolve
25
- #
26
- # Fields have `resolve` functions to determine their values at query-time.
27
- # The default implementation is to call a method on the object based on the field name.
28
- #
29
- # @example Create a field which calls a method with the same name.
30
- # GraphQL::ObjectType.define do
31
- # field :name, types.String, "The name of this thing "
32
- # end
33
- #
34
- # You can specify a custom proc with the `resolve` helper.
35
- #
36
- # There are some shortcuts for common `resolve` implementations:
37
- # - Provide `property:` to call a method with a different name than the field name
38
- # - Provide `hash_key:` to resolve the field by doing a key lookup, eg `obj[:my_hash_key]`
39
- #
40
- # @example Create a field that calls a different method on the object
41
- # GraphQL::ObjectType.define do
42
- # # use the `property` keyword:
43
- # field :firstName, types.String, property: :first_name
44
- # end
45
- #
46
- # @example Create a field looks up with `[hash_key]`
47
- # GraphQL::ObjectType.define do
48
- # # use the `hash_key` keyword:
49
- # field :firstName, types.String, hash_key: :first_name
50
- # end
51
- #
52
- # ## Arguments
53
- #
54
- # Fields can take inputs; they're called arguments. You can define them with the `argument` helper.
55
- #
56
- # @example Create a field with an argument
57
- # field :students, types[StudentType] do
58
- # argument :grade, types.Int
59
- # resolve ->(obj, args, ctx) {
60
- # Student.where(grade: args[:grade])
61
- # }
62
- # end
63
- #
64
- # They can have default values which will be provided to `resolve` if the query doesn't include a value.
65
- #
66
- # @example Argument with a default value
67
- # field :events, types[EventType] do
68
- # # by default, don't include past events
69
- # argument :includePast, types.Boolean, default_value: false
70
- # resolve ->(obj, args, ctx) {
71
- # args[:includePast] # => false if no value was provided in the query
72
- # # ...
73
- # }
74
- # end
75
- #
76
- # Only certain types maybe used for inputs:
77
- #
78
- # - Scalars
79
- # - Enums
80
- # - Input Objects
81
- # - Lists of those types
82
- #
83
- # Input types may also be non-null -- in that case, the query will fail
84
- # if the input is not present.
85
- #
86
- # ## Complexity
87
- #
88
- # Fields can have _complexity_ values which describe the computation cost of resolving the field.
89
- # You can provide the complexity as a constant with `complexity:` or as a proc, with the `complexity` helper.
90
- #
91
- # @example Custom complexity values
92
- # # Complexity can be a number or a proc.
93
- #
94
- # # Complexity can be defined with a keyword:
95
- # field :expensive_calculation, !types.Int, complexity: 10
96
- #
97
- # # Or inside the block:
98
- # field :expensive_calculation_2, !types.Int do
99
- # complexity ->(ctx, args, child_complexity) { ctx[:current_user].staff? ? 0 : 10 }
100
- # end
101
- #
102
- # @example Calculating the complexity of a list field
103
- # field :items, types[ItemType] do
104
- # argument :limit, !types.Int
105
- # # Multiply the child complexity by the possible items on the list
106
- # complexity ->(ctx, args, child_complexity) { child_complexity * args[:limit] }
107
- # end
108
- #
109
- # @example Creating a field, then assigning it to a type
110
- # name_field = GraphQL::Field.define do
111
- # name("Name")
112
- # type(!types.String)
113
- # description("The name of this thing")
114
- # resolve ->(object, arguments, context) { object.name }
115
- # end
116
- #
117
- # NamedType = GraphQL::ObjectType.define do
118
- # # The second argument may be a GraphQL::Field
119
- # field :name, name_field
120
- # end
121
- #
5
+ # @api deprecated
122
6
  class Field
123
7
  include GraphQL::Define::InstanceDefinable
124
8
  accepts_definitions :name, :description, :deprecation_reason,
@@ -196,6 +80,10 @@ module GraphQL
196
80
 
197
81
  attr_accessor :ast_node
198
82
 
83
+ # Future-compatible alias
84
+ # @see {GraphQL::SchemaMember}
85
+ alias :graphql_definition :itself
86
+
199
87
  # @return [Boolean]
200
88
  def connection?
201
89
  @connection
@@ -266,7 +154,7 @@ module GraphQL
266
154
  end
267
155
 
268
156
  def name=(new_name)
269
- old_name = @name
157
+ old_name = defined?(@name) ? @name : nil
270
158
  @name = new_name
271
159
 
272
160
  if old_name != new_name && @resolve_proc.is_a?(Field::Resolve::NameResolve)
@@ -315,6 +203,14 @@ module GraphQL
315
203
  }
316
204
  end
317
205
 
206
+ def type_class
207
+ metadata[:type_class]
208
+ end
209
+
210
+ def get_argument(argument_name)
211
+ arguments[argument_name]
212
+ end
213
+
318
214
  private
319
215
 
320
216
  def build_default_resolver
@@ -33,7 +33,7 @@ module GraphQL
33
33
  end
34
34
 
35
35
  def self.build(onlies)
36
- case onlies
36
+ case onlies.size
37
37
  when 0
38
38
  nil
39
39
  when 1
@@ -1,35 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- # A reusable container for field logic, including arguments, resolve, return type, and documentation.
4
- #
5
- # Class-level values defined with the DSL will be inherited,
6
- # so {GraphQL::Function}s can extend one another.
7
- #
8
- # It's OK to override the instance methods here in order to customize behavior of instances.
9
- #
10
- # @example A reusable GraphQL::Function attached as a field
11
- # class FindRecord < GraphQL::Function
12
- # attr_reader :type
13
- #
14
- # def initialize(model:, type:)
15
- # @model = model
16
- # @type = type
17
- # end
18
- #
19
- # argument :id, GraphQL::ID_TYPE
20
- #
21
- # def call(obj, args, ctx)
22
- # @model.find(args.id)
23
- # end
24
- # end
25
- #
26
- # QueryType = GraphQL::ObjectType.define do
27
- # name "Query"
28
- # field :post, function: FindRecord.new(model: Post, type: PostType)
29
- # field :comment, function: FindRecord.new(model: Comment, type: CommentType)
30
- # end
31
- #
32
- # @see {GraphQL::Schema::Resolver} for a replacement for `GraphQL::Function`
3
+ # @api deprecated
33
4
  class Function
34
5
  # @return [Hash<String => GraphQL::Argument>] Arguments, keyed by name
35
6
  def arguments
@@ -1,28 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- # {InputObjectType}s are key-value inputs for fields.
4
- #
5
- # Input objects have _arguments_ which are identical to {GraphQL::Field} arguments.
6
- # They map names to types and support default values.
7
- # Their input types can be any input types, including {InputObjectType}s.
8
- #
9
- # @example An input type with name and number
10
- # PlayerInput = GraphQL::InputObjectType.define do
11
- # name("Player")
12
- # argument :name, !types.String
13
- # argument :number, !types.Int
14
- # end
15
- #
16
- # In a `resolve` function, you can access the values by making nested lookups on `args`.
17
- #
18
- # @example Accessing input values in a resolve function
19
- # resolve ->(obj, args, ctx) {
20
- # args[:player][:name] # => "Tony Gwynn"
21
- # args[:player][:number] # => 19
22
- # args[:player].to_h # { "name" => "Tony Gwynn", "number" => 19 }
23
- # # ...
24
- # }
25
- #
3
+ # @api deprecated
26
4
  class InputObjectType < GraphQL::BaseType
27
5
  accepts_definitions(
28
6
  :arguments, :mutation,
@@ -80,6 +58,10 @@ module GraphQL
80
58
  result
81
59
  end
82
60
 
61
+ def get_argument(argument_name)
62
+ arguments[argument_name]
63
+ end
64
+
83
65
  private
84
66
 
85
67
  def coerce_non_null_input(value, ctx)
@@ -136,7 +118,7 @@ module GraphQL
136
118
  # Items in the input that are unexpected
137
119
  input.each do |name, value|
138
120
  if visible_arguments_map[name].nil?
139
- result.add_problem("Field is not defined on #{self.name}", [name])
121
+ result.add_problem("Field is not defined on #{self.graphql_name}", [name])
140
122
  end
141
123
  end
142
124
 
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ # This error is raised when `Types::Int` is given an input value outside of 32-bit integer range.
4
+ #
5
+ # For really big integer values, consider `GraphQL::Types::BigInt`
6
+ #
7
+ # @see GraphQL::Types::Int which raises this error
8
+ class IntegerDecodingError < GraphQL::RuntimeTypeError
9
+ # The value which couldn't be decoded
10
+ attr_reader :integer_value
11
+
12
+ def initialize(value)
13
+ @integer_value = value
14
+ super("Integer out of bounds: #{value}. \nConsider using GraphQL::Types::BigInt instead.")
15
+ end
16
+ end
17
+ end
@@ -1,31 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- # An Interface contains a collection of types which implement some of the same fields.
4
- #
5
- # Interfaces can have fields, defined with `field`, just like an object type.
6
- #
7
- # Objects which implement this field _inherit_ field definitions from the interface.
8
- # An object type can override the inherited definition by redefining that field.
9
- #
10
- # @example An interface with three fields
11
- # DeviceInterface = GraphQL::InterfaceType.define do
12
- # name("Device")
13
- # description("Hardware devices for computing")
14
- #
15
- # field :ram, types.String
16
- # field :processor, ProcessorType
17
- # field :release_year, types.Int
18
- # end
19
- #
20
- # @example Implementing an interface with an object type
21
- # Laptoptype = GraphQL::ObjectType.define do
22
- # interfaces [DeviceInterface]
23
- # end
24
- #
3
+ # @api deprecated
25
4
  class InterfaceType < GraphQL::BaseType
26
5
  accepts_definitions :fields, :orphan_types, :resolve_type, field: GraphQL::Define::AssignObjectField
27
6
 
28
7
  attr_accessor :fields, :orphan_types, :resolve_type_proc
8
+ attr_writer :type_membership_class
29
9
  ensure_defined :fields, :orphan_types, :resolve_type_proc, :resolve_type
30
10
 
31
11
  def initialize
@@ -71,7 +51,7 @@ module GraphQL
71
51
  # @return [GraphQL::ObjectType, nil] The type named `type_name` if it exists and implements this {InterfaceType}, (else `nil`)
72
52
  def get_possible_type(type_name, ctx)
73
53
  type = ctx.query.get_type(type_name)
74
- type if type && ctx.query.schema.possible_types(self).include?(type)
54
+ type if type && ctx.query.warden.possible_types(self).include?(type)
75
55
  end
76
56
 
77
57
  # Check if a type is a possible type of this {InterfaceType}
@@ -82,5 +62,9 @@ module GraphQL
82
62
  type_name = type.is_a?(String) ? type : type.graphql_name
83
63
  !get_possible_type(type_name, ctx).nil?
84
64
  end
65
+
66
+ def type_membership_class
67
+ @type_membership_class || GraphQL::Schema::TypeMembership
68
+ end
85
69
  end
86
70
  end
@@ -66,11 +66,11 @@ module GraphQL
66
66
  # Call the block for each type in `self`.
67
67
  # This uses the simplest possible expression of `self`,
68
68
  # so if this scope is defined by an abstract type, it gets yielded.
69
- def each
69
+ def each(&block)
70
70
  if @abstract_type
71
71
  yield(@type)
72
72
  else
73
- @types.each { |t| yield(t) }
73
+ @types.each(&block)
74
74
  end
75
75
  end
76
76