graphql 1.10.0.pre1 → 1.10.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +1 -0
  3. data/lib/generators/graphql/install_generator.rb +1 -0
  4. data/lib/generators/graphql/mutation_generator.rb +1 -1
  5. data/lib/generators/graphql/templates/base_field.erb +0 -4
  6. data/lib/generators/graphql/templates/base_mutation.erb +8 -0
  7. data/lib/generators/graphql/templates/graphql_controller.erb +5 -0
  8. data/lib/generators/graphql/templates/mutation.erb +1 -1
  9. data/lib/generators/graphql/templates/schema.erb +1 -1
  10. data/lib/graphql.rb +4 -1
  11. data/lib/graphql/analysis/ast.rb +14 -13
  12. data/lib/graphql/analysis/ast/analyzer.rb +23 -4
  13. data/lib/graphql/analysis/ast/field_usage.rb +1 -1
  14. data/lib/graphql/analysis/ast/max_query_complexity.rb +3 -3
  15. data/lib/graphql/analysis/ast/max_query_depth.rb +7 -3
  16. data/lib/graphql/analysis/ast/query_complexity.rb +2 -2
  17. data/lib/graphql/analysis/ast/visitor.rb +3 -3
  18. data/lib/graphql/base_type.rb +1 -1
  19. data/lib/graphql/directive.rb +0 -1
  20. data/lib/graphql/directive/deprecated_directive.rb +1 -12
  21. data/lib/graphql/execution/errors.rb +4 -8
  22. data/lib/graphql/execution/interpreter.rb +5 -11
  23. data/lib/graphql/execution/interpreter/runtime.rb +56 -48
  24. data/lib/graphql/execution/lazy/lazy_method_map.rb +4 -0
  25. data/lib/graphql/execution/lookahead.rb +5 -5
  26. data/lib/graphql/execution/multiplex.rb +10 -0
  27. data/lib/graphql/function.rb +1 -1
  28. data/lib/graphql/input_object_type.rb +3 -2
  29. data/lib/graphql/interface_type.rb +1 -1
  30. data/lib/graphql/introspection/base_object.rb +2 -5
  31. data/lib/graphql/introspection/directive_type.rb +1 -1
  32. data/lib/graphql/introspection/entry_points.rb +6 -6
  33. data/lib/graphql/introspection/schema_type.rb +1 -6
  34. data/lib/graphql/introspection/type_type.rb +5 -5
  35. data/lib/graphql/language.rb +1 -1
  36. data/lib/graphql/language/block_string.rb +2 -2
  37. data/lib/graphql/language/definition_slice.rb +21 -10
  38. data/lib/graphql/language/document_from_schema_definition.rb +42 -42
  39. data/lib/graphql/language/lexer.rb +49 -48
  40. data/lib/graphql/language/lexer.rl +49 -48
  41. data/lib/graphql/language/nodes.rb +11 -8
  42. data/lib/graphql/language/parser.rb +4 -1
  43. data/lib/graphql/language/parser.y +4 -1
  44. data/lib/graphql/language/token.rb +1 -1
  45. data/lib/graphql/pagination/array_connection.rb +0 -1
  46. data/lib/graphql/pagination/connection.rb +31 -10
  47. data/lib/graphql/pagination/connections.rb +7 -2
  48. data/lib/graphql/pagination/relation_connection.rb +1 -7
  49. data/lib/graphql/query.rb +9 -4
  50. data/lib/graphql/query/arguments.rb +8 -1
  51. data/lib/graphql/query/literal_input.rb +2 -1
  52. data/lib/graphql/query/variables.rb +5 -1
  53. data/lib/graphql/relay/base_connection.rb +3 -3
  54. data/lib/graphql/relay/relation_connection.rb +9 -5
  55. data/lib/graphql/schema.rb +699 -153
  56. data/lib/graphql/schema/argument.rb +20 -4
  57. data/lib/graphql/schema/build_from_definition.rb +64 -31
  58. data/lib/graphql/schema/built_in_types.rb +5 -5
  59. data/lib/graphql/schema/directive.rb +16 -1
  60. data/lib/graphql/schema/directive/deprecated.rb +18 -0
  61. data/lib/graphql/schema/directive/feature.rb +1 -1
  62. data/lib/graphql/schema/enum.rb +39 -3
  63. data/lib/graphql/schema/field.rb +39 -9
  64. data/lib/graphql/schema/field/connection_extension.rb +4 -4
  65. data/lib/graphql/schema/find_inherited_value.rb +13 -0
  66. data/lib/graphql/schema/finder.rb +13 -11
  67. data/lib/graphql/schema/input_object.rb +109 -1
  68. data/lib/graphql/schema/interface.rb +8 -7
  69. data/lib/graphql/schema/introspection_system.rb +104 -36
  70. data/lib/graphql/schema/late_bound_type.rb +1 -0
  71. data/lib/graphql/schema/list.rb +26 -0
  72. data/lib/graphql/schema/loader.rb +10 -4
  73. data/lib/graphql/schema/member.rb +3 -0
  74. data/lib/graphql/schema/member/base_dsl_methods.rb +23 -13
  75. data/lib/graphql/schema/member/build_type.rb +1 -1
  76. data/lib/graphql/schema/member/has_arguments.rb +2 -2
  77. data/lib/graphql/schema/member/has_fields.rb +15 -6
  78. data/lib/graphql/schema/member/instrumentation.rb +6 -1
  79. data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
  80. data/lib/graphql/schema/member/validates_input.rb +33 -0
  81. data/lib/graphql/schema/non_null.rb +25 -0
  82. data/lib/graphql/schema/object.rb +14 -1
  83. data/lib/graphql/schema/printer.rb +4 -3
  84. data/lib/graphql/schema/relay_classic_mutation.rb +5 -1
  85. data/lib/graphql/schema/resolver.rb +20 -2
  86. data/lib/graphql/schema/scalar.rb +18 -3
  87. data/lib/graphql/schema/subscription.rb +1 -1
  88. data/lib/graphql/schema/timeout_middleware.rb +3 -2
  89. data/lib/graphql/schema/traversal.rb +1 -1
  90. data/lib/graphql/schema/type_expression.rb +22 -24
  91. data/lib/graphql/schema/validation.rb +17 -1
  92. data/lib/graphql/schema/warden.rb +46 -17
  93. data/lib/graphql/schema/wrapper.rb +1 -1
  94. data/lib/graphql/static_validation/base_visitor.rb +10 -6
  95. data/lib/graphql/static_validation/definition_dependencies.rb +21 -12
  96. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +4 -4
  97. data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
  98. data/lib/graphql/static_validation/type_stack.rb +2 -2
  99. data/lib/graphql/static_validation/validator.rb +1 -1
  100. data/lib/graphql/subscriptions.rb +38 -13
  101. data/lib/graphql/subscriptions/event.rb +24 -7
  102. data/lib/graphql/subscriptions/instrumentation.rb +1 -1
  103. data/lib/graphql/subscriptions/subscription_root.rb +0 -1
  104. data/lib/graphql/tracing/active_support_notifications_tracing.rb +10 -10
  105. data/lib/graphql/tracing/platform_tracing.rb +1 -2
  106. data/lib/graphql/tracing/skylight_tracing.rb +1 -0
  107. data/lib/graphql/unresolved_type_error.rb +2 -2
  108. data/lib/graphql/upgrader/member.rb +1 -1
  109. data/lib/graphql/version.rb +1 -1
  110. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d8cd9472c04900ca59a46d06eedf501e09d1f0561a5df1c902faada7c9536df
