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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 78e01c4a75da2ab94a931c38e49c2e697de00b28837045807d1c7c9f02a9d831
4
- data.tar.gz: eb281e483efaafef9824d8e41f0dc0558fe2c2351a4d675d2b875cc2de630a8f
3
+ metadata.gz: d34099c7acb7ca11c9994b591e7696bb239933a9cdf4e116a296c8ba5f0edd0a
4
+ data.tar.gz: eed4bf2da3bb5ecc392ea5ebe01a7f0d45f0e88bbcd3eb6465c7a99a832b0426
5
5
  SHA512:
6
- metadata.gz: 893b327d435f43a7ab1e97940662a9d786b27446b07280df6fe171e1271cc07048ed1098e7bf6cf7bd643d9c77765be4b1abd175f771faefdcc4cc6e49e0724a
7
- data.tar.gz: 7ca9736e3fd003b784f2a5c3dfa62a02b44675623c0cddfb4064d26924e77694b6f1f05a9f6ab795d2e6f6ced93f8e57542e4b63123485a7f4599c6d92c36db7
6
+ metadata.gz: 3a3fc3b086e9a2eb410d693601d51b9c916043a21ffe2205ccedbd2c129aa674227f1e09b0dbed36b84fc658cb1128ea7937e4a6692643ce7b76aeb0fee550e6
7
+ data.tar.gz: ce80dce78040983568ca09093cb21b1bf51fed5c2bdef7265c39cb8e8b79d29277d203e44a898a8a5b7b1ab8006017e223c2ab95593c309c00ac35a44148c1a4
@@ -1,4 +1,11 @@
1
1
  class <%= schema_name %> < GraphQL::Schema
2
+ query(Types::QueryType)
3
+
4
+ # Opt in to the new runtime (default in future graphql-ruby versions)
5
+ use GraphQL::Execution::Interpreter
6
+
7
+ # Add built-in connections for pagination
8
+ use GraphQL::Pagination::Connections
2
9
  <% if options[:relay] %>
3
10
  # Relay Object Identification:
4
11
 
@@ -1,38 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- # Used for defined arguments ({Field}, {InputObjectType})
4
- #
5
- # {#name} must be a String.
6
- #
7
- # @example defining an argument for a field
8
- # GraphQL::Field.define do
9
- # # ...
10
- # argument :favoriteFood, types.String, "Favorite thing to eat", default_value: "pizza"
11
- # end
12
- #
13
- # @example defining an argument for an {InputObjectType}
14
- # GraphQL::InputObjectType.define do
15
- # argument :newName, !types.String
16
- # end
17
- #
18
- # @example defining an argument with a `prepare` function
19
- # GraphQL::Field.define do
20
- # argument :userId, types.ID, prepare: ->(userId) do
21
- # User.find_by(id: userId)
22
- # end
23
- # end
24
- #
25
- # @example returning an {ExecutionError} from a `prepare` function
26
- # GraphQL::Field.define do
27
- # argument :date do
28
- # type !types.String
29
- # prepare ->(date) do
30
- # return GraphQL::ExecutionError.new("Invalid date format") unless DateValidator.valid?(date)
31
- # Time.zone.parse(date)
32
- # end
33
- # end
34
- # end
35
-
3
+ # @api deprecated
36
4
  class Argument
37
5
  include GraphQL::Define::InstanceDefinable
38
6
  accepts_definitions :name, :type, :description, :default_value, :as, :prepare, :method_access
@@ -138,9 +106,9 @@ module GraphQL
138
106
  end
139
107
 
140
108
  if type_or_argument.is_a?(GraphQL::Argument)
141
- type_or_argument.redefine(kwargs, &block)
109
+ type_or_argument.redefine(**kwargs, &block)
142
110
  else
143
- GraphQL::Argument.define(kwargs, &block)
111
+ GraphQL::Argument.define(**kwargs, &block)
144
112
  end
145
113
  end
146
114
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
3
  module Define
4
- # Turn enum value configs into a {GraphQL::EnumType::EnumValue} and register it with the {GraphQL::EnumType}
4
+ # @api deprecated
5
5
  module AssignEnumValue
