graphql 1.10.0.pre3 → 1.10.0.pre4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/templates/schema.erb +7 -0
  3. data/lib/graphql/argument.rb +3 -35
  4. data/lib/graphql/define/assign_enum_value.rb +1 -1
  5. data/lib/graphql/define/assign_object_field.rb +3 -3
  6. data/lib/graphql/define/defined_object_proxy.rb +8 -2
  7. data/lib/graphql/define/instance_definable.rb +10 -106
  8. data/lib/graphql/directive.rb +4 -0
  9. data/lib/graphql/enum_type.rb +1 -71
  10. data/lib/graphql/execution/execute.rb +1 -1
  11. data/lib/graphql/execution/interpreter/runtime.rb +48 -8
  12. data/lib/graphql/execution/multiplex.rb +3 -3
  13. data/lib/graphql/field.rb +1 -117
  14. data/lib/graphql/function.rb +1 -30
  15. data/lib/graphql/input_object_type.rb +1 -23
  16. data/lib/graphql/interface_type.rb +1 -22
  17. data/lib/graphql/language/document_from_schema_definition.rb +9 -3
  18. data/lib/graphql/language/nodes.rb +2 -2
  19. data/lib/graphql/object_type.rb +1 -21
  20. data/lib/graphql/query.rb +0 -1
  21. data/lib/graphql/query/context.rb +2 -5
  22. data/lib/graphql/relay/connection_type.rb +2 -1
  23. data/lib/graphql/relay/edge_type.rb +1 -0
  24. data/lib/graphql/relay/mutation.rb +1 -86
  25. data/lib/graphql/relay/node.rb +2 -2
  26. data/lib/graphql/scalar_type.rb +1 -58
  27. data/lib/graphql/schema.rb +60 -9
  28. data/lib/graphql/schema/build_from_definition.rb +6 -1
  29. data/lib/graphql/schema/directive.rb +7 -1
  30. data/lib/graphql/schema/enum_value.rb +1 -0
  31. data/lib/graphql/schema/introspection_system.rb +4 -1
  32. data/lib/graphql/schema/list.rb +17 -2
  33. data/lib/graphql/schema/loader.rb +9 -3
  34. data/lib/graphql/schema/mutation.rb +1 -1
  35. data/lib/graphql/schema/object.rb +0 -4
  36. data/lib/graphql/schema/relay_classic_mutation.rb +1 -1
  37. data/lib/graphql/schema/resolver.rb +1 -1
  38. data/lib/graphql/schema/subscription.rb +5 -5
  39. data/lib/graphql/schema/type_membership.rb +1 -1
  40. data/lib/graphql/schema/union.rb +1 -1
  41. data/lib/graphql/subscriptions.rb +2 -2
  42. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -1
  43. data/lib/graphql/tracing.rb +7 -3
  44. data/lib/graphql/tracing/active_support_notifications_tracing.rb +4 -0
  45. data/lib/graphql/tracing/appsignal_tracing.rb +8 -0
  46. data/lib/graphql/tracing/data_dog_tracing.rb +8 -0
  47. data/lib/graphql/tracing/new_relic_tracing.rb +8 -0
  48. data/lib/graphql/tracing/platform_tracing.rb +25 -4
  49. data/lib/graphql/tracing/prometheus_tracing.rb +8 -0
  50. data/lib/graphql/tracing/scout_tracing.rb +8 -0
  51. data/lib/graphql/tracing/skylight_tracing.rb +8 -0
  52. data/lib/graphql/union_type.rb +12 -27
  53. data/lib/graphql/version.rb +1 -1
  54. metadata +8 -8
@@ -11,7 +11,7 @@ module GraphQL
11
11
  field = GraphQL::Types::Relay::NodeField.graphql_definition
12
12
 
13
13
  if kwargs.any? || block
14
- field = field.redefine(kwargs, &block)
14
+ field = field.redefine(**kwargs, &block)
15
15
  end
16
16
 
17
17
  field
@@ -21,7 +21,7 @@ module GraphQL
21
21
  field = GraphQL::Types::Relay::NodesField.graphql_definition
22
22
 
23
23
  if kwargs.any? || block
24
- field = field.redefine(kwargs, &block)
24
+ field = field.redefine(**kwargs, &block)
25
25
  end
26
26
 
27
27
  field
