graphql 1.10.0.pre3 → 1.10.0.pre4

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 (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,