graphql 2.0.26 → 2.1.1

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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
  3. data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
  4. data/lib/generators/graphql/relay.rb +18 -1
  5. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  6. data/lib/generators/graphql/templates/base_connection.erb +2 -0
  7. data/lib/generators/graphql/templates/base_edge.erb +2 -0
  8. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  9. data/lib/generators/graphql/templates/base_field.erb +2 -0
  10. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  11. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  12. data/lib/generators/graphql/templates/base_object.erb +2 -0
  13. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  14. data/lib/generators/graphql/templates/base_union.erb +2 -0
  15. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  16. data/lib/generators/graphql/templates/loader.erb +2 -0
  17. data/lib/generators/graphql/templates/mutation.erb +2 -0
  18. data/lib/generators/graphql/templates/node_type.erb +2 -0
  19. data/lib/generators/graphql/templates/query_type.erb +2 -0
  20. data/lib/generators/graphql/templates/schema.erb +2 -0
  21. data/lib/graphql/analysis/ast/analyzer.rb +7 -0
  22. data/lib/graphql/analysis/ast/visitor.rb +2 -2
  23. data/lib/graphql/analysis/ast.rb +15 -11
  24. data/lib/graphql/dataloader/source.rb +7 -0
  25. data/lib/graphql/dataloader.rb +9 -0
  26. data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +170 -0
  27. data/lib/graphql/execution/interpreter/runtime.rb +95 -254
  28. data/lib/graphql/execution/interpreter.rb +0 -6
  29. data/lib/graphql/execution/lookahead.rb +1 -1
  30. data/lib/graphql/introspection/dynamic_fields.rb +1 -1
  31. data/lib/graphql/introspection/entry_points.rb +2 -2
  32. data/lib/graphql/language/block_string.rb +28 -16
  33. data/lib/graphql/language/definition_slice.rb +1 -1
  34. data/lib/graphql/language/document_from_schema_definition.rb +36 -35
  35. data/lib/graphql/language/lexer.rb +86 -56
  36. data/lib/graphql/language/nodes.rb +2 -2
  37. data/lib/graphql/language/parser.rb +706 -691
  38. data/lib/graphql/language/parser.y +1 -0
  39. data/lib/graphql/language/printer.rb +294 -145
  40. data/lib/graphql/language/sanitized_printer.rb +20 -22
  41. data/lib/graphql/language/static_visitor.rb +167 -0
  42. data/lib/graphql/language/visitor.rb +20 -81
  43. data/lib/graphql/language.rb +1 -0
  44. data/lib/graphql/pagination/connection.rb +23 -1
  45. data/lib/graphql/query/context/scoped_context.rb +101 -0
  46. data/lib/graphql/query/context.rb +32 -98
  47. data/lib/graphql/query.rb +2 -19
  48. data/lib/graphql/rake_task.rb +3 -12
  49. data/lib/graphql/schema/addition.rb +6 -0
  50. data/lib/graphql/schema/directive/specified_by.rb +14 -0
  51. data/lib/graphql/schema/field/connection_extension.rb +1 -15
  52. data/lib/graphql/schema/field/scope_extension.rb +7 -1
  53. data/lib/graphql/schema/field.rb +7 -4
  54. data/lib/graphql/schema/has_single_input_argument.rb +156 -0
  55. data/lib/graphql/schema/introspection_system.rb +2 -0
  56. data/lib/graphql/schema/member/base_dsl_methods.rb +2 -1
  57. data/lib/graphql/schema/member/has_arguments.rb +14 -2
  58. data/lib/graphql/schema/member/has_fields.rb +4 -1
  59. data/lib/graphql/schema/member/has_interfaces.rb +21 -7
  60. data/lib/graphql/schema/member/scoped.rb +19 -0
  61. data/lib/graphql/schema/object.rb +8 -0
  62. data/lib/graphql/schema/printer.rb +8 -7
  63. data/lib/graphql/schema/relay_classic_mutation.rb +6 -128
  64. data/lib/graphql/schema/resolver.rb +14 -8
  65. data/lib/graphql/schema/scalar.rb +3 -3
  66. data/lib/graphql/schema/subscription.rb +11 -4
  67. data/lib/graphql/schema/validator.rb +1 -1
  68. data/lib/graphql/schema/warden.rb +23 -37
  69. data/lib/graphql/schema.rb +23 -22
  70. data/lib/graphql/static_validation/all_rules.rb +1 -1
  71. data/lib/graphql/static_validation/base_visitor.rb +1 -1
  72. data/lib/graphql/static_validation/literal_validator.rb +1 -1
  73. data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
  74. data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
  75. data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +1 -1
  76. data/lib/graphql/static_validation/validation_context.rb +5 -5
  77. data/lib/graphql/static_validation.rb +0 -1
  78. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +2 -1
  79. data/lib/graphql/subscriptions.rb +11 -6
  80. data/lib/graphql/tracing/appoptics_trace.rb +2 -2
  81. data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
  82. data/lib/graphql/types/relay/connection_behaviors.rb +19 -2
  83. data/lib/graphql/types/relay/edge_behaviors.rb +7 -0
  84. data/lib/graphql/version.rb +1 -1
  85. data/lib/graphql.rb +1 -2
  86. metadata +7 -4
  87. data/lib/graphql/filter.rb +0 -59
  88. data/lib/graphql/static_validation/type_stack.rb +0 -216