@@ -1,63 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- # # GraphQL::ScalarType
4
- #
5
- # Scalars are plain values. They are leaf nodes in a GraphQL query tree.
6
- #
7
- # ## Built-in Scalars
8
- #
9
- # `GraphQL` comes with standard built-in scalars:
10
- #
11
- # |Constant | `.define` helper|
12
- # |-------|--------|
13
- # |`GraphQL::STRING_TYPE` | `types.String`|
14
- # |`GraphQL::INT_TYPE` | `types.Int`|
15
- # |`GraphQL::FLOAT_TYPE` | `types.Float`|
16
- # |`GraphQL::ID_TYPE` | `types.ID`|
17
- # |`GraphQL::BOOLEAN_TYPE` | `types.Boolean`|
18
- #
19
- # (`types` is an instance of `GraphQL::Definition::TypeDefiner`; `.String`, `.Float`, etc are methods which return built-in scalars.)
20
- #
21
- # ## Custom Scalars
22
- #
23
- # You can define custom scalars for your GraphQL server. It requires some special functions:
24
- #
25
- # - `coerce_input` is used to prepare incoming values for GraphQL execution. (Incoming values come from variables or literal values in the query string.)
26
- # - `coerce_result` is used to turn Ruby values _back_ into serializable values for query responses.
27
- #
28
- # @example defining a type for Time
29
- # TimeType = GraphQL::ScalarType.define do
30
- # name "Time"
31
- # description "Time since epoch in seconds"
32
- #
33
- # coerce_input ->(value, ctx) { Time.at(Float(value)) }
34
- # coerce_result ->(value, ctx) { value.to_f }
35
- # end
36
- #
37
- #
38
- # You can customize the error message for invalid input values by raising a `GraphQL::CoercionError` within `coerce_input`:
39
- #
40
- # @example raising a custom error message
41
- # TimeType = GraphQL::ScalarType.define do
42
- # name "Time"
43
- # description "Time since epoch in seconds"
44
- #
45
- # coerce_input ->(value, ctx) do
46
- # begin
47
- # Time.at(Float(value))
48
- # rescue ArgumentError
49
- # raise GraphQL::CoercionError, "cannot coerce `#{value.inspect}` to Float"
50
- # end
51
- # end
52
- #
53
- # coerce_result ->(value, ctx) { value.to_f }
54
- # end
55
- #
56
- # This will result in the message of the `GraphQL::CoercionError` being used in the error response:
57
- #
58
- # @example custom error response
59
- # {"message"=>"cannot coerce `"2"` to Float", "locations"=>[{"line"=>3, "column"=>9}], "fields"=>["arg"]}
60
- #
3
+ # @api deprecated
61
4
  class ScalarType < GraphQL::BaseType
62
5
  accepts_definitions :coerce, :coerce_input, :coerce_result
63
6
  ensure_defined :coerce_non_null_input, :coerce_result