4
- data.tar.gz: 409d5ef50405fe5f6ca2f1c197e9c98696c3b89bbf35323e325e7a4bc157419c
3
+ metadata.gz: 0b0dea1cf870243e0c1ca99c9aa276b3ab6dca48c94048d99033c7e868d6edb7
4
+ data.tar.gz: a9067feb798b969d50e6cd3b436432adba4216ad8b66d58cd8cde2d76f9d5589
5
5
  SHA512:
6
- metadata.gz: '0511959efa6a890699def5ea1d681ed9000435903f078955ecdf0a4f4c1be409ea542cd8e8b9cced7f22e22df49115038bbb544d611b9f66a6fdb5ae75c92566'
7
- data.tar.gz: cb29aa9f21e13c65d4b700720cd2079968f6f6b709712e464133f78c383841c219c24bce7a5ffe6b6dd6577c6e7c03f282f259dca73896b669d2cfcaaa072abe
6
+ metadata.gz: d2effe2d2074b17026c7c6e3ddc71db82b1bd17ce8624dbdd9a88345ff39b2177ae48981deabdda227fb4bcf965469a5e874faeb76c0830d598fdb5501673c98
7
+ data.tar.gz: 810111555e1713e4d0d6afabba7102a03f458349d135d92f573236feedd116d81481ba7119c364d9533d39f1d98aa940ce32dc7d452008f6c00827796e5794ef
@@ -25,6 +25,7 @@ module Graphql
25
25
 