@@ -30,6 +30,10 @@ module GraphQL
30
30
  # @see authorized_new to make instances
31
31
  protected :new
32
32
 
33
+ def wrap_scoped(object, context)
34
+ scoped_new(object, context)
35
+ end
36
+
33
37
  # This is called by the runtime to return an object to call methods on.
34
38
  def wrap(object, context)
35
39
  authorized_new(object, context)
@@ -91,6 +95,10 @@ module GraphQL
91
95
  end
92
96
  end
93
97
  end
98
+
99
+ def scoped_new(object, context)
100
+ self.new(object, context)
101
+ end
94
102
  end
95
103
 
96
104
  def initialize(object, context)
@@ -36,15 +36,11 @@ module GraphQL
36
36
 
37
37
  # @param schema [GraphQL::Schema]
38
38
  # @param context [Hash]
39
- # @param only [<#call(member, ctx)>]
40
- # @param except [<#call(member, ctx)>]
41
39
  # @param introspection [Boolean] Should include the introspection types in the string?
42
- def initialize(schema, context: nil, only: nil, except: nil, introspection: false)
40
+ def initialize(schema, context: nil, introspection: false)
43
41
  @document_from_schema = GraphQL::Language::DocumentFromSchemaDefinition.new(
44
42
  schema,
45
43
  context: context,
46
- only: only,
47
- except: except,
48
44
  include_introspection_types: introspection,
49
45
  )
50
46
 
@@ -61,7 +57,12 @@ module GraphQL
61
57
  false
62
58
  end
63
59
  end
64
- schema = Class.new(GraphQL::Schema) { query(query_root) }
60
+ schema = Class.new(GraphQL::Schema) {
61
+ query(query_root)
62
+ def self.visible?(member, _ctx)
63
+ member.graphql_name != "Root"
64
+ end
65
+ }
65
66
 
