graphql 1.10.7 → 1.10.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/object_generator.rb +50 -8
  3. data/lib/graphql.rb +4 -4
  4. data/lib/graphql/analysis/ast/query_complexity.rb +1 -1
  5. data/lib/graphql/compatibility/execution_specification/specification_schema.rb +2 -2
  6. data/lib/graphql/execution/instrumentation.rb +1 -1
  7. data/lib/graphql/execution/interpreter.rb +2 -0
  8. data/lib/graphql/execution/interpreter/argument_value.rb +28 -0
  9. data/lib/graphql/execution/interpreter/arguments.rb +36 -0
  10. data/lib/graphql/execution/interpreter/arguments_cache.rb +3 -7
  11. data/lib/graphql/execution/interpreter/runtime.rb +38 -35
  12. data/lib/graphql/execution/lookahead.rb +3 -1
  13. data/lib/graphql/internal_representation/scope.rb +2 -2
  14. data/lib/graphql/internal_representation/visit.rb +2 -2
  15. data/lib/graphql/object_type.rb +1 -1
  16. data/lib/graphql/relay/base_connection.rb +0 -2
  17. data/lib/graphql/schema.rb +17 -11
  18. data/lib/graphql/schema/argument.rb +6 -0
  19. data/lib/graphql/schema/base_64_encoder.rb +2 -0
  20. data/lib/graphql/schema/enum.rb +9 -1
  21. data/lib/graphql/schema/field.rb +30 -21
  22. data/lib/graphql/schema/input_object.rb +10 -9
  23. data/lib/graphql/schema/interface.rb +5 -0
  24. data/lib/graphql/schema/list.rb +2 -1
  25. data/lib/graphql/schema/loader.rb +3 -0
  26. data/lib/graphql/schema/member.rb +1 -0
  27. data/lib/graphql/schema/member/has_arguments.rb +33 -13
  28. data/lib/graphql/schema/member/has_fields.rb +1 -1
  29. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  30. data/lib/graphql/schema/object.rb +9 -2
  31. data/lib/graphql/schema/resolver.rb +1 -1
  32. data/lib/graphql/schema/union.rb +6 -0
  33. data/lib/graphql/schema/warden.rb +7 -1
  34. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -0
  35. data/lib/graphql/subscriptions/subscription_root.rb +10 -2
  36. data/lib/graphql/tracing.rb +5 -4
  37. data/lib/graphql/tracing/new_relic_tracing.rb +1 -12
  38. data/lib/graphql/tracing/platform_tracing.rb +14 -0
  39. data/lib/graphql/tracing/scout_tracing.rb +11 -0
  40. data/lib/graphql/types/iso_8601_date.rb +2 -2
  41. data/lib/graphql/types/iso_8601_date_time.rb +19 -15
  42. data/lib/graphql/version.rb +1 -1
  43. metadata +6 -3
@@ -71,6 +71,13 @@ module GraphQL
71
71
  end
72
72
 
73
73
  class << self
74
+ # Set up a type-specific invalid null error to use when this object's non-null fields wrongly return `nil`.
75
+ # It should help with debugging and bug tracker integrations.
76
+ def inherited(child_class)
77
+ child_class.const_set(:InvalidNullError, Class.new(GraphQL::InvalidNullError))
78
+ super
79
+ end
80
+
74
81
  def implements(*new_interfaces, **options)
75
82
  new_memberships = []
76
83
  new_interfaces.each do |int|
@@ -79,14 +86,14 @@ module GraphQL
79
86
  raise "#{int} cannot be implemented since it's not a GraphQL Interface. Use `include` for plain Ruby modules."
80
87
  end
81
88
 
82
- new_memberships << int.type_membership_class.new(int, self, options)
89
+ new_memberships << int.type_membership_class.new(int, self, **options)
83
90
 
84
91
  # Include the methods here,
85
92
  # `.fields` will use the inheritance chain
86
93
  # to find inherited fields
87
94
  include(int)
88
95
  elsif int.is_a?(GraphQL::InterfaceType)
89
- new_memberships << int.type_membership_class.new(int, self, options)
96
+ new_memberships << int.type_membership_class.new(int, self, **options)
90
97
  elsif int.is_a?(String) || int.is_a?(GraphQL::Schema::LateBoundType)