@@ -104,6 +104,8 @@ module GraphQL
104
104
  mutation: ->(schema, t) { schema.mutation = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
105
105
  subscription: ->(schema, t) { schema.subscription = t.respond_to?(:graphql_definition) ? t.graphql_definition : t },
106
106
  disable_introspection_entry_points: ->(schema) { schema.disable_introspection_entry_points = true },
107
+ disable_schema_introspection_entry_point: ->(schema) { schema.disable_schema_introspection_entry_point = true },
108
+ disable_type_introspection_entry_point: ->(schema) { schema.disable_type_introspection_entry_point = true },
107
109
  directives: ->(schema, directives) { schema.directives = directives.reduce({}) { |m, d| m[d.graphql_name] = d; m } },
108
110
  directive: ->(schema, directive) { schema.directives[directive.graphql_name] = directive },
109
111
  instrument: ->(schema, type, instrumenter, after_built_ins: false) {
@@ -163,6 +165,20 @@ module GraphQL
163
165
  !!@disable_introspection_entry_points
164
166
  end
165
167
 
168
+ # [Boolean] True if this object disables the __schema introspection entry point field
169
+ attr_accessor :disable_schema_introspection_entry_point
170
+
171
+ def disable_schema_introspection_entry_point?
172
+ !!@disable_schema_introspection_entry_point
173
+ end
174
+
175
+ # [Boolean] True if this object disables the __type introspection entry point field
176
+ attr_accessor :disable_type_introspection_entry_point
177
+
178
+ def disable_type_introspection_entry_point?
179
+ !!@disable_type_introspection_entry_point
180
+ end
181
+
166
182
  class << self
167
183
  attr_writer :default_execution_strategy
168
184
  end
@@ -213,6 +229,8 @@ module GraphQL
213
229
  @interpreter = false
214
230
  @error_bubbling = false
215
231
  @disable_introspection_entry_points = false
232
+ @disable_schema_introspection_entry_point = false
233
+ @disable_type_introspection_entry_point = false
216
234
  end
217
235
 
218
236
  # @return [Boolean] True if using the new {GraphQL::Execution::Interpreter}
@@ -282,7 +300,7 @@ module GraphQL
282
300
  query = GraphQL::Query.new(self, document: doc, context: context)
283
301
  validator_opts = { schema: self }
284
302
  rules && (validator_opts[:rules] = rules)
285
- validator = GraphQL::StaticValidation::Validator.new(validator_opts)
303
+ validator = GraphQL::StaticValidation::Validator.new(**validator_opts)
286
304
  res = validator.validate(query)
287
305
  res[:errors]
288
306
  end
@@ -730,9 +748,12 @@ module GraphQL
730
748
  end
731
749
 
732
750
  # Return the GraphQL::Language::Document IDL AST for the schema
751
+ # @param context [Hash]
752
+ # @param only [<#call(member, ctx)>]
753
+ # @param except [<#call(member, ctx)>]
733
754
  # @return [GraphQL::Language::Document]
734
- def to_document
735
- GraphQL::Language::DocumentFromSchemaDefinition.new(self).document
755
+ def to_document(only: nil, except: nil, context: {})
756
+ GraphQL::Language::DocumentFromSchemaDefinition.new(self, only: only, except: except, context: context).document
736
757
  end
737
758
 
738
759
  # Return the Hash response of {Introspection::INTROSPECTION_QUERY}.
@@ -835,13 +856,13 @@ module GraphQL
835
856
  GraphQL::StaticValidation::Validator.new(schema: self)
836
857
  end
837
858
 
838
- def use(plugin, options = {})
839
- if options.any?
840
- plugin.use(self, options)
859
+ def use(plugin, **kwargs)
860
+ if kwargs.any?
861
+ plugin.use(self, **kwargs)
841
862
  else
842
863
  plugin.use(self)
843
864
  end
844
- own_plugins << [plugin, options]
865
+ own_plugins << [plugin, kwargs]
845
866
  end
846
867
 
847
868
  def plugins
@@ -860,6 +881,8 @@ module GraphQL
860
881
  schema_defn.default_max_page_size = default_max_page_size
861
882
  schema_defn.orphan_types = orphan_types.map(&:graphql_definition)
862
883
  schema_defn.disable_introspection_entry_points = disable_introspection_entry_points?
884
+ schema_defn.disable_schema_introspection_entry_point = disable_schema_introspection_entry_point?
885
+ schema_defn.disable_type_introspection_entry_point = disable_type_introspection_entry_point?
863
886
 
864
887
  prepped_dirs = {}
865
888
  directives.each { |k, v| prepped_dirs[k] = v.graphql_definition}
@@ -1202,6 +1225,18 @@ module GraphQL
1202
1225
  @introspection_system = nil
1203
1226
  end
1204
1227
 
1228
+ def disable_schema_introspection_entry_point
1229
+ @disable_schema_introspection_entry_point = true
1230
+ # TODO: this clears the cache made in `def types`. But this is not a great solution.
1231
+ @introspection_system = nil
1232
+ end
1233
+
1234
+ def disable_type_introspection_entry_point
1235
+ @disable_type_introspection_entry_point = true
1236
+ # TODO: this clears the cache made in `def types`. But this is not a great solution.
1237
+ @introspection_system = nil
1238
+ end
1239
+
1205
1240
  def disable_introspection_entry_points?
1206
1241
  if instance_variable_defined?(:@disable_introspection_entry_points)
1207
1242
  @disable_introspection_entry_points
@@ -1210,6 +1245,22 @@ module GraphQL
1210
1245
  end
1211
1246
  end
1212
1247
 
1248
+ def disable_schema_introspection_entry_point?
1249
+ if instance_variable_defined?(:@disable_schema_introspection_entry_point)
1250
+ @disable_schema_introspection_entry_point
1251
+ else
1252
+ find_inherited_value(:disable_schema_introspection_entry_point?, false)
1253
+ end
1254
+ end
1255
+
1256
+ def disable_type_introspection_entry_point?
1257
+ if instance_variable_defined?(:@disable_type_introspection_entry_point)
1258
+ @disable_type_introspection_entry_point
1259
+ else
1260
+ find_inherited_value(:disable_type_introspection_entry_point?, false)
1261
+ end
1262
+ end
1263
+
1213
1264
  def orphan_types(*new_orphan_types)
1214
1265
  if new_orphan_types.any?
1215
1266
  new_orphan_types = new_orphan_types.flatten
@@ -1292,11 +1343,11 @@ module GraphQL
1292
1343
  end
1293
1344
 
1294
1345
  def visible?(member, ctx)
1295
- member.visible?(ctx)
1346
+ member.type_class.visible?(ctx)
1296
1347
  end
1297
1348
 
1298
1349
  def accessible?(member, ctx)
1299
- member.accessible?(ctx)
1350
+ member.type_class.accessible?(ctx)
1300
1351
  end
1301
1352
 
1302
1353
  # This hook is called when a client tries to access one or more
@@ -129,7 +129,11 @@ module GraphQL
129
129
  end
130
130
 
131
131
  using.each do |plugin, options|
132
- use(plugin, options)
132
+ if options
133
+ use(plugin, **options)
134
+ else
135
+ use(plugin)
136
+ end
133
137
  end
134
138
  end
135
139
  end
@@ -196,6 +200,7 @@ module GraphQL
196
200
  builder = self
197
201
  type_def = nil
198
202
  typed_resolve_fn = ->(field, obj, args, ctx) { default_resolve.call(type_def, field, obj, args, ctx) }
203
+
199
204
  Class.new(GraphQL::Schema::Object) do
200
205
  type_def = self
201
206
  graphql_name(object_type_definition.name)
@@ -9,8 +9,14 @@ module GraphQL
9
9
  class Directive < GraphQL::Schema::Member
10
10
  extend GraphQL::Schema::Member::HasArguments
11
11
  class << self
12
+ # Return a name based on the class name,
13
+ # but downcase the first letter.
12
14
  def default_graphql_name
13
- super.downcase
15
+ @default_graphql_name ||= begin
16
+ camelized_name = super
17
+ camelized_name[0] = camelized_name[0].downcase
18
+ camelized_name
19
+ end
14
20
  end
15
21
 
16
22
  def locations(*new_locations)
@@ -26,6 +26,7 @@ module GraphQL
26
26
  # enum_value_class CustomEnumValue
27
27
  # end
28
28
  class EnumValue < GraphQL::Schema::Member
29
+ include GraphQL::Schema::Member::CachedGraphQLDefinition
29
30
  include GraphQL::Schema::Member::AcceptsDefinition
30
31
  include GraphQL::Schema::Member::HasPath
31
32
  include GraphQL::Schema::Member::HasAstNode
@@ -34,7 +34,10 @@ module GraphQL
34
34
  if schema.disable_introspection_entry_points?
35
35
  {}
36
36
  else
37
- get_fields_from_class(class_sym: :EntryPoints)
37
+ entry_point_fields = get_fields_from_class(class_sym: :EntryPoints)
38
+ entry_point_fields.delete('__schema') if schema.disable_schema_introspection_entry_point?
39
+ entry_point_fields.delete('__type') if schema.disable_type_introspection_entry_point?
40
+ entry_point_fields
38
41
  end
39
42
  @dynamic_fields = get_fields_from_class(class_sym: :DynamicFields)
40
43
  end
@@ -36,12 +36,16 @@ module GraphQL
36
36
  end
37
37
 
38
38
  def coerce_input(value, ctx)
39
- Array(value).map { |item| item.nil? ? item : of_type.coerce_input(item, ctx) }
39
+ if value.nil?
40
+ nil
41
+ else
42
+ ensure_array(value).map { |item| item.nil? ? item : of_type.coerce_input(item, ctx) }
43
+ end
40
44
  end
41
45
 
42
46
  def validate_non_null_input(value, ctx)
43
47
  result = GraphQL::Query::InputValidationResult.new
44
- Array(value).each_with_index do |item, index|
48
+ ensure_array(value).each_with_index do |item, index|
45
49
  item_result = of_type.validate_input(item, ctx)
46
50
  if !item_result.valid?
47
51
  result.merge_result!(index, item_result)
@@ -49,6 +53,17 @@ module GraphQL
49
53
  end
50
54
  result
51
55
  end
56
+
57
+ private
58
+
59
+ def ensure_array(value)
60
+ # `Array({ a: 1 })` makes `[[:a, 1]]`, so do it manually
61
+ if value.is_a?(Array)
62
+ value
63
+ else
64
+ [value]
65
+ end
66
+ end
52
67
  end
53
68
  end
54
69
  end
@@ -124,14 +124,20 @@ module GraphQL
124
124
  }]