26
26
  def create_mutation_root_type
27
27
  create_dir("#{options[:directory]}/mutations")
28
+ template("base_mutation.erb", "#{options[:directory]}/mutations/base_mutation.rb", { skip: true })
28
29
  template("mutation_type.erb", "#{options[:directory]}/types/mutation_type.rb", { skip: true })
29
30
  insert_root_type('mutation', 'MutationType')
30
31
  end
@@ -24,6 +24,7 @@ module Graphql
24
24
  # - query_type.rb
25
25
  # - loaders/
26
26
  # - mutations/
27
+ # - base_mutation.rb
27
28
  # - {app_name}_schema.rb
28
29
  # ```
29
30
  #
@@ -45,7 +45,7 @@ module Graphql
45
45
  private
46
46
 
47
47
  def assign_names!(name)
48
- @field_name = name.camelize(:lower)
48
+ @field_name = name.camelize.underscore
49
49
  @mutation_name = name.camelize(:upper)
50
50
  @file_name = name.camelize.underscore
51
51
  end
@@ -1,9 +1,5 @@
1
1
  module Types
2
2
  class BaseField < GraphQL::Schema::Field
3
3
  argument_class Types::BaseArgument
4
-
5
- def resolve_field(obj, args, ctx)
6
- resolve(obj, args, ctx)
7
- end
8
4
  end
9
5
  end
@@ -0,0 +1,8 @@
1
+ module Mutations
2
+ class BaseMutation < GraphQL::Schema::RelayClassicMutation
3
+ argument_class Types::BaseArgument
4
+ field_class Types::BaseField
5
+ input_object_class Types::BaseInputObject
6
+ object_class Types::BaseObject
7
+ end
8
+ end
@@ -1,4 +1,9 @@
1
1
  class GraphqlController < ApplicationController
2
+ # If accessing from outside this domain, nullify the session
3
+ # This allows for outside API access while preventing CSRF attacks,
4
+ # but you'll have to authenticate your user separately
5
+ # protect_from_forgery with: :null_session
6
+
2
7
  def execute
3
8
  variables = ensure_hash(params[:variables])
4
9
  query = params[:query]
@@ -1,5 +1,5 @@
1
1
  module Mutations
2
- class <%= mutation_name %> < GraphQL::Schema::RelayClassicMutation
2
+ class <%= mutation_name %> < BaseMutation
3
3
  # TODO: define return fields
4
4
  # field :post, Types::PostType, null: false
5
5
 
@@ -24,7 +24,7 @@ class <%= schema_name %> < GraphQL::Schema
24
24
  def self.resolve_type(type, obj, ctx)
25
25
  # TODO: Implement this function
26
26
  # to return the correct type for `obj`
27
- raise(NotImplementedError)
27
+ raise(GraphQL::RequiredImplementationMissingError)
28
28
  end
29
29
  <% end %><% if options[:batch] %>
30
30
  # GraphQL::Batch setup:
@@ -10,6 +10,9 @@ module GraphQL
10
10
  class Error < StandardError
11
11
  end
12
12
 
13
+ class RequiredImplementationMissingError < Error
14
+ end
15
+
13
16
  # Turn a query string or schema definition into an AST
14
17
  # @param graphql_string [String] a GraphQL query string or schema definition
15
18
  # @return [GraphQL::Language::Nodes::Document]
@@ -81,6 +84,7 @@ require "graphql/tracing"
81
84
  require "graphql/execution"
82
85
  require "graphql/dig"
83
86
  require "graphql/schema"
87
+ require "graphql/query"
84
88
  require "graphql/directive"
85
89
  require "graphql/execution"
86
90
  require "graphql/types"
@@ -104,7 +108,6 @@ require "graphql/invalid_name_error"
104
108
  require "graphql/unresolved_type_error"
105
109
  require "graphql/integer_encoding_error"
106
110
  require "graphql/string_encoding_error"
107
- require "graphql/query"
108
111
  require "graphql/internal_representation"
109
112
  require "graphql/static_validation"
110
113
  require "graphql/version"
@@ -12,9 +12,8 @@ module GraphQL
12
12
  module AST
13
13
  module_function
14
14
 
15
- def use(schema_defn)
16
- schema = schema_defn.target
17
- schema.analysis_engine = GraphQL::Analysis::AST
15
+ def use(schema_class)
16
+ schema_class.analysis_engine = GraphQL::Analysis::AST
18
17
  end
19
18
 