66
67
  introspection_schema_ast = GraphQL::Language::DocumentFromSchemaDefinition.new(
67
68
  schema,
@@ -94,7 +95,7 @@ module GraphQL
94
95
 
95
96
  class IntrospectionPrinter < GraphQL::Language::Printer
96
97
  def print_schema_definition(schema)
97
- "schema {\n query: Root\n}"
98
+ print_string("schema {\n query: Root\n}")
98
99
  end
99
100
  end
100
101
  end
@@ -21,6 +21,10 @@ module GraphQL
21
21
  # @see {GraphQL::Schema::Mutation} for an example, it's basically the same.
22
22
  #
23
23
  class RelayClassicMutation < GraphQL::Schema::Mutation
24
+ include GraphQL::Schema::HasSingleInputArgument
25
+
26
+ argument :client_mutation_id, String, "A unique identifier for the client performing the mutation.", required: false
27
+
24
28
  # The payload should always include this field
25
29
  field(:client_mutation_id, String, "A unique identifier for the client performing the mutation.")
26
30
  # Relay classic default:
@@ -31,34 +35,14 @@ module GraphQL
31
35
  def resolve_with_support(**inputs)
32
36
  input = inputs[:input].to_kwargs
33
37
 
34
- new_extras = field ? field.extras : []
35
- all_extras = self.class.extras + new_extras
36
-
37
- # Transfer these from the top-level hash to the
38
- # shortcutted `input:` object
39
- all_extras.each do |ext|
40
- # It's possible that the `extra` was not passed along by this point,
41
- # don't re-add it if it wasn't given here.
42
- if inputs.key?(ext)
43
- input[ext] = inputs[ext]
44
- end
45
- end
46
-
47
38
  if input
48
39
  # This is handled by Relay::Mutation::Resolve, a bit hacky, but here we are.
49
40
  input_kwargs = input.to_h
50
41
  client_mutation_id = input_kwargs.delete(:client_mutation_id)
51
- else
52
- # Relay Classic Mutations with no `argument`s
53
- # don't require `input:`
54
- input_kwargs = {}
42
+ inputs[:input] = input_kwargs
55
43
  end
56
44
 
57
- return_value = if input_kwargs.any?
58
- super(**input_kwargs)
59
- else
60
- super()
61
- end
45
+ return_value = super(**inputs)
62
46
 
63
47
  context.query.after_lazy(return_value) do |return_hash|
64
48
  # It might be an error
@@ -68,112 +52,6 @@ module GraphQL
68
52
  return_hash
69
53
  end
70
54
  end
71
-
72
- class << self
73
- def dummy
74
- @dummy ||= begin
75
- d = Class.new(GraphQL::Schema::Resolver)
76
- d.argument_class(self.argument_class)
77
- # TODO make this lazier?
78
- d.argument(:input, input_type, description: "Parameters for #{self.graphql_name}")
79
- d
80
- end
81
- end
82
-
83
- def field_arguments(context = GraphQL::Query::NullContext)
84
- dummy.arguments(context)
85
- end
86
-
87
- def get_field_argument(name, context = GraphQL::Query::NullContext)
88
- dummy.get_argument(name, context)
89
- end
90
-
91
- def own_field_arguments
92
- dummy.own_arguments
93
- end
94
-
95
- def all_field_argument_definitions
96
- dummy.all_argument_definitions
97
- end
98
-
99
- # Also apply this argument to the input type:
100
- def argument(*args, own_argument: false, **kwargs, &block)
101
- it = input_type # make sure any inherited arguments are already added to it
102
- arg = super(*args, **kwargs, &block)
103
-
104
- # This definition might be overriding something inherited;
105
- # if it is, remove the inherited definition so it's not confused at runtime as having multiple definitions
106
- prev_args = it.own_arguments[arg.graphql_name]
107
- case prev_args
108
- when GraphQL::Schema::Argument
109
- if prev_args.owner != self
110
- it.own_arguments.delete(arg.graphql_name)
111
- end
112
- when Array
113
- prev_args.reject! { |a| a.owner != self }
114
- if prev_args.empty?
115
- it.own_arguments.delete(arg.graphql_name)
116
- end
117
- end
118
-
119
- it.add_argument(arg)
120
- arg
121
- end
122
-
123
- # The base class for generated input object types
124
- # @param new_class [Class] The base class to use for generating input object definitions
125
- # @return [Class] The base class for this mutation's generated input object (default is {GraphQL::Schema::InputObject})
126
- def input_object_class(new_class = nil)
127
- if new_class
128
- @input_object_class = new_class
129
- end
130
- @input_object_class || (superclass.respond_to?(:input_object_class) ? superclass.input_object_class : GraphQL::Schema::InputObject)
131
- end
132
-
133
- # @param new_input_type [Class, nil] If provided, it configures this mutation to accept `new_input_type` instead of generating an input type
134
- # @return [Class] The generated {Schema::InputObject} class for this mutation's `input`
135
- def input_type(new_input_type = nil)
136
- if new_input_type
137
- @input_type = new_input_type
138
- end
139
- @input_type ||= generate_input_type
140
- end
141
-
142
- private
143
-
144
- # Generate the input type for the `input:` argument
145
- # To customize how input objects are generated, override this method
146
- # @return [Class] a subclass of {.input_object_class}
147
- def generate_input_type
148
- mutation_args = all_argument_definitions
149
- mutation_class = self
150
- Class.new(input_object_class) do
151
- class << self
152
- def default_graphql_name
153
- "#{self.mutation.graphql_name}Input"
154
- end
155
-
156
- def description(new_desc = nil)
157
- super || "Autogenerated input type of #{self.mutation.graphql_name}"
158
- end
159
- end
160
- mutation(mutation_class)
161
- # these might be inherited:
162
- mutation_args.each do |arg|
163
- add_argument(arg)
164
- end
165
- argument :client_mutation_id, String, "A unique identifier for the client performing the mutation.", required: false
166
- end
167
- end
168
- end
169
-
170
- private
171
-
172
- def authorize_arguments(args, values)
173
- # remove the `input` wrapper to match values
174
- input_args = args["input"].type.unwrap.arguments(context)
175
- super(input_args, values)
176
- end
177
55
  end
178
56
  end
179
57
  end
@@ -65,19 +65,20 @@ module GraphQL
65
65
  # @api private
66
66
  def resolve_with_support(**args)
67
67
  # First call the ready? hook which may raise
68
- ready_val = if args.any?
68
+ raw_ready_val = if args.any?
69
69
  ready?(**args)
70
70
  else
71
71
  ready?
72
72
  end
73
- context.query.after_lazy(ready_val) do |is_ready, ready_early_return|
74
- if ready_early_return
73
+ context.query.after_lazy(raw_ready_val) do |ready_val|
74
+ if ready_val.is_a?(Array)
75
+ is_ready, ready_early_return = ready_val
75
76
  if is_ready != false
76
77
  raise "Unexpected result from #ready? (expected `true`, `false` or `[false, {...}]`): [#{is_ready.inspect}, #{ready_early_return.inspect}]"
77
78
  else
78
79
  ready_early_return
79
80
  end
80
- elsif is_ready
81
+ elsif ready_val
81
82
  # Then call each prepare hook, which may return a different value
82
83
  # for that argument, or may return a lazy object
83
84
  load_arguments_val = load_arguments(args)
@@ -85,21 +86,22 @@ module GraphQL
85
86
  @prepared_arguments = loaded_args
86
87
  Schema::Validator.validate!(self.class.validators, object, context, loaded_args, as: @field)
87
88
  # Then call `authorized?`, which may raise or may return a lazy object
88
- authorized_val = if loaded_args.any?
89
+ raw_authorized_val = if loaded_args.any?
89
90
  authorized?(**loaded_args)
90
91
  else
91
92
  authorized?
92
93
  end
93
- context.query.after_lazy(authorized_val) do |(authorized_result, early_return)|
94
+ context.query.after_lazy(raw_authorized_val) do |authorized_val|
94
95
  # If the `authorized?` returned two values, `false, early_return`,
95
96
  # then use the early return value instead of continuing
96
- if early_return
97
+ if authorized_val.is_a?(Array)
98
+ authorized_result, early_return = authorized_val
97
99
  if authorized_result == false
98
100
  early_return
99
101
  else
100
102
  raise "Unexpected result from #authorized? (expected `true`, `false` or `[false, {...}]`): [#{authorized_result.inspect}, #{early_return.inspect}]"
101
103
  end
102
- elsif authorized_result
104
+ elsif authorized_val
103
105
  # Finally, all the hooks have passed, so resolve it
104
106
  if loaded_args.any?
105
107
  public_send(self.class.resolve_method, **loaded_args)
@@ -212,6 +214,10 @@ module GraphQL
212
214
  arguments(context)
213
215
  end
214
216
 
217
+ def any_field_arguments?
218
+ any_arguments?
219
+ end
220
+
215
221
  def get_field_argument(name, context = GraphQL::Query::NullContext)
216
222
  get_argument(name, context)
217
223
  end
@@ -19,9 +19,9 @@ module GraphQL
19
19
 
20
20
  def specified_by_url(new_url = nil)
21
21
  if new_url
22
- @specified_by_url = new_url
23
- elsif defined?(@specified_by_url)
24
- @specified_by_url
22
+ directive(GraphQL::Schema::Directive::SpecifiedBy, url: new_url)
23
+ elsif (directive = directives.find { |dir| dir.graphql_name == "specifiedBy" })
24
+ directive.arguments[:url] # rubocop:disable Development/ContextIsPassedCop
25
25
  elsif superclass.respond_to?(:specified_by_url)
26
26
  superclass.specified_by_url
27
27
  else
@@ -28,14 +28,19 @@ module GraphQL
28
28
  def resolve_with_support(**args)
29
29
  result = nil
30
30
  unsubscribed = true
31
- catch :graphql_subscription_unsubscribed do
31
+ unsubscribed_result = catch :graphql_subscription_unsubscribed do
32
32
  result = super
33
33
  unsubscribed = false
34
34
  end
35
35
 
36
36
 
37
37
  if unsubscribed
38
- context.skip
38
+ if unsubscribed_result
39
+ context.namespace(:subscriptions)[:final_update] = true
40
+ unsubscribed_result
41
+ else
42
+ context.skip
43
+ end
39
44
  else
40
45
  result
41
46
  end
@@ -94,9 +99,11 @@ module GraphQL
94
99
  end
95
100
 
96
101
  # Call this to halt execution and remove this subscription from the system
97
- def unsubscribe
102
+ # @param update_value [Object] if present, deliver this update before unsubscribing
103
+ # @return [void]
104
+ def unsubscribe(update_value = nil)
98
105
  context.namespace(:subscriptions)[:unsubscribed] = true
99
- throw :graphql_subscription_unsubscribed
106
+ throw :graphql_subscription_unsubscribed, update_value
100
107
  end
101
108
 
102
109
  READING_SCOPE = ::Object.new
@@ -133,7 +133,7 @@ module GraphQL
133
133
  if all_errors.frozen? # It's empty
134
134
  all_errors = []
135
135
  end
136
- interpolation_vars = { validated: validated.graphql_name }
136
+ interpolation_vars = { validated: validated.graphql_name, value: value.inspect }
137
137
  if errors.is_a?(String)
138
138
  all_errors << (errors % interpolation_vars)
139
139
  else
@@ -4,37 +4,12 @@ require 'set'
4
4
 
5
5
  module GraphQL
6
6
  class Schema
7
- # Restrict access to a {GraphQL::Schema} with a user-defined filter.
7
+ # Restrict access to a {GraphQL::Schema} with a user-defined `visible?` implementations.
8
8
  #
9
9
  # When validating and executing a query, all access to schema members
10
10
  # should go through a warden. If you access the schema directly,
11
11
  # you may show a client something that it shouldn't be allowed to see.
12
12
  #
13
- # @example Hiding private fields
14
- # private_members = -> (member, ctx) { member.metadata[:private] }
15
- # result = Schema.execute(query_string, except: private_members)
16
- #
17
- # @example Custom filter implementation
18
- # # It must respond to `#call(member)`.
19
- # class MissingRequiredFlags
20
- # def initialize(user)
21
- # @user = user
22
- # end
23
- #
24
- # # Return `false` if any required flags are missing
25
- # def call(member, ctx)
26
- # member.metadata[:required_flags].any? do |flag|
27
- # !@user.has_flag?(flag)
28
- # end
29
- # end
30
- # end
31
- #
32
- # # Then, use the custom filter in query:
33
- # missing_required_flags = MissingRequiredFlags.new(current_user)
34
- #
35
- # # This query can only access members which match the user's flags
36
- # result = Schema.execute(query_string, except: missing_required_flags)
37
- #
38
13
  # @api private
39
14
  class Warden
40
15
  def self.from_context(context)
@@ -114,22 +89,16 @@ module GraphQL
114
89
  def interfaces(obj_type); obj_type.interfaces; end
115
90
  end
116
91
 
117
- # @param filter [<#call(member)>] Objects are hidden when `.call(member, ctx)` returns true
118
92
  # @param context [GraphQL::Query::Context]
119
93
  # @param schema [GraphQL::Schema]
120
- def initialize(filter = nil, context:, schema:)
94
+ def initialize(context:, schema:)
121
95
  @schema = schema
122
96
  # Cache these to avoid repeated hits to the inheritance chain when one isn't present
123
97
  @query = @schema.query
124
98
  @mutation = @schema.mutation
125
99
  @subscription = @schema.subscription
126
100
  @context = context
127
- @visibility_cache = if filter
128
- read_through { |m| filter.call(m, context) }
129
- else
130
- read_through { |m| schema.visible?(m, context) }
131
- end
132
-
101
+ @visibility_cache = read_through { |m| schema.visible?(m, context) }
133
102
  @visibility_cache.compare_by_identity
134
103
  # Initialize all ivars to improve object shape consistency:
135
104
  @types = @visible_types = @reachable_types = @visible_parent_fields =
@@ -219,7 +188,16 @@ module GraphQL
219
188
  # @param argument_owner [GraphQL::Field, GraphQL::InputObjectType]
220
189
  # @return [Array<GraphQL::Argument>] Visible arguments on `argument_owner`
221
190
  def arguments(argument_owner, ctx = nil)
222
- @visible_arguments ||= read_through { |o| o.arguments(@context).each_value.select { |a| visible_argument?(a, @context) } }
191
+ @visible_arguments ||= read_through { |o|
192
+ args = o.arguments(@context)
193
+ if args.any?
194
+ args = args.values
195
+ args.select! { |a| visible_argument?(a, @context) }
196
+ args
197
+ else
198
+ EmptyObjects::EMPTY_ARRAY
199
+ end
200
+ }
223
201
  @visible_arguments[argument_owner]
224
202
  end
225
203
 
@@ -242,7 +220,13 @@ module GraphQL
242
220
 
243
221
  # @return [Array<GraphQL::InterfaceType>] Visible interfaces implemented by `obj_type`
244
222
  def interfaces(obj_type)
245
- @visible_interfaces ||= read_through { |t| t.interfaces(@context).select { |i| visible_type?(i) } }
223
+ @visible_interfaces ||= read_through { |t|
224
+ ints = t.interfaces(@context)
225
+ if ints.any?
226
+ ints.select! { |i| visible_type?(i) }
227
+ end
228
+ ints
229
+ }
246
230
  @visible_interfaces[obj_type]
247
231
  end
248
232
 
@@ -385,7 +369,9 @@ module GraphQL
385
369
  end
386
370
 
387
371
  def read_through
388
- Hash.new { |h, k| h[k] = yield(k) }
372
+ h = Hash.new { |h, k| h[k] = yield(k) }
373
+ h.compare_by_identity
374
+ h
389
375
  end
390
376
 
391
377
  def reachable_type_set
@@ -37,10 +37,12 @@ require "graphql/schema/directive/skip"
37
37
  require "graphql/schema/directive/feature"
38
38
  require "graphql/schema/directive/flagged"
39
39
  require "graphql/schema/directive/transform"
40
+ require "graphql/schema/directive/specified_by"
40
41
  require "graphql/schema/type_membership"
41
42
 
42
43
  require "graphql/schema/resolver"
43
44
  require "graphql/schema/mutation"
45
+ require "graphql/schema/has_single_input_argument"
44
46
  require "graphql/schema/relay_classic_mutation"
45
47
  require "graphql/schema/subscription"
46
48
 
@@ -222,7 +224,7 @@ module GraphQL
222
224
  # @param include_specified_by_url [Boolean] If true, scalar types' `specifiedByUrl:` will be included in the response
223
225
  # @param include_is_one_of [Boolean] If true, `isOneOf: true|false` will be included with input objects
224
226
  # @return [Hash] GraphQL result
225
- def as_json(only: nil, except: nil, context: {}, include_deprecated_args: true, include_schema_description: false, include_is_repeatable: false, include_specified_by_url: false, include_is_one_of: false)
227
+ def as_json(context: {}, include_deprecated_args: true, include_schema_description: false, include_is_repeatable: false, include_specified_by_url: false, include_is_one_of: false)
226
228
  introspection_query = Introspection.query(
227
229
  include_deprecated_args: include_deprecated_args,
228
230
  include_schema_description: include_schema_description,
@@ -231,16 +233,14 @@ module GraphQL
231
233
  include_specified_by_url: include_specified_by_url,
232
234
  )
233
235
 
234
- execute(introspection_query, only: only, except: except, context: context).to_h
236
+ execute(introspection_query, context: context).to_h
235
237
  end
236
238
 
237
239
  # Return the GraphQL IDL for the schema
238
240
  # @param context [Hash]
239
- # @param only [<#call(member, ctx)>]
240
- # @param except [<#call(member, ctx)>]
241
241
  # @return [String]
242
- def to_definition(only: nil, except: nil, context: {})
243
- GraphQL::Schema::Printer.print_schema(self, only: only, except: except, context: context)
242
+ def to_definition(context: {})
243
+ GraphQL::Schema::Printer.print_schema(self, context: context)
244
244
  end
245
245
 
246
246
  # Return the GraphQL::Language::Document IDL AST for the schema
@@ -268,20 +268,6 @@ module GraphQL
268
268
  @find_cache[path] ||= @finder.find(path)
269
269
  end
270
270
 
271
- def default_filter
272
- GraphQL::Filter.new(except: default_mask)
273
- end
274
-
275
- def default_mask(new_mask = nil)
276
- if new_mask
277
- line = caller(2, 10).find { |l| !l.include?("lib/graphql") }
278
- GraphQL::Deprecation.warn("GraphQL::Filter and Schema.mask are deprecated and will be removed in v2.1.0. Implement `visible?` on your schema members instead (https://graphql-ruby.org/authorization/visibility.html).\n #{line}")
279
- @own_default_mask = new_mask
280
- else
281
- @own_default_mask || find_inherited_value(:default_mask, Schema::NullMask)
282
- end
283
- end
284
-
285
271
  def static_validator
286
272
  GraphQL::StaticValidation::Validator.new(schema: self)
287
273
  end
@@ -776,7 +762,16 @@ module GraphQL
776
762
  own_orphan_types.concat(new_orphan_types.flatten)
777
763
  end
778
764
 
779
- find_inherited_value(:orphan_types, EMPTY_ARRAY) + own_orphan_types
765
+ inherited_ot = find_inherited_value(:orphan_types, nil)
766
+ if inherited_ot
767
+ if own_orphan_types.any?
768
+ inherited_ot + own_orphan_types
769
+ else
770
+ inherited_ot
771
+ end
772
+ else
773
+ own_orphan_types
774
+ end
780
775
  end
781
776
 
782
777
  def default_execution_strategy
@@ -978,7 +973,12 @@ module GraphQL
978
973
  new_directives.flatten.each { |d| directive(d) }
979
974
  end
980
975
 
981
- find_inherited_value(:directives, default_directives).merge(own_directives)
976
+ inherited_dirs = find_inherited_value(:directives, default_directives)
977
+ if own_directives.any?
978
+ inherited_dirs.merge(own_directives)
979
+ else
980
+ inherited_dirs
981
+ end
982
982
  end
983
983
 
984
984
  # Attach a single directive to this schema
@@ -994,6 +994,7 @@ module GraphQL
994
994
  "skip" => GraphQL::Schema::Directive::Skip,
995
995
  "deprecated" => GraphQL::Schema::Directive::Deprecated,
996
996
  "oneOf" => GraphQL::Schema::Directive::OneOf,
997
+ "specifiedBy" => GraphQL::Schema::Directive::SpecifiedBy,
997
998
  }.freeze