125
125
  )
126
126
  when "FIELD"
127
- GraphQL::Field.define(
127
+ defns = {
128
128
  name: type["name"],
129
129
  type: type_resolver.call(type["type"]),
130
130
  description: type["description"],
131
- arguments: Hash[type["args"].map { |arg|
131
+ }
132
+
133
+ # Avoid passing an empty hash, which warns on Ruby 2.7
134
+ if type["args"].any?
135
+ defns[:arguments] = Hash[type["args"].map { |arg|
132
136
  [arg["name"], define_type(arg.merge("kind" => "ARGUMENT"), type_resolver)]
133
137
  }]
134
- )
138
+ end
139
+
140
+ GraphQL::Field.define(**defns)
135
141
  when "ARGUMENT"
136
142
  kwargs = {}
137
143
  if type["defaultValue"]
@@ -64,7 +64,7 @@ module GraphQL
64
64
 
65
65
  class << self
66
66
  # Override this method to handle legacy-style usages of `MyMutation.field`
67
- def field(*args, &block)
67
+ def field(*args, **kwargs, &block)
68
68
  if args.empty?
69
69
  raise ArgumentError, "#{name}.field is used for adding fields to this mutation. Use `mutation: #{name}` to attach this mutation instead."
70
70
  else
@@ -57,13 +57,9 @@ module GraphQL
57
57
  else
58
58
  nil
59
59
  end
60
- # rescue GraphQL::ExecutionError => err
61
- # err
62
60
  end
63
61
  end
64
62
  end
65
- # rescue GraphQL::ExecutionError => err
66
- # err
67
63
  end
68
64
  end
69
65
 
@@ -61,7 +61,7 @@ module GraphQL
61
61
  end
62
62
 
63
63
  return_value = if input_kwargs.any?
64
- super(input_kwargs)
64
+ super(**input_kwargs)
65
65
  else
66
66
  super()
67
67
  end
@@ -76,7 +76,7 @@ module GraphQL
76
76
  context.schema.after_lazy(load_arguments_val) do |loaded_args|
77
77
  # Then call `authorized?`, which may raise or may return a lazy object
78
78
  authorized_val = if loaded_args.any?
79
- authorized?(loaded_args)
79
+ authorized?(**loaded_args)
80
80
  else
81
81
  authorized?
82
82
  end
@@ -39,12 +39,12 @@ module GraphQL
39
39
  def resolve(**args)
40
40
  # Dispatch based on `@mode`, which will raise a `NoMethodError` if we ever
41
41
  # have an unexpected `@mode`
42
- public_send("resolve_#{@mode}", args)
42
+ public_send("resolve_#{@mode}", **args)
43
43
  end
44
44
 
45
45
  # Wrap the user-defined `#subscribe` hook
46
- def resolve_subscribe(args)
47
- ret_val = args.any? ? subscribe(args) : subscribe
46
+ def resolve_subscribe(**args)
47
+ ret_val = args.any? ? subscribe(**args) : subscribe
48
48
  if ret_val == :no_response
49
49
  context.skip
50
50
  else
@@ -62,8 +62,8 @@ module GraphQL
62
62
  end
63
63
 
64
64
  # Wrap the user-provided `#update` hook
65
- def resolve_update(args)
66
- ret_val = args.any? ? update(args) : update
65
+ def resolve_update(**args)
66
+ ret_val = args.any? ? update(**args) : update
67
67
  if ret_val == :no_update
68
68
  raise NoUpdateError
69
69
  else
@@ -19,7 +19,7 @@ module GraphQL
19
19
  # @param abstract_type [Class<GraphQL::Schema::Union>, Module<GraphQL::Schema::Interface>]
20
20
  # @param object_type [Class<GraphQL::Schema::Object>]
21
21
  # @param options [Hash] Any options passed to `.possible_types` or `.implements`
22
- def initialize(abstract_type, object_type, options)
22
+ def initialize(abstract_type, object_type, **options)
23
23
  @abstract_type = abstract_type
24
24
  @object_type = object_type
25
25
  @options = options
@@ -8,7 +8,7 @@ module GraphQL
8
8
  def possible_types(*types, context: GraphQL::Query::NullContext, **options)
9
9
  if types.any?
10
10
  types.each do |t|
11
- type_memberships << type_membership_class.new(self, t, options)
11
+ type_memberships << type_membership_class.new(self, t, **options)
12
12
  end
13
13
  else
14
14
  visible_types = []
@@ -28,7 +28,7 @@ module GraphQL
28
28
  defn.instrument(:query, instrumentation)
29
29
  defn.instrument(:field, instrumentation)
30
30
  options[:schema] = schema
31
- schema.subscriptions = self.new(options)
31
+ schema.subscriptions = self.new(**options)
32
32
  nil
33
33
  end
34
34
 
@@ -95,7 +95,7 @@ module GraphQL
95
95
  operation_name = query_data.fetch(:operation_name)
96
96
  # Re-evaluate the saved query
97
97
  result = @schema.execute(
98
- {
98
+ **{
99
99
  query: query_string,
100
100
  context: context,
101
101
  subscription_topic: event.topic,