91
98
  if options.any?
92
99
  raise ArgumentError, "`implements(...)` doesn't support options with late-loaded types yet. Remove #{options} and open an issue to request this feature."
@@ -220,7 +220,7 @@ module GraphQL
220
220
  # or use it as a configuration method to assign a return type
221
221
  # instead of generating one.
222
222
  # TODO unify with {#null}
223
- # @param new_type [Class, nil] If a type definition class is provided, it will be used as the return type of the field
223
+ # @param new_type [Class, Array<Class>, nil] If a type definition class is provided, it will be used as the return type of the field
224
224
  # @param null [true, false] Whether or not the field may return `nil`
225
225
  # @return [Class] The type which this field returns.
226
226
  def type(new_type = nil, null: nil)
@@ -3,8 +3,14 @@ module GraphQL
3
3
  class Schema
4
4
  class Union < GraphQL::Schema::Member
5
5
  extend GraphQL::Schema::Member::AcceptsDefinition
6
+ extend GraphQL::Schema::Member::HasUnresolvedTypeError
6
7
 
7
8
  class << self
9
+ def inherited(child_class)
10
+ add_unresolved_type_error(child_class)
11
+ super
12
+ end
13
+
8
14
  def possible_types(*types, context: GraphQL::Query::NullContext, **options)
9
15
  if types.any?
10
16
  types.each do |t|
@@ -166,7 +166,13 @@ module GraphQL
166
166
  end
167
167
 
168
168
  def visible_field?(owner_type, field_defn)
169
- visible?(field_defn) && visible_type?(field_defn.type.unwrap) && field_on_visible_interface?(field_defn, owner_type)
169
+ # This field is visible in its own right
170
+ visible?(field_defn) &&
171
+ # This field's return type is visible
172
+ visible_type?(field_defn.type.unwrap) &&
173
+ # This field is either defined on this object type,
174
+ # or the interface it's inherited from is also visible
175
+ ((field_defn.respond_to?(:owner) && field_defn.owner == owner_type) || field_on_visible_interface?(field_defn, owner_type))
170
176
  end
171
177
 
172
178
  # We need this to tell whether a field was inherited by an interface
@@ -8,6 +8,7 @@ module GraphQL
8
8
  #
9
9
  # - No queueing system; ActiveJob should be added
10
10
  # - Take care to reload context when re-delivering the subscription. (see {Query#subscription_update?})
11
+ # - Avoid the async ActionCable adapter and use the redis or PostgreSQL adapters instead. Otherwise calling #trigger won't work from background jobs or the Rails console.
11
12
  #
12
13
  # @example Adding ActionCableSubscriptions to your schema
13
14
  # class MySchema < GraphQL::Schema
@@ -40,7 +40,7 @@ module GraphQL
40
40
  # for the backend to register:
41
41
  event = Subscriptions::Event.new(
42
42
  name: field.name,
43
- arguments: arguments,
43
+ arguments: arguments_without_field_extras(arguments: arguments),
44
44
  context: context,
45
45
  field: field,
46
46
  )
@@ -48,7 +48,7 @@ module GraphQL
48
48
  value
49
49
  elsif context.query.subscription_topic == Subscriptions::Event.serialize(
50
50
  field.name,
51
- arguments,
51
+ arguments_without_field_extras(arguments: arguments),
52
52
  field,
53
53
  scope: (field.subscription_scope ? context[field.subscription_scope] : nil),
54
54
  )
@@ -60,6 +60,14 @@ module GraphQL
60
60
  context.skip
61
61
  end
62
62
  end
63
+
64
+ private
65
+
66
+ def arguments_without_field_extras(arguments:)
67
+ arguments.dup.tap do |event_args|
68
+ field.extras.each { |k| event_args.delete(k) }
69
+ end
70
+ end
63
71
  end
64
72
  end
65
73
  end
@@ -63,8 +63,9 @@ module GraphQL
63
63
  # @param key [String] The name of the event in GraphQL internals
64
64
  # @param metadata [Hash] Event-related metadata (can be anything)
65
65
  # @return [Object] Must return the value of the block
