graphql 1.10.6 → 1.10.11

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 (46) 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 +47 -38
  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/language/document_from_schema_definition.rb +42 -23
  16. data/lib/graphql/object_type.rb +1 -1
  17. data/lib/graphql/relay/base_connection.rb +0 -2
  18. data/lib/graphql/schema.rb +28 -13
  19. data/lib/graphql/schema/argument.rb +6 -0
  20. data/lib/graphql/schema/base_64_encoder.rb +2 -0
  21. data/lib/graphql/schema/enum.rb +9 -1
  22. data/lib/graphql/schema/field.rb +30 -21
  23. data/lib/graphql/schema/input_object.rb +9 -6
  24. data/lib/graphql/schema/interface.rb +5 -0
  25. data/lib/graphql/schema/list.rb +7 -1
  26. data/lib/graphql/schema/loader.rb +110 -103
  27. data/lib/graphql/schema/member.rb +1 -0
  28. data/lib/graphql/schema/member/has_arguments.rb +33 -13
  29. data/lib/graphql/schema/member/has_fields.rb +1 -1
  30. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  31. data/lib/graphql/schema/non_null.rb +5 -0
  32. data/lib/graphql/schema/object.rb +10 -3
  33. data/lib/graphql/schema/printer.rb +0 -14
  34. data/lib/graphql/schema/resolver.rb +1 -1
  35. data/lib/graphql/schema/union.rb +6 -0
  36. data/lib/graphql/schema/warden.rb +7 -1
  37. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +1 -0
  38. data/lib/graphql/subscriptions/subscription_root.rb +10 -2
  39. data/lib/graphql/tracing.rb +5 -4
  40. data/lib/graphql/tracing/new_relic_tracing.rb +1 -12
  41. data/lib/graphql/tracing/platform_tracing.rb +14 -0
  42. data/lib/graphql/tracing/scout_tracing.rb +11 -0
  43. data/lib/graphql/types/iso_8601_date.rb +3 -3
  44. data/lib/graphql/types/iso_8601_date_time.rb +18 -8
  45. data/lib/graphql/version.rb +1 -1
  46. metadata +6 -3
@@ -94,20 +94,6 @@ module GraphQL
94
94
  print(node)
95
95
  end
96
96
 
97
- def print_directive(directive)
98
- if directive.name == "deprecated"
99
- reason = directive.arguments.find { |arg| arg.name == "reason" }
100
-
101
- if reason.value == GraphQL::Schema::Directive::DEFAULT_DEPRECATION_REASON
102
- "@deprecated"
103
- else
104
- "@deprecated(reason: #{reason.value.to_s.inspect})"
105
- end
106
- else
107
- super
108
- end
109
- end
110
-
111
97
  class IntrospectionPrinter < GraphQL::Language::Printer
112
98
  def print_schema_definition(schema)
113
99
  "schema {\n query: Root\n}"
@@ -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,17 +15,17 @@ module GraphQL
15
15
  class ISO8601Date < GraphQL::Schema::Scalar
16
16
  description "An ISO 8601-encoded date"
17
17
 
18
- # @param value [Date]
18
+ # @param value [Date,Time,DateTime,String]
19
19
  # @return [String]
20
20
  def self.coerce_result(value, _ctx)
21
- value.iso8601
21
+ Date.parse(value.to_s).iso8601
22
22
  end
23
23
 
24
24
  # @param str_value [String]
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,19 +31,27 @@ module GraphQL
29
31
  @time_precision = value
30
32
  end
31
33
 
32
- # @param value [DateTime]
34
+ # @param value [Time,Date,DateTime,String]
33
35
  # @return [String]
34
36
  def self.coerce_result(value, _ctx)
35
- value.iso8601(time_precision)
36
- rescue ArgumentError
37
- raise GraphQL::Error, "An incompatible object (#{value.class}) was given to #{self}. Make sure that only DateTimes are used with this type."
37
+ case value
38
+ when Date
39
+ return value.to_time.iso8601(time_precision)
40
+ when ::String
41
+ return Time.parse(value).iso8601(time_precision)
42
+ else
43
+ # Time, DateTime or compatible is given:
44
+ return value.iso8601(time_precision)
45
+ end
46
+ rescue StandardError => error
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})"
38
48
  end
39
49
 
40
50
  # @param str_value [String]
41
- # @return [DateTime]
51
+ # @return [Time]
42
52
  def self.coerce_input(str_value, _ctx)
43
- DateTime.iso8601(str_value)
44
- rescue ArgumentError
53
+ Time.iso8601(str_value)
54
+ rescue ArgumentError, TypeError
45
55
  # Invalid input
46
56
  nil
47
57
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "1.10.6"
3
+ VERSION = "1.10.11"
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.6
4
+ version: 1.10.11
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-06 00:00:00.000000000 Z
11
+ date: 2020-06-11 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