graphql 1.10.10 → 1.11.1

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/object_generator.rb +50 -8
  3. data/lib/graphql.rb +3 -3
  4. data/lib/graphql/execution/interpreter.rb +1 -1
  5. data/lib/graphql/execution/interpreter/arguments.rb +1 -5
  6. data/lib/graphql/execution/interpreter/runtime.rb +20 -24
  7. data/lib/graphql/execution/multiplex.rb +1 -2
  8. data/lib/graphql/introspection/schema_type.rb +3 -3
  9. data/lib/graphql/invalid_null_error.rb +18 -0
  10. data/lib/graphql/pagination/connection.rb +13 -6
  11. data/lib/graphql/pagination/connections.rb +5 -4
  12. data/lib/graphql/query.rb +1 -2
  13. data/lib/graphql/schema.rb +26 -3
  14. data/lib/graphql/schema/argument.rb +6 -0
  15. data/lib/graphql/schema/build_from_definition.rb +7 -12
  16. data/lib/graphql/schema/enum.rb +9 -1
  17. data/lib/graphql/schema/field.rb +68 -80
  18. data/lib/graphql/schema/field/connection_extension.rb +2 -1
  19. data/lib/graphql/schema/input_object.rb +1 -3
  20. data/lib/graphql/schema/interface.rb +5 -0
  21. data/lib/graphql/schema/member.rb +1 -0
  22. data/lib/graphql/schema/member/has_arguments.rb +6 -0
  23. data/lib/graphql/schema/member/has_fields.rb +1 -1
  24. data/lib/graphql/schema/member/has_unresolved_type_error.rb +15 -0
  25. data/lib/graphql/schema/object.rb +7 -0
  26. data/lib/graphql/schema/resolver.rb +14 -0
  27. data/lib/graphql/schema/subscription.rb +1 -1
  28. data/lib/graphql/schema/union.rb +6 -0
  29. data/lib/graphql/schema/warden.rb +0 -1
  30. data/lib/graphql/subscriptions.rb +41 -8
  31. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +49 -5
  32. data/lib/graphql/subscriptions/broadcast_analyzer.rb +84 -0
  33. data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +21 -0
  34. data/lib/graphql/subscriptions/event.rb +16 -1
  35. data/lib/graphql/subscriptions/subscription_root.rb +13 -3
  36. data/lib/graphql/tracing.rb +1 -27
  37. data/lib/graphql/tracing/new_relic_tracing.rb +1 -12
  38. data/lib/graphql/tracing/platform_tracing.rb +39 -15
  39. data/lib/graphql/tracing/scout_tracing.rb +11 -0
  40. data/lib/graphql/tracing/statsd_tracing.rb +42 -0
  41. data/lib/graphql/types/iso_8601_date.rb +1 -1
  42. data/lib/graphql/types/iso_8601_date_time.rb +17 -13
  43. data/lib/graphql/version.rb +1 -1
  44. metadata +6 -2
@@ -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
 
@@ -32,17 +32,19 @@ module GraphQL
32
32
  trace_field = true # implemented with instrumenter
33
33
  else
34
34
  field = data[:field]
35
- cache = platform_key_cache(data.fetch(:query).context)
36
- platform_key = cache.fetch(field) do
37
- cache[field] = platform_field_key(data[:owner], field)
38
- end
39
-
40
35
  return_type = field.type.unwrap
41
36
  trace_field = if return_type.kind.scalar? || return_type.kind.enum?
42
37
  (field.trace.nil? && @trace_scalars) || field.trace
43
38
  else
44
39
  true
45
40
  end
41
+
42
+ platform_key = if trace_field
43
+ context = data.fetch(:query).context
44
+ cached_platform_key(context, field) { platform_field_key(data[:owner], field) }
45
+ else
46
+ nil
47
+ end
46
48
  end
47
49
 
48
50
  if platform_key && trace_field
@@ -53,20 +55,16 @@ module GraphQL
53
55
  yield
54
56
  end
55
57
  when "authorized", "authorized_lazy"
56
- cache = platform_key_cache(data.fetch(:context))
57
58
  type = data.fetch(:type)
58
- platform_key = cache.fetch(type) do
59
- cache[type] = platform_authorized_key(type)
60
- end
59
+ context = data.fetch(:context)
60
+ platform_key = cached_platform_key(context, type) { platform_authorized_key(type) }
61
61
  platform_trace(platform_key, key, data) do
62
62
  yield
63
63
  end
64
64
  when "resolve_type", "resolve_type_lazy"
65
- cache = platform_key_cache(data.fetch(:context))
66
65
  type = data.fetch(:type)
67
- platform_key = cache.fetch(type) do
68
- cache[type] = platform_resolve_type_key(type)
69
- end
66
+ context = data.fetch(:context)
67
+ platform_key = cached_platform_key(context, type) { platform_resolve_type_key(type) }
70
68
  platform_trace(platform_key, key, data) do