20
19
  # Analyze a multiplex, and all queries within.
@@ -23,7 +22,7 @@ module GraphQL
23
22
  #
24
23
  # @param multiplex [GraphQL::Execution::Multiplex]
25
24
  # @param analyzers [Array<GraphQL::Analysis::AST::Analyzer>]
26
- # @return [void]
25
+ # @return [Array<Any>] Results from multiplex analyzers
27
26
  def analyze_multiplex(multiplex, analyzers)
28
27
  multiplex_analyzers = analyzers.map { |analyzer| analyzer.new(multiplex) }
29
28
 
@@ -46,8 +45,8 @@ module GraphQL
46
45
  multiplex.queries.each_with_index do |query, idx|
47
46
  query.analysis_errors = multiplex_errors + analysis_errors(query_results[idx])
48
47
  end
48
+ multiplex_results
49
49
  end
50
- nil
51
50
  end
52
51
 
53
52
  # @param query [GraphQL::Query]
@@ -60,16 +59,18 @@ module GraphQL
60
59
  .select { |analyzer| analyzer.analyze? }
61
60
 
62
61
  analyzers_to_run = query_analyzers + multiplex_analyzers
63
- return [] unless analyzers_to_run.any?
62
+ if analyzers_to_run.any?
63
+ visitor = GraphQL::Analysis::AST::Visitor.new(
64
+ query: query,
65
+ analyzers: analyzers_to_run
66
+ )
64
67
 
65
- visitor = GraphQL::Analysis::AST::Visitor.new(
66
- query: query,
67
- analyzers: analyzers_to_run
68
- )
68
+ visitor.visit
69
69
 
70
- visitor.visit
71
-
72
- query_analyzers.map(&:result)
70
+ query_analyzers.map(&:result)
71
+ else
72
+ []
73
+ end
73
74
  end
74
75
  end
75
76
 
@@ -5,10 +5,21 @@ module GraphQL
5
5
  # Query analyzer for query ASTs. Query analyzers respond to visitor style methods
6
6
  # but are prefixed by `enter` and `leave`.
7
7
  #
8
- # @param [GraphQL::Query] The query to analyze
8
+ # When an analyzer is initialized with a Multiplex, you can always get the current query from
9
+ # `visitor.query` in the visit methods.
10
+ #
11
+ # @param [GraphQL::Query, GraphQL::Execution::Multiplex] The query or multiplex to analyze
9
12
  class Analyzer
10
- def initialize(query)
11
- @query = query
13
+ def initialize(subject)
14
+ @subject = subject
15
+
16
+ if subject.is_a?(GraphQL::Query)
17
+ @query = subject
18
+ @multiplex = nil
19
+ else
20
+ @multiplex = subject
21
+ @query = nil
22
+ end
12
23
  end
13
24
 
14
25
  # Analyzer hook to decide at analysis time whether a query should
@@ -22,7 +33,7 @@ module GraphQL
22
33
  # in a query error.
23
34
  # @return [Any] The analyzer result
24
35
  def result
25
- raise NotImplementedError
36
+ raise GraphQL::RequiredImplementationMissingError
26
37
  end
27
38
 
28
39
  class << self
@@ -58,7 +69,15 @@ module GraphQL
58
69
 
59
70
  protected
60
71
 
72
+ # @return [GraphQL::Query, GraphQL::Execution::Multiplex] Whatever this analyzer is analyzing
73
+ attr_reader :subject
74
+
75
+ # @return [GraphQL::Query, nil] `nil` if this analyzer is visiting a multiplex
76
+ # (When this is `nil`, use `visitor.query` inside visit methods to get the current query)
61
77
  attr_reader :query
78
+
79
+ # @return [GraphQL::Execution::Multiplex, nil] `nil` if this analyzer is visiting a query
80
+ attr_reader :multiplex
62
81
  end
63
82
  end
64
83
  end
@@ -11,7 +11,7 @@ module GraphQL
11
11
 
12
12
  def on_leave_field(node, parent, visitor)
13
13
  field_defn = visitor.field_definition
14
- field = "#{visitor.parent_type_definition.name}.#{field_defn.name}"
14
+ field = "#{visitor.parent_type_definition.graphql_name}.#{field_defn.graphql_name}"
15
15
  @used_fields << field
16
16
  @used_deprecated_fields << field if field_defn.deprecation_reason
17
17
  end
@@ -7,12 +7,12 @@ module GraphQL
7
7
  # see {Schema#max_complexity} and {Query#max_complexity}