998
999
  end
999
1000
 
@@ -3,7 +3,7 @@ module GraphQL
3
3
  module StaticValidation
4
4
  # Default rules for {GraphQL::StaticValidation::Validator}
5
5
  #
6
- # Order is important here. Some validators return {GraphQL::Language::Visitor::SKIP}
6
+ # Order is important here. Some validators skip later hooks.
7
7
  # which stops the visit on that node. That way it doesn't try to find fields on types that
8
8
  # don't exist, etc.
9
9
  ALL_RULES = [
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
3
  module StaticValidation
4
- class BaseVisitor < GraphQL::Language::Visitor
4
+ class BaseVisitor < GraphQL::Language::StaticVisitor
5
5
  def initialize(document, context)
6
6
  @path = []
7
7
  @object_types = []
@@ -111,7 +111,7 @@ module GraphQL
111
111
  # that required fields are missing
112
112
  required_field_names = @warden.arguments(type)
113
113
  .select { |argument| argument.type.kind.non_null? && @warden.get_argument(type, argument.name) }
114
- .map(&:name)
114
+ .map!(&:name)
115
115
 
116
116
  present_field_names = ast_node.arguments.map(&:name)
117
117
  missing_required_field_names = required_field_names - present_field_names
@@ -340,7 +340,7 @@ module GraphQL
340
340
  selections.each do |node|
341
341
  case node
342
342
  when GraphQL::Language::Nodes::Field
343
- definition = context.query.get_field(owner_type, node.name)
343
+ definition = context.warden.get_field(owner_type, node.name)
344
344
  fields << Field.new(node, definition, owner_type, parents)
345
345
  when GraphQL::Language::Nodes::InlineFragment
346
346
  fragment_type = node.type ? context.warden.get_type(node.type.name) : owner_type
@@ -21,7 +21,7 @@ module GraphQL
21
21
  present_argument_names = ast_node.arguments.map(&:name)
22
22
  required_argument_names = context.warden.arguments(defn)
23
23
  .select { |a| a.type.kind.non_null? && !a.default_value? && context.warden.get_argument(defn, a.name) }
24
- .map(&:name)
24
+ .map!(&:name)
25
25
 
26
26
  missing_names = required_argument_names - present_argument_names
27
27
  if missing_names.any?
@@ -36,7 +36,7 @@ module GraphQL
36
36
 
37
37
  required_fields = context.warden.arguments(parent_type)
38
38
  .select{|arg| arg.type.kind.non_null?}
39
- .map(&:graphql_name)
39
+ .map!(&:graphql_name)
40
40
 
41
41
  present_fields = ast_node.arguments.map(&:name)
42
42
  missing_fields = required_fields - present_fields
@@ -8,20 +8,20 @@ module GraphQL
8
8
  # It provides access to the schema & fragments which validators may read from.
9
9
  #
10
10
  # It holds a list of errors which each validator may add to.
11
- #
12
- # It also provides limited access to the {TypeStack} instance,
13
- # which tracks state as you climb in and out of different fields.
14
11
  class ValidationContext
15
12
  extend Forwardable
16
13
 
17
14
  attr_reader :query, :errors, :visitor,
18
15
  :on_dependency_resolve_handlers,
19
- :max_errors
16
+ :max_errors, :warden, :schema
17
+
20
18
 
21
- def_delegators :@query, :schema, :document, :fragments, :operations, :warden
19
+ def_delegators :@query, :document, :fragments, :operations
22
20
 
23
21
  def initialize(query, visitor_class, max_errors)
24
22
  @query = query
23
+ @warden = query.warden
24
+ @schema = query.schema
25
25
  @literal_validator = LiteralValidator.new(context: query.context)
26
26
  @errors = []
27
27
  @max_errors = max_errors || Float::INFINITY
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require "graphql/static_validation/error"
3
3
  require "graphql/static_validation/definition_dependencies"
4
- require "graphql/static_validation/type_stack"
5
4
  require "graphql/static_validation/validator"
6
5
  require "graphql/static_validation/validation_context"
7
6
  require "graphql/static_validation/validation_timeout_error"
@@ -124,7 +124,8 @@ module GraphQL
124
124
  # This subscription was re-evaluated.
125
125
  # Send it to the specific stream where this client was waiting.
126
126
  def deliver(subscription_id, result)
127
- payload = { result: result.to_h, more: true }
127
+ has_more = !result.context.namespace(:subscriptions)[:final_update]
128
+ payload = { result: result.to_h, more: has_more }
128
129
  @action_cable.server.broadcast(stream_subscription_name(subscription_id), payload)
129
130
  end
130
131