71
69
  yield
72
70
  end
@@ -103,10 +101,36 @@ module GraphQL
103
101
  end
104
102
 
105
103
  private
104
+
105
+ # Get the transaction name based on the operation type and name
106
+ def transaction_name(query)
107
+ selected_op = query.selected_operation
108
+ if selected_op
109
+ op_type = selected_op.operation_type
110
+ op_name = selected_op.name || "anonymous"
111
+ else
112
+ op_type = "query"
113
+ op_name = "anonymous"
114
+ end
115
+ "GraphQL/#{op_type}.#{op_name}"
116
+ end
117
+
106
118
  attr_reader :options
107
119
 
108
- def platform_key_cache(ctx)
109
- ctx.namespace(self.class)[:platform_key_cache] ||= {}
120
+ # Different kind of schema objects have different kinds of keys:
121
+ #
122
+ # - Object types: `.authorized`
123
+ # - Union/Interface types: `.resolve_type`
124
+ # - Fields: execution
125
+ #
126
+ # So, they can all share one cache.
127
+ #
128
+ # If the key isn't present, the given block is called and the result is cached for `key`.
129
+ #
130
+ # @return [String]
131
+ def cached_platform_key(ctx, key)
132
+ cache = ctx.namespace(self.class)[:platform_key_cache] ||= {}
133
+ cache.fetch(key) { cache[key] = yield }
110
134
  end
111
135
  end
112
136
  end
@@ -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
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module Tracing
5
+ class StatsdTracing < PlatformTracing
6
+ self.platform_keys = {
7
+ 'lex' => "graphql.lex",
8
+ 'parse' => "graphql.parse",
9
+ 'validate' => "graphql.validate",
10
+ 'analyze_query' => "graphql.analyze_query",
11
+ 'analyze_multiplex' => "graphql.analyze_multiplex",
12
+ 'execute_multiplex' => "graphql.execute_multiplex",
13
+ 'execute_query' => "graphql.execute_query",
14
+ 'execute_query_lazy' => "graphql.execute_query_lazy",
15
+ }
16
+
17
+ # @param statsd [Object] A statsd client
18
+ def initialize(statsd:, **rest)
19
+ @statsd = statsd
20
+ super(**rest)
21
+ end
22
+
23
+ def platform_trace(platform_key, key, data)
24
+ @statsd.time(platform_key) do
25
+ yield
26
+ end
27
+ end
28
+
29
+ def platform_field_key(type, field)
30
+ "graphql.#{type.graphql_name}.#{field.graphql_name}"
31
+ end
32
+
33
+ def platform_authorized_key(type)
34
+ "graphql.authorized.#{type.graphql_name}"
35
+ end
36
+
37
+ def platform_resolve_type_key(type)
38
+ "graphql.resolve_type.#{type.graphql_name}"
39
+ end
40
+ end
41
+ end
42
+ 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
@@ -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
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)
53
+ Time.iso8601(str_value)
54
54
  rescue ArgumentError, TypeError
55
- # Invalid input
56
- nil
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.10"
3
+ VERSION = "1.11.1"
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.10
4
+ version: 1.11.1
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-05-20 00:00:00.000000000 Z
11
+ date: 2020-06-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark-ips
@@ -582,6 +582,7 @@ files:
582
582
  - lib/graphql/schema/member/has_ast_node.rb
583
583
  - lib/graphql/schema/member/has_fields.rb
584
584
  - lib/graphql/schema/member/has_path.rb
585
+ - lib/graphql/schema/member/has_unresolved_type_error.rb
585
586
  - lib/graphql/schema/member/instrumentation.rb
586
587
  - lib/graphql/schema/member/relay_shortcuts.rb
587
588
  - lib/graphql/schema/member/scoped.rb
@@ -680,6 +681,8 @@ files:
680
681
  - lib/graphql/string_type.rb
681
682
  - lib/graphql/subscriptions.rb
682
683
  - lib/graphql/subscriptions/action_cable_subscriptions.rb
684
+ - lib/graphql/subscriptions/broadcast_analyzer.rb
685
+ - lib/graphql/subscriptions/default_subscription_resolve_extension.rb
683
686
  - lib/graphql/subscriptions/event.rb
684
687
  - lib/graphql/subscriptions/instrumentation.rb
685
688
  - lib/graphql/subscriptions/serialize.rb
@@ -695,6 +698,7 @@ files:
695
698
  - lib/graphql/tracing/prometheus_tracing/graphql_collector.rb
696
699
  - lib/graphql/tracing/scout_tracing.rb
697
700
  - lib/graphql/tracing/skylight_tracing.rb
701
+ - lib/graphql/tracing/statsd_tracing.rb
698
702
  - lib/graphql/type_kinds.rb
699
703
  - lib/graphql/types.rb
700
704
  - lib/graphql/types/big_int.rb