6
6
  def self.call(enum_type, name, desc = nil, deprecation_reason: nil, value: name, &block)
7
7
  enum_value = GraphQL::EnumType::EnumValue.define(
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
3
  module Define
4
- # Turn field configs into a {GraphQL::Field} and attach it to a {GraphQL::ObjectType} or {GraphQL::InterfaceType}
4
+ # @api deprecated
5
5
  module AssignObjectField
6
6
  def self.call(owner_type, name, type_or_field = nil, desc = nil, function: nil, field: nil, relay_mutation_function: nil, **kwargs, &block)
7
7
  name_s = name.to_s
@@ -28,9 +28,9 @@ module GraphQL
28
28
  end
29
29
 
30
30
  obj_field = if base_field
31
- base_field.redefine(kwargs, &block)
31
+ base_field.redefine(**kwargs, &block)
32
32
  else
33
- GraphQL::Field.define(kwargs, &block)
33
+ GraphQL::Field.define(**kwargs, &block)
34
34
  end
35
35
 
36
36
 
@@ -32,10 +32,16 @@ module GraphQL
32
32
  end
33
33
 
34
34
  # Lookup a function from the dictionary and call it if it's found.
35
- def method_missing(name, *args, &block)
35
+ def method_missing(name, *args, **kwargs, &block)
36
36
  definition = @dictionary[name]
37
37
  if definition
38
- definition.call(@target, *args, &block)
38
+ # Avoid passing `kwargs` when it's not used.
39
+ # Ruby 2.7 does fine here, but older Rubies receive too many arguments.
40
+ if kwargs.any?
41
+ definition.call(@target, *args, **kwargs, &block)
42
+ else
43
+ definition.call(@target, *args, &block)
44
+ end
39
45
  else
40
46
  msg = "#{@target.class.name} can't define '#{name}'"
41
47
  raise NoDefinitionError, msg, caller
@@ -1,118 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
3
  module Define
4
- # This module provides the `.define { ... }` API for
5
- # {GraphQL::BaseType}, {GraphQL::Field} and others.
6
- #
7
- # Calling `.accepts_definitions(...)` creates:
8
- #
9
- # - a keyword to the `.define` method
10
- # - a helper method in the `.define { ... }` block
11
- #
12
- # The `.define { ... }` block will be called lazily. To be sure it has been
13
- # called, use the private method `#ensure_defined`. That will call the
14
- # definition block if it hasn't been called already.
15
- #
16
- # The goals are:
17
- #
18
- # - Minimal overhead in consuming classes
19
- # - Independence between consuming classes
20
- # - Extendable by third-party libraries without monkey-patching or other nastiness
21
- #
22
- # @example Make a class definable
23
- # class Car
24
- # include GraphQL::Define::InstanceDefinable
25
- # attr_accessor :make, :model, :doors
26
- # accepts_definitions(
27
- # # These attrs will be defined with plain setters, `{attr}=`
28
- # :make, :model,
29
- # # This attr has a custom definition which applies the config to the target
30
- # doors: ->(car, doors_count) { doors_count.times { car.doors << Door.new } }
31
- # )
32
- # ensure_defined(:make, :model, :doors)
33
- #
34
- # def initialize
35
- # @doors = []
36
- # end
37
- # end
38
- #
39
- # class Door; end;
40
- #
41
- # # Create an instance with `.define`:
42
- # subaru_baja = Car.define do
43
- # make "Subaru"
44
- # model "Baja"
45
- # doors 4
46
- # end
47
- #
48
- # # The custom proc was applied:
49
- # subaru_baja.doors #=> [<Door>, <Door>, <Door>, <Door>]
50
- #
51
- # @example Extending the definition of a class
52
- # # Add some definitions:
53
- # Car.accepts_definitions(all_wheel_drive: GraphQL::Define.assign_metadata_key(:all_wheel_drive))
54
- #
55
- # # Use it in a definition
56
- # subaru_baja = Car.define do
57
- # # ...
58
- # all_wheel_drive true
59
- # end
60
- #
61
- # # Access it from metadata
62
- # subaru_baja.metadata[:all_wheel_drive] # => true
63
- #
64
- # @example Extending the definition of a class via a plugin
65
- # # A plugin is any object that responds to `.use(definition)`
66
- # module SubaruCar
67
- # extend self
68
- #
69
- # def use(defn)
70
- # # `defn` has the same methods as within `.define { ... }` block
71
- # defn.make "Subaru"
72
- # defn.doors 4
73
- # end
74
- # end
75
- #
76
- # # Use the plugin within a `.define { ... }` block
77
- # subaru_baja = Car.define do
78
- # use SubaruCar
79
- # model 'Baja'
80
- # end
81
- #
82
- # subaru_baja.make # => "Subaru"
83
- # subaru_baja.doors # => [<Door>, <Door>, <Door>, <Door>]
84
- #
85
- # @example Making a copy with an extended definition
86
- # # Create an instance with `.define`:
87
- # subaru_baja = Car.define do
88
- # make "Subaru"
89
- # model "Baja"
90
- # doors 4
91
- # end
92
- #
93
- # # Then extend it with `#redefine`
94
- # two_door_baja = subaru_baja.redefine do
95
- # doors 2
96
- # end
4
+ # @api deprecated
97
5
  module InstanceDefinable
98
6
  def self.included(base)
99
7
  base.extend(ClassMethods)
100
8
  base.ensure_defined(:metadata)
101
9
  end
102
10
 
103
- # `metadata` can store arbitrary key-values with an object.
104
- #
105
- # @return [Hash<Object, Object>] Hash for user-defined storage
11
+ # @api deprecated
106
12
  def metadata
107
13
  @metadata ||= {}
108
14
  end
109
15
 
110
- # Mutate this instance using functions from its {.definition}s.
111
- # Keywords or helpers in the block correspond to keys given to `accepts_definitions`.
112
- #
113
- # Note that the block is not called right away -- instead, it's deferred until
114
- # one of the defined fields is needed.
115
- # @return [void]
16
+ # @api deprecated
116
17
  def define(**kwargs, &block)
117
18
  # make sure the previous definition_proc was executed:
118
19
  ensure_defined
@@ -121,9 +22,7 @@ module GraphQL
121
22
  nil
122
23
  end
123
24
 
124
- # Shallow-copy this object, then apply new definitions to the copy.
125
- # @see {#define} for arguments
126
- # @return [InstanceDefinable] A new instance, with any extended definitions
25
+ # @api deprecated
127
26
  def redefine(**kwargs, &block)
128
27
  ensure_defined
129
28
  new_inst = self.dup
@@ -154,7 +53,12 @@ module GraphQL
154
53
  defn_proxy = DefinedObjectProxy.new(self)
155
54
  # Apply definition from `define(...)` kwargs
156
55
  defn.define_keywords.each do |keyword, value|
157
- defn_proxy.public_send(keyword, value)
56
+ # Don't splat string hashes, which blows up on Rubies before 2.7
57
+ if value.is_a?(Hash) && value.each_key.all? { |k| k.is_a?(Symbol) }
58
+ defn_proxy.public_send(keyword, **value)
59
+ else
60
+ defn_proxy.public_send(keyword, value)
61
+ end
158
62
  end
159
63
  # and/or apply definition from `define { ... }` block
160
64
  if defn.define_proc
@@ -95,6 +95,10 @@ module GraphQL
95
95
  def inspect
96
96
  "#<GraphQL::Directive #{name}>"
97
97
  end
98
+
99
+ def type_class
100
+ metadata[:type_class]
101
+ end
98
102
  end
99
103
  end
100
104
 
@@ -1,76 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- # Represents a collection of related values.
4
- # By convention, enum names are `SCREAMING_CASE_NAMES`,
5
- # but other identifiers are supported too.
6
- #
7
- # You can use as return types _or_ as inputs.
8
- #
9
- # By default, enums are passed to `resolve` functions as
10
- # the strings that identify them, but you can provide a
11
- # custom Ruby value with the `value:` keyword.
12
- #
13
- # @example An enum of programming languages
14
- # LanguageEnum = GraphQL::EnumType.define do
15
- # name "Language"
16
- # description "Programming language for Web projects"
17
- # value("PYTHON", "A dynamic, function-oriented language")
18
- # value("RUBY", "A very dynamic language aimed at programmer happiness")
19
- # value("JAVASCRIPT", "Accidental lingua franca of the web")
20
- # end
21
- #
22
- # @example Using an enum as a return type
23
- # field :favoriteLanguage, LanguageEnum, "This person's favorite coding language"
24
- # # ...
25
- # # In a query:
26
- # Schema.execute("{ coder(id: 1) { favoriteLanguage } }")
27
- # # { "data" => { "coder" => { "favoriteLanguage" => "RUBY" } } }
28
- #
29
- # @example Defining an enum input
30
- # field :coders, types[CoderType] do
31
- # argument :knowing, types[LanguageEnum]
32
- # resolve ->(obj, args, ctx) {
33
- # Coder.where(language: args[:knowing])
34
- # }
35
- # end
36
- #
37
- # @example Using an enum as input
38
- # {
39
- # # find coders who know Python and Ruby
40
- # coders(knowing: [PYTHON, RUBY]) {
41
- # name
42
- # hourlyRate
43
- # }
44
- # }
45
- #
46
- # @example Enum whose values are different in Ruby-land
47
- # GraphQL::EnumType.define do
48
- # # ...
49
- # # use the `value:` keyword:
50
- # value("RUBY", "Lisp? Smalltalk?", value: :rb)
51
- # end
52
- #
53
- # # Now, resolve functions will receive `:rb` instead of `"RUBY"`
54
- # field :favoriteLanguage, LanguageEnum
55
- # resolve ->(obj, args, ctx) {
56
- # args[:favoriteLanguage] # => :rb
57
- # }
58
- #
59
- # @example Enum whose values are different in ActiveRecord-land
60
- # class Language < ActiveRecord::Base
61
- # enum language: {
62
- # rb: 0
63
- # }
64
- # end
65
- #
66
- # # Now enum type should be defined as
67
- # GraphQL::EnumType.define do
68
- # # ...
69
- # # use the `value:` keyword:
70
- # value("RUBY", "Lisp? Smalltalk?", value: 'rb')
71
- # end
72
- #
73
-
3
+ # @api deprecated
74
4
  class EnumType < GraphQL::BaseType
75
5
  accepts_definitions :values, value: GraphQL::Define::AssignEnumValue
76
6
  ensure_defined(:values, :validate_non_null_input, :coerce_non_null_input, :coerce_result)
@@ -20,7 +20,7 @@ module GraphQL
20
20
 
21
21
  def execute(ast_operation, root_type, query)
22
22
  result = resolve_root_selection(query)
23
- lazy_resolve_root_selection(result, {query: query})
23
+ lazy_resolve_root_selection(result, **{query: query})
24
24
  GraphQL::Execution::Flatten.call(query.context)
25
25
  end
26
26
 
@@ -50,7 +50,7 @@ module GraphQL
50
50
  path = []
51
51
  @interpreter_context[:current_object] = query.root_value
52
52
  @interpreter_context[:current_path] = path
53
- object_proxy = root_type.authorized_new(query.root_value, context)
53
+ object_proxy = authorized_new(root_type, query.root_value, context, path)
54
54
  object_proxy = schema.sync_lazy(object_proxy)
55
55
  if object_proxy.nil?
56
56
  # Root .authorized? returned false.
@@ -165,7 +165,7 @@ module GraphQL
165
165
  object = owner_object
166
166
 
167
167
  if is_introspection
168
- object = field_defn.owner.authorized_new(object, context)
168
+ object = authorized_new(field_defn.owner, object, context, next_path)
169
169
  end
170
170
 
171
171
  begin
@@ -293,8 +293,8 @@ module GraphQL
293
293
  write_in_response(path, r)
294
294
  r
295
295
  when "UNION", "INTERFACE"
296
- resolved_type_or_lazy = query.resolve_type(type, value)
297
- after_lazy(resolved_type_or_lazy, owner: type, path: path, scoped_context: context.scoped_context, field: field, owner_object: owner_object, arguments: arguments) do |resolved_type|
296
+ resolved_type_or_lazy = resolve_type(type, value, path)
297
+ after_lazy(resolved_type_or_lazy, owner: type, path: path, scoped_context: context.scoped_context, field: field, owner_object: owner_object, arguments: arguments, trace: false) do |resolved_type|
298
298
  possible_types = query.possible_types(type)
299
299
 
300
300
  if !possible_types.include?(resolved_type)
@@ -309,11 +309,11 @@ module GraphQL
309
309
  end
310
310
  when "OBJECT"
311
311
  object_proxy = begin
312
- type.authorized_new(value, context)
312
+ authorized_new(type, value, context, path)
313
313
  rescue GraphQL::ExecutionError => err
314
314
  err
315
315
  end
316
- after_lazy(object_proxy, owner: type, path: path, scoped_context: context.scoped_context, field: field, owner_object: owner_object, arguments: arguments) do |inner_object|
316
+ after_lazy(object_proxy, owner: type, path: path, scoped_context: context.scoped_context, field: field, owner_object: owner_object, arguments: arguments, trace: false) do |inner_object|
317
317
  continue_value = continue_value(path, inner_object, field, is_non_null, ast_node)
318
318
  if HALT != continue_value
319
319
  response_hash = {}
@@ -390,8 +390,9 @@ module GraphQL
390
390
  # @param path [Array<String>]
391
391
  # @param field [GraphQL::Schema::Field]
392
392
  # @param eager [Boolean] Set to `true` for mutation root fields only
393
+ # @param trace [Boolean] If `false`, don't wrap this with field tracing
393
394
  # @return [GraphQL::Execution::Lazy, Object] If loading `object` will be deferred, it's a wrapper over it.
394
- def after_lazy(lazy_obj, owner:, field:, path:, scoped_context:, owner_object:, arguments:, eager: false)
395
+ def after_lazy(lazy_obj, owner:, field:, path:, scoped_context:, owner_object:, arguments:, eager: false, trace: true)
395
396
  @interpreter_context[:current_object] = owner_object
396
397
  @interpreter_context[:current_arguments] = arguments
397
398
  @interpreter_context[:current_path] = path
@@ -407,7 +408,11 @@ module GraphQL
407
408
  # but don't wrap the continuation below
408
409
  inner_obj = begin
409
410
  query.with_error_handling do
410
- query.trace("execute_field_lazy", {owner: owner, field: field, path: path, query: query, object: owner_object, arguments: arguments}) do
411
+ if trace
412
+ query.trace("execute_field_lazy", {owner: owner, field: field, path: path, query: query, object: owner_object, arguments: arguments}) do
413
+ schema.sync_lazy(lazy_obj)
414
+ end
415
+ else
411
416
  schema.sync_lazy(lazy_obj)
412
417
  end
413
418
  end
@@ -639,6 +644,41 @@ module GraphQL
639
644
  end
640
645
  res && res[:__dead]
641
646
  end
647
+
648
+ def resolve_type(type, value, path)
649
+ trace_payload = { context: context, type: type, object: value, path: path }
650
+ resolved_type = query.trace("resolve_type", trace_payload) do
651
+ query.resolve_type(type, value)
652
+ end
653
+
654
+ if schema.lazy?(resolved_type)
655
+ GraphQL::Execution::Lazy.new do
656
+ query.trace("resolve_type_lazy", trace_payload) do
657
+ schema.sync_lazy(resolved_type)
658
+ end
659
+ end
660
+ else
661
+ resolved_type
662
+ end
663
+ end
664
+
665
+ def authorized_new(type, value, context, path)
666
+ trace_payload = { context: context, type: type, object: value, path: path }
667
+
668
+ auth_val = context.query.trace("authorized", trace_payload) do
669
+ type.authorized_new(value, context)
670
+ end
671
+
672
+ if context.schema.lazy?(auth_val)
673
+ GraphQL::Execution::Lazy.new do
674
+ context.query.trace("authorized_lazy", trace_payload) do
675
+ context.schema.sync_lazy(auth_val)
676
+ end
677
+ end
678
+ else
679
+ auth_val
680
+ end
681
+ end
642
682
  end
643
683
  end
644
684
  end