66
- def trace(key, metadata)
67
- call_tracers(0, key, metadata) { yield }
66
+ def trace(key, metadata, &block)
67
+ return yield if @tracers.empty?
68
+ call_tracers(0, key, metadata, &block)
68
69
  end
69
70
 
70
71
  private
@@ -76,11 +77,11 @@ module GraphQL
76
77
  # @param key [String] The current event name
77
78
  # @param metadata [Object] The current event object
78
79
  # @return Whatever the block returns
79
- def call_tracers(idx, key, metadata)
80
+ def call_tracers(idx, key, metadata, &block)
80
81
  if idx == @tracers.length
81
82
  yield
82
83
  else
83
- @tracers[idx].trace(key, metadata) { call_tracers(idx + 1, key, metadata) { yield } }
84
+ @tracers[idx].trace(key, metadata) { call_tracers(idx + 1, key, metadata, &block) }
84
85
  end
85
86
  end
86
87
  end
@@ -26,18 +26,7 @@ module GraphQL
26
26
  if key == "execute_query"
27
27
  set_this_txn_name = data[:query].context[:set_new_relic_transaction_name]
28
28
  if set_this_txn_name == true || (set_this_txn_name.nil? && @set_transaction_name)
29
- query = data[:query]
30
- # Set the transaction name based on the operation type and name
31
- selected_op = query.selected_operation
32
- if selected_op
33
- op_type = selected_op.operation_type
34
- op_name = selected_op.name || "anonymous"
35
- else
36
- op_type = "query"
37
- op_name = "anonymous"
38
- end
39
-
40
- NewRelic::Agent.set_transaction_name("GraphQL/#{op_type}.#{op_name}")
29
+ NewRelic::Agent.set_transaction_name(transaction_name(data[:query]))
41
30
  end
42
31
  end
43
32
 
@@ -103,6 +103,20 @@ module GraphQL
103
103
  end
104
104
 
105
105
  private
106
+
107
+ # Get the transaction name based on the operation type and name
108
+ def transaction_name(query)
109
+ selected_op = query.selected_operation
110
+ if selected_op
111
+ op_type = selected_op.operation_type
112
+ op_name = selected_op.name || "anonymous"
113
+ else
114
+ op_type = "query"
115
+ op_name = "anonymous"
116
+ end
117
+ "GraphQL/#{op_type}.#{op_name}"
118
+ end
119
+
106
120
  attr_reader :options
107
121
 
108
122
  def platform_key_cache(ctx)
@@ -16,12 +16,23 @@ module GraphQL
16
16
  "execute_query_lazy" => "execute.graphql",
17
17
  }
18
18
 
19
+ # @param set_transaction_name [Boolean] If true, the GraphQL operation name will be used as the transaction name.
20
+ # This is not advised if you run more than one query per HTTP request, for example, with `graphql-client` or multiplexing.
21
+ # It can also be specified per-query with `context[:set_scout_transaction_name]`.
19
22
  def initialize(options = {})
20
23
  self.class.include ScoutApm::Tracer
24
+ @set_transaction_name = options.fetch(:set_transaction_name, false)
21
25
  super(options)
22
26
  end
23
27
 
24
28
  def platform_trace(platform_key, key, data)
29
+ if key == "execute_query"
30
+ set_this_txn_name = data[:query].context[:set_scout_transaction_name]
31
+ if set_this_txn_name == true || (set_this_txn_name.nil? && @set_transaction_name)
32
+ ScoutApm::Transaction.rename(transaction_name(data[:query]))
33
+ end
34
+ end
35
+
25
36
  self.class.instrument("GraphQL", platform_key, INSTRUMENT_OPTS) do
26
37
  yield
27
38
  end
@@ -15,7 +15,7 @@ module GraphQL
15
15
  class ISO8601Date < GraphQL::Schema::Scalar
16
16
  description "An ISO 8601-encoded date"
17
17
 
18
- # @param value [Date,DateTime,String]
18
+ # @param value [Date,Time,DateTime,String]
19
19
  # @return [String]
20
20
  def self.coerce_result(value, _ctx)
21
21
  Date.parse(value.to_s).iso8601
@@ -25,7 +25,7 @@ module GraphQL
25
25
  # @return [Date]
26
26
  def self.coerce_input(str_value, _ctx)
27
27
  Date.iso8601(str_value)