8
8
  class MaxQueryComplexity < QueryComplexity
9
9
  def result
10
- return if query.max_complexity.nil?
10
+ return if subject.max_complexity.nil?
11
11
 
12
12
  total_complexity = max_possible_complexity
13
13
 
14
- if total_complexity > query.max_complexity
15
- GraphQL::AnalysisError.new("Query has complexity of #{total_complexity}, which exceeds max complexity of #{query.max_complexity}")
14
+ if total_complexity > subject.max_complexity
15
+ GraphQL::AnalysisError.new("Query has complexity of #{total_complexity}, which exceeds max complexity of #{subject.max_complexity}")
16
16
  else
17
17
  nil
18
18
  end
@@ -4,10 +4,14 @@ module GraphQL
4
4
  module AST
5
5
  class MaxQueryDepth < QueryDepth
6
6
  def result
7
- return unless query.max_depth
7
+ configured_max_depth = if query
8
+ query.max_depth
9
+ else
10
+ multiplex.schema.max_depth
11
+ end
8
12
 
9
- if @max_depth > query.max_depth
10
- GraphQL::AnalysisError.new("Query has depth of #{@max_depth}, which exceeds max depth of #{query.max_depth}")
13
+ if configured_max_depth && @max_depth > configured_max_depth
14
+ GraphQL::AnalysisError.new("Query has depth of #{@max_depth}, which exceeds max depth of #{configured_max_depth}")
11
15
  else
12
16
  nil
13
17
  end
@@ -42,7 +42,7 @@ module GraphQL
42
42
  if @complexities_on_type.last.is_a?(AbstractTypeComplexity)
43
43
  key = selection_key(visitor.response_path, visitor.query)
44
44
  parent_type = visitor.parent_type_definition
45
- query.possible_types(parent_type).each do |type|
45
+ visitor.query.possible_types(parent_type).each do |type|
46
46
  @complexities_on_type.last.merge(type, key, own_complexity)
47
47
  end
48
48
  else
@@ -74,7 +74,7 @@ module GraphQL
74
74
 
75
75
  case defined_complexity
76
76
  when Proc
77
- defined_complexity.call(query.context, arguments, child_complexity)
77
+ defined_complexity.call(visitor.query.context, arguments, child_complexity)
78
78
  when Numeric
79
79
  defined_complexity + (child_complexity || 0)
80
80
  else
@@ -134,7 +134,7 @@ module GraphQL
134
134
  argument_defn = if (arg = @argument_definitions.last)
135
135
  arg_type = arg.type.unwrap
136
136
  if arg_type.kind.input_object?
137
- arg_type.input_fields[node.name]
137
+ arg_type.arguments[node.name]
138
138
  else
139
139
  nil
140
140
  end
@@ -214,7 +214,7 @@ module GraphQL
214
214
  fragment_def = query.fragments[fragment_spread.name]
215
215
 
216
216
  object_type = if fragment_def.type
217
- query.schema.types.fetch(fragment_def.type.name, nil)
217
+ @query.warden.get_type(fragment_def.type.name)
218
218
  else
219
219
  object_types.last
220
220
  end
@@ -245,7 +245,7 @@ module GraphQL
245
245
 
246
246
  def on_fragment_with_type(node)
247
247
  object_type = if node.type
248
- @schema.types.fetch(node.type.name, nil)
248
+ @query.warden.get_type(node.type.name)
249
249
  else
250
250
  @object_types.last
251
251
  end
@@ -171,7 +171,7 @@ module GraphQL
171
171
  end
172
172
 
173
173
  def coerce_result(value, ctx)
174
- raise NotImplementedError
174
+ raise GraphQL::RequiredImplementationMissingError
175
175
  end
176
176
 
177
177
  # Types with fields may override this
@@ -45,7 +45,6 @@ module GraphQL
45
45
  INPUT_FIELD_DEFINITION = :INPUT_FIELD_DEFINITION,
46
46
  ]
47
47
 
48
- DEFAULT_DEPRECATION_REASON = 'No longer supported'
49
48
  LOCATION_DESCRIPTIONS = {
50
49
  QUERY: 'Location adjacent to a query operation.',
51
50
  MUTATION: 'Location adjacent to a mutation operation.',
@@ -1,13 +1,2 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::Directive::DeprecatedDirective = GraphQL::Directive.define do
3
- name "deprecated"
4
- description "Marks an element of a GraphQL schema as no longer supported."
5
- locations([GraphQL::Directive::FIELD_DEFINITION, GraphQL::Directive::ENUM_VALUE])
6
-
7
- reason_description = "Explains why this element was deprecated, usually also including a "\
8
- "suggestion for how to access supported similar data. Formatted "\
9
- "in [Markdown](https://daringfireball.net/projects/markdown/)."
10
-
11
- argument :reason, GraphQL::STRING_TYPE, reason_description, default_value: GraphQL::Directive::DEFAULT_DEPRECATION_REASON
12
- default_directive true
13
- end
2
+ GraphQL::Directive::DeprecatedDirective = GraphQL::Schema::Directive::Deprecated.graphql_definition
@@ -18,12 +18,7 @@ module GraphQL
18
18
  #
19
19
  class Errors
20
20
  def self.use(schema)
21
- schema_class = schema.is_a?(Class) ? schema : schema.target.class
22
- schema.tracer(self.new(schema_class))
23
- end
24
-
25
- def initialize(schema)
26
- @schema = schema
21
+ schema.tracer(self.new)
27
22
  end
28
23
 
29
24
  def trace(event, data)
@@ -40,12 +35,13 @@ module GraphQL
40
35
  def with_error_handling(trace_data)
41
36
  yield
42
37
  rescue StandardError => err
43
- rescues = @schema.rescues
38
+ ctx = trace_data[:query].context
39
+ schema = ctx.schema
40
+ rescues = schema.rescues
44
41
  _err_class, handler = rescues.find { |err_class, handler| err.is_a?(err_class) }
45
42
  if handler
46
43
  obj = trace_data[:object]
47
44
  args = trace_data[:arguments]
48
- ctx = trace_data[:query].context
49
45
  field = trace_data[:field]
50
46
  if obj.is_a?(GraphQL::Schema::Object)
51
47
  obj = obj.object
@@ -17,17 +17,11 @@ module GraphQL
17
17
  runtime.final_value
18
18
  end
19
19
 
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
20
+ def self.use(schema_class)
21
+ schema_class.interpreter = true
22
+ schema_class.query_execution_strategy(GraphQL::Execution::Interpreter)
23
+ schema_class.mutation_execution_strategy(GraphQL::Execution::Interpreter)
24
+ schema_class.subscription_execution_strategy(GraphQL::Execution::Interpreter)
31
25
  end
32
26
 
33
27
  def self.begin_multiplex(multiplex)
@@ -45,8 +45,7 @@ module GraphQL
45
45
  def run_eager
46
46
  root_operation = query.selected_operation
47
47
  root_op_type = root_operation.operation_type || "query"
48
- legacy_root_type = schema.root_type_for_operation(root_op_type)
49
- root_type = legacy_root_type.metadata[:type_class] || raise("Invariant: type must be class-based: #{legacy_root_type}")
48
+ root_type = schema.root_type_for_operation(root_op_type)
50
49
  object_proxy = root_type.authorized_new(query.root_value, context)
51
50
  object_proxy = schema.sync_lazy(object_proxy)
52
51
  if object_proxy.nil?
@@ -86,11 +85,10 @@ module GraphQL
86
85
  end
87
86
  when GraphQL::Language::Nodes::InlineFragment
88
87
  if node.type
89
- type_defn = schema.types[node.type.name]
90
- type_defn = type_defn.metadata[:type_class]
88
+ type_defn = schema.get_type(node.type.name)
91
89
  # Faster than .map{}.include?()
92
90
  query.warden.possible_types(type_defn).each do |t|
93
- if t.metadata[:type_class] == owner_type
91
+ if t == owner_type
94
92
  gather_selections(owner_object, owner_type, node.selections, selections_by_name)
95
93
  break
96
94
  end
@@ -101,10 +99,9 @@ module GraphQL
101
99
  end
102
100
  when GraphQL::Language::Nodes::FragmentSpread
103
101
  fragment_def = query.fragments[node.name]
104
- type_defn = schema.types[fragment_def.type.name]
105
- type_defn = type_defn.metadata[:type_class]
106
- schema.possible_types(type_defn).each do |t|
107
- if t.metadata[:type_class] == owner_type
102
+ type_defn = schema.get_type(fragment_def.type.name)
103
+ query.warden.possible_types(type_defn).each do |t|
104
+ if t == owner_type
108
105
  gather_selections(owner_object, owner_type, fragment_def.selections, selections_by_name)
109
106
  break
110
107
  end
@@ -133,18 +130,18 @@ module GraphQL
133
130
  field_defn = @fields_cache[owner_type][field_name] ||= owner_type.get_field(field_name)
134
131
  is_introspection = false
135
132
  if field_defn.nil?
136
- field_defn = if owner_type == schema.query.metadata[:type_class] && (entry_point_field = schema.introspection_system.entry_point(name: field_name))
133
+ field_defn = if owner_type == schema.query && (entry_point_field = schema.introspection_system.entry_point(name: field_name))
137
134
  is_introspection = true
138
- entry_point_field.metadata[:type_class]
135
+ entry_point_field
139
136
  elsif (dynamic_field = schema.introspection_system.dynamic_field(name: field_name))
140
137
  is_introspection = true
141
- dynamic_field.metadata[:type_class]
138
+ dynamic_field
142
139
  else
143
140
  raise "Invariant: no field for #{owner_type}.#{field_name}"
144
141
  end
145
142
  end
146
143
 
147
- return_type = resolve_if_late_bound_type(field_defn.type)
144
+ return_type = field_defn.type
148
145
 
149
146
  next_path = path.dup
150
147
  next_path << result_name
@@ -296,7 +293,6 @@ module GraphQL
296
293
  write_in_response(path, nil)
297
294
  nil
298
295
  else
299
- resolved_type = resolved_type.metadata[:type_class]
300
296
  continue_field(path, value, field, resolved_type, ast_node, next_selections, is_non_null, owner_object, arguments)
301
297
  end
302
298
  end
@@ -338,8 +334,6 @@ module GraphQL
338
334
  response_list
339
335
  when "NON_NULL"
340
336
  inner_type = type.of_type
341
- # For fields like `__schema: __Schema!`
342
- inner_type = resolve_if_late_bound_type(inner_type)
343
337
  # Don't `set_type_at_path` because we want the static type,
344
338
  # we're going to use that to determine whether a `nil` should be propagated or not.
345
339
  continue_field(path, value, field, inner_type, ast_node, next_selections, true, owner_object, arguments)
@@ -359,7 +353,7 @@ module GraphQL
359
353
  else
360
354
  dir_defn = schema.directives.fetch(dir_node.name)
361
355
  if !dir_defn.is_a?(Class)
362
- dir_defn = dir_defn.metadata[:type_class] || raise("Only class-based directives are supported (not `@#{dir_node.name}`)")
356
+ dir_defn = dir_defn.type_class || raise("Only class-based directives are supported (not `@#{dir_node.name}`)")
363
357
  end
364
358
  dir_args = arguments(nil, dir_defn, dir_node)
365
359
  dir_defn.resolve(object, dir_args, context) do
@@ -371,7 +365,7 @@ module GraphQL
371
365
  # Check {Schema::Directive.include?} for each directive that's present
372
366
  def directives_include?(node, graphql_object, parent_type)
373
367
  node.directives.each do |dir_node|
374
- dir_defn = schema.directives.fetch(dir_node.name).metadata[:type_class] || raise("Only class-based directives are supported (not #{dir_node.name.inspect})")
368
+ dir_defn = schema.directives.fetch(dir_node.name).type_class || raise("Only class-based directives are supported (not #{dir_node.name.inspect})")
375
369
  args = arguments(graphql_object, dir_defn, dir_node)
376
370
  if !dir_defn.include?(graphql_object, args, context)
377
371
  return false
@@ -380,14 +374,6 @@ module GraphQL
380
374
  true
381
375
  end
382
376
 
383
- def resolve_if_late_bound_type(type)
384
- if type.is_a?(GraphQL::Schema::LateBoundType)
385
- query.warden.get_type(type.name).metadata[:type_class]
386
- else
387
- type
388
- end
389
- end
390
-
391
377
  # @param obj [Object] Some user-returned value that may want to be batched
392
378
  # @param path [Array<String>]
393
379
  # @param field [GraphQL::Schema::Field]
@@ -448,7 +434,7 @@ module GraphQL
448
434
  arg_defn = arg_defns[arg_name]
449
435
  # Need to distinguish between client-provided `nil`
450
436
  # and nothing-at-all
451
- is_present, value = arg_to_value(graphql_object, arg_defn.type, arg_value)
437
+ is_present, value = arg_to_value(graphql_object, arg_defn.type, arg_value, already_arguments: false)
452
438
  if is_present
453
439
  # This doesn't apply to directives, which are legacy
454
440
  # Can remove this when Skip and Include use classes or something.
@@ -460,50 +446,72 @@ module GraphQL
460
446
  end
461
447
  arg_defns.each do |name, arg_defn|
462
448
  if arg_defn.default_value? && !kwarg_arguments.key?(arg_defn.keyword)
463
- _is_present, value = arg_to_value(graphql_object, arg_defn.type, arg_defn.default_value)
449
+ _is_present, value = arg_to_value(graphql_object, arg_defn.type, arg_defn.default_value, already_arguments: false)
464
450
  kwarg_arguments[arg_defn.keyword] = value
465
451
  end
466
452
  end
467
453
  kwarg_arguments
468
454
  end
469
455
 
456
+ # TODO CAN THIS USE `.coerce_input` ???
457
+
470
458
  # Get a Ruby-ready value from a client query.
471
459
  # @param graphql_object [Object] The owner of the field whose argument this is
472
460
  # @param arg_type [Class, GraphQL::Schema::NonNull, GraphQL::Schema::List]
473
461
  # @param ast_value [GraphQL::Language::Nodes::VariableIdentifier, String, Integer, Float, Boolean]
462
+ # @param already_arguments [Boolean] if true, don't re-coerce these with `arguments(...)`
474
463
  # @return [Array(is_present, value)]
475
- def arg_to_value(graphql_object, arg_type, ast_value)
464
+ def arg_to_value(graphql_object, arg_type, ast_value, already_arguments:)
476
465
  if ast_value.is_a?(GraphQL::Language::Nodes::VariableIdentifier)
477
466
  # If it's not here, it will get added later
478
467
  if query.variables.key?(ast_value.name)
479
- return true, query.variables[ast_value.name]
468
+ variable_value = query.variables[ast_value.name]
469
+ arg_to_value(graphql_object, arg_type, variable_value, already_arguments: true)
480
470
  else
481
471
  return false, nil
482
472
  end
483
473
  elsif ast_value.is_a?(GraphQL::Language::Nodes::NullValue)
484
474
  return true, nil
485
475
  elsif arg_type.is_a?(GraphQL::Schema::NonNull)
486
- arg_to_value(graphql_object, arg_type.of_type, ast_value)
476
+ arg_to_value(graphql_object, arg_type.of_type, ast_value, already_arguments: already_arguments)
487
477
  elsif arg_type.is_a?(GraphQL::Schema::List)
488
- # Treat a single value like a list
489
- arg_value = Array(ast_value)
490
- list = []
491
- arg_value.map do |inner_v|
492
- _present, value = arg_to_value(graphql_object, arg_type.of_type, inner_v)
493
- list << value
494
- end
495
- return true, list
478
+ if ast_value.nil?
479
+ return true, nil
480
+ else
481
+ # Treat a single value like a list
482
+ arg_value = Array(ast_value)
483
+ list = []
484
+ arg_value.map do |inner_v|
485
+ _present, value = arg_to_value(graphql_object, arg_type.of_type, inner_v, already_arguments: already_arguments)
486
+ list << value
487
+ end
488
+ return true, list
489
+ end
496
490
  elsif arg_type.is_a?(Class) && arg_type < GraphQL::Schema::InputObject
497
- # For these, `prepare` is applied during `#initialize`.
498
- # Pass `nil` so it will be skipped in `#arguments`.
499
- # What a mess.
500
- args = arguments(nil, arg_type, ast_value)
501
- # We're not tracking defaults_used, but for our purposes
502
- # we compare the value to the default value.
503
- return true, arg_type.new(ruby_kwargs: args, context: context, defaults_used: nil)
491
+ if already_arguments
492
+ # This came from a variable, already prepared.
493
+ # But replace `nil` with `{}` like we would for `arg_type`
494
+ if ast_value.nil?
495
+ return false, nil
496
+ else
497
+ return true, arg_type.new(ruby_kwargs: ast_value, context: context, defaults_used: nil)
498
+ end
499
+ else
500
+ # For these, `prepare` is applied during `#initialize`.
501
+ # Pass `nil` so it will be skipped in `#arguments`.
502
+ # What a mess.
503
+ args = arguments(nil, arg_type, ast_value)
504
+ return true, arg_type.new(ruby_kwargs: args, context: context, defaults_used: nil)
505
+ end
504
506
  else
505
- flat_value = flatten_ast_value(ast_value)
506
- return true, arg_type.coerce_input(flat_value, context)
507
+ flat_value = if already_arguments
508
+ # It was coerced by variable handling
509
+ ast_value
510
+ else
511
+ v = flatten_ast_value(ast_value)
512
+ arg_type.coerce_input(v, context)
513
+ end
514
+ return true, flat_value
507
515
  end
508
516
  end
509
517