28
- rescue ArgumentError
28
+ rescue ArgumentError, TypeError
29
29
  # Invalid input
30
30
  nil
31
31
  end
@@ -1,7 +1,9 @@
1
+ require 'time'
2
+
1
3
  # frozen_string_literal: true
2
4
  module GraphQL
3
5
  module Types
4
- # This scalar takes `DateTime`s and transmits them as strings,
6
+ # This scalar takes `Time`s and transmits them as strings,
5
7
  # using ISO 8601 format.
6
8
  #
7
9
  # Use it for fields or arguments as follows:
@@ -29,31 +31,33 @@ module GraphQL
29
31
  @time_precision = value
30
32
  end
31
33
 
32
- # @param value [Date,DateTime,String]
34
+ # @param value [Time,Date,DateTime,String]
33
35
  # @return [String]
34
- def self.coerce_result(value, _ctx)\
36
+ def self.coerce_result(value, _ctx)
35
37
  case value
36
- when DateTime
37
- return value.iso8601(time_precision)
38
38
  when Date
39
- return DateTime.parse(value.to_s).iso8601(time_precision)
39
+ return value.to_time.iso8601(time_precision)
40
40
  when ::String
41
- return DateTime.parse(value).iso8601(time_precision)
41
+ return Time.parse(value).iso8601(time_precision)
42
42
  else
43
- # In case some other API-compliant thing is given:
43
+ # Time, DateTime or compatible is given:
44
44
  return value.iso8601(time_precision)
45
- end
45
+ end
46
46
  rescue StandardError => error
47
- raise GraphQL::Error, "An incompatible object (#{value.class}) was given to #{self}. Make sure that only Dates, DateTimes, and well-formatted Strings are used with this type. (#{error.message})"
47
+ raise GraphQL::Error, "An incompatible object (#{value.class}) was given to #{self}. Make sure that only Times, Dates, DateTimes, and well-formatted Strings are used with this type. (#{error.message})"
48
48
  end
49
49
 
50
50
  # @param str_value [String]
51
- # @return [DateTime]
51
+ # @return [Time]
52
52
  def self.coerce_input(str_value, _ctx)
53
- DateTime.iso8601(str_value)
54
- rescue ArgumentError
55
- # Invalid input
56
- nil
53
+ Time.iso8601(str_value)
54
+ rescue ArgumentError, TypeError
55
+ begin
56
+ Date.iso8601(str_value).to_time
57
+ rescue ArgumentError, TypeError
58
+ # Invalid input
59
+ nil
60
+ end
57
61
  end
58
62
  end
59
63
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "1.10.7"
3
+ VERSION = "1.10.12"
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.7
4
+ version: 1.10.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-16 00:00:00.000000000 Z
11
+ date: 2020-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark-ips
@@ -422,6 +422,8 @@ files:
422
422
  - lib/graphql/execution/flatten.rb
423
423
  - lib/graphql/execution/instrumentation.rb
424
424
  - lib/graphql/execution/interpreter.rb
425
+ - lib/graphql/execution/interpreter/argument_value.rb
426
+ - lib/graphql/execution/interpreter/arguments.rb
425
427
  - lib/graphql/execution/interpreter/arguments_cache.rb
426
428
  - lib/graphql/execution/interpreter/execution_errors.rb
427
429
  - lib/graphql/execution/interpreter/handles_raw_value.rb
@@ -580,6 +582,7 @@ files:
580
582
  - lib/graphql/schema/member/has_ast_node.rb
581
583
  - lib/graphql/schema/member/has_fields.rb
582
584
  - lib/graphql/schema/member/has_path.rb
585
+ - lib/graphql/schema/member/has_unresolved_type_error.rb
583
586
  - lib/graphql/schema/member/instrumentation.rb
584
587
  - lib/graphql/schema/member/relay_shortcuts.rb
585
588
  - lib/graphql/schema/member/scoped.rb
@@ -746,7 +749,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
746
749
  - !ruby/object:Gem::Version
747
750
  version: '0'
748
751
  requirements: []
749
- rubygems_version: 3.0.3
752
+ rubygems_version: 3.1.2
750
753
  signing_key:
751
754
  specification_version: 4
752
755
  summary: A GraphQL language and runtime for Ruby