graphql 1.11.3 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/core.rb +8 -0
  3. data/lib/generators/graphql/install_generator.rb +5 -5
  4. data/lib/generators/graphql/object_generator.rb +2 -0
  5. data/lib/generators/graphql/relay_generator.rb +63 -0
  6. data/lib/generators/graphql/templates/base_argument.erb +2 -0
  7. data/lib/generators/graphql/templates/base_connection.erb +8 -0
  8. data/lib/generators/graphql/templates/base_edge.erb +8 -0
  9. data/lib/generators/graphql/templates/base_enum.erb +2 -0
  10. data/lib/generators/graphql/templates/base_field.erb +2 -0
  11. data/lib/generators/graphql/templates/base_input_object.erb +2 -0
  12. data/lib/generators/graphql/templates/base_interface.erb +2 -0
  13. data/lib/generators/graphql/templates/base_mutation.erb +2 -0
  14. data/lib/generators/graphql/templates/base_object.erb +2 -0
  15. data/lib/generators/graphql/templates/base_scalar.erb +2 -0
  16. data/lib/generators/graphql/templates/base_union.erb +2 -0
  17. data/lib/generators/graphql/templates/enum.erb +2 -0
  18. data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
  19. data/lib/generators/graphql/templates/interface.erb +2 -0
  20. data/lib/generators/graphql/templates/loader.erb +2 -0
  21. data/lib/generators/graphql/templates/mutation.erb +2 -0
  22. data/lib/generators/graphql/templates/mutation_type.erb +2 -0
  23. data/lib/generators/graphql/templates/node_type.erb +9 -0
  24. data/lib/generators/graphql/templates/object.erb +3 -1
  25. data/lib/generators/graphql/templates/query_type.erb +3 -3
  26. data/lib/generators/graphql/templates/scalar.erb +2 -0
  27. data/lib/generators/graphql/templates/schema.erb +10 -35
  28. data/lib/generators/graphql/templates/union.erb +3 -1
  29. data/lib/graphql.rb +55 -4
  30. data/lib/graphql/analysis/analyze_query.rb +7 -0
  31. data/lib/graphql/analysis/ast.rb +11 -2
  32. data/lib/graphql/analysis/ast/visitor.rb +9 -1
  33. data/lib/graphql/argument.rb +3 -3
  34. data/lib/graphql/backtrace.rb +28 -19
  35. data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
  36. data/lib/graphql/backtrace/table.rb +22 -2
  37. data/lib/graphql/backtrace/tracer.rb +40 -8
  38. data/lib/graphql/backwards_compatibility.rb +1 -0
  39. data/lib/graphql/compatibility/execution_specification.rb +1 -0
  40. data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
  41. data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
  42. data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
  43. data/lib/graphql/dataloader.rb +197 -0
  44. data/lib/graphql/dataloader/null_dataloader.rb +21 -0
  45. data/lib/graphql/dataloader/request.rb +24 -0
  46. data/lib/graphql/dataloader/request_all.rb +22 -0
  47. data/lib/graphql/dataloader/source.rb +93 -0
  48. data/lib/graphql/define/assign_global_id_field.rb +2 -2
  49. data/lib/graphql/define/instance_definable.rb +32 -2
  50. data/lib/graphql/define/type_definer.rb +5 -5
  51. data/lib/graphql/deprecated_dsl.rb +5 -0
  52. data/lib/graphql/enum_type.rb +2 -0
  53. data/lib/graphql/execution/errors.rb +4 -0
  54. data/lib/graphql/execution/execute.rb +7 -0
  55. data/lib/graphql/execution/interpreter.rb +20 -6
  56. data/lib/graphql/execution/interpreter/arguments.rb +57 -5
  57. data/lib/graphql/execution/interpreter/arguments_cache.rb +8 -0
  58. data/lib/graphql/execution/interpreter/handles_raw_value.rb +0 -7
  59. data/lib/graphql/execution/interpreter/runtime.rb +251 -138
  60. data/lib/graphql/execution/multiplex.rb +20 -6
  61. data/lib/graphql/function.rb +4 -0
  62. data/lib/graphql/input_object_type.rb +2 -0
  63. data/lib/graphql/integer_decoding_error.rb +17 -0
  64. data/lib/graphql/interface_type.rb +3 -1
  65. data/lib/graphql/introspection.rb +96 -0
  66. data/lib/graphql/introspection/field_type.rb +7 -3
  67. data/lib/graphql/introspection/input_value_type.rb +6 -0
  68. data/lib/graphql/introspection/introspection_query.rb +6 -92
  69. data/lib/graphql/introspection/type_type.rb +7 -3
  70. data/lib/graphql/invalid_null_error.rb +1 -1
  71. data/lib/graphql/language/block_string.rb +24 -5
  72. data/lib/graphql/language/document_from_schema_definition.rb +50 -23
  73. data/lib/graphql/language/lexer.rb +7 -3
  74. data/lib/graphql/language/lexer.rl +7 -3
  75. data/lib/graphql/language/nodes.rb +1 -1
  76. data/lib/graphql/language/parser.rb +107 -103
  77. data/lib/graphql/language/parser.y +4 -0
  78. data/lib/graphql/language/sanitized_printer.rb +59 -26
  79. data/lib/graphql/name_validator.rb +6 -7
  80. data/lib/graphql/object_type.rb +2 -0
  81. data/lib/graphql/pagination/connection.rb +5 -1
  82. data/lib/graphql/pagination/connections.rb +15 -17
  83. data/lib/graphql/query.rb +8 -3
  84. data/lib/graphql/query/context.rb +38 -4
  85. data/lib/graphql/query/fingerprint.rb +2 -0
  86. data/lib/graphql/query/serial_execution.rb +1 -0
  87. data/lib/graphql/query/validation_pipeline.rb +4 -1
  88. data/lib/graphql/relay/array_connection.rb +2 -2
  89. data/lib/graphql/relay/base_connection.rb +7 -0
  90. data/lib/graphql/relay/connection_instrumentation.rb +4 -4
  91. data/lib/graphql/relay/connection_type.rb +1 -1
  92. data/lib/graphql/relay/mutation.rb +1 -0
  93. data/lib/graphql/relay/node.rb +3 -0
  94. data/lib/graphql/relay/range_add.rb +14 -5
  95. data/lib/graphql/relay/type_extensions.rb +2 -0
  96. data/lib/graphql/scalar_type.rb +2 -0
  97. data/lib/graphql/schema.rb +107 -38
  98. data/lib/graphql/schema/argument.rb +74 -5
  99. data/lib/graphql/schema/build_from_definition.rb +203 -86
  100. data/lib/graphql/schema/default_type_error.rb +2 -0
  101. data/lib/graphql/schema/directive.rb +76 -0
  102. data/lib/graphql/schema/directive/deprecated.rb +1 -1
  103. data/lib/graphql/schema/directive/flagged.rb +57 -0
  104. data/lib/graphql/schema/enum.rb +3 -0
  105. data/lib/graphql/schema/enum_value.rb +12 -6
  106. data/lib/graphql/schema/field.rb +59 -24
  107. data/lib/graphql/schema/field/connection_extension.rb +11 -9
  108. data/lib/graphql/schema/field/scope_extension.rb +1 -1
  109. data/lib/graphql/schema/input_object.rb +38 -25
  110. data/lib/graphql/schema/interface.rb +2 -1
  111. data/lib/graphql/schema/late_bound_type.rb +2 -2
  112. data/lib/graphql/schema/loader.rb +1 -0
  113. data/lib/graphql/schema/member.rb +4 -0
  114. data/lib/graphql/schema/member/base_dsl_methods.rb +1 -0
  115. data/lib/graphql/schema/member/build_type.rb +17 -7
  116. data/lib/graphql/schema/member/has_arguments.rb +70 -51
  117. data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
  118. data/lib/graphql/schema/member/has_directives.rb +98 -0
  119. data/lib/graphql/schema/member/has_fields.rb +2 -2
  120. data/lib/graphql/schema/member/has_validators.rb +31 -0
  121. data/lib/graphql/schema/member/type_system_helpers.rb +3 -3
  122. data/lib/graphql/schema/object.rb +11 -0
  123. data/lib/graphql/schema/printer.rb +5 -4
  124. data/lib/graphql/schema/relay_classic_mutation.rb +4 -2
  125. data/lib/graphql/schema/resolver.rb +7 -0
  126. data/lib/graphql/schema/resolver/has_payload_type.rb +2 -0
  127. data/lib/graphql/schema/subscription.rb +20 -12
  128. data/lib/graphql/schema/timeout.rb +29 -15
  129. data/lib/graphql/schema/timeout_middleware.rb +2 -0
  130. data/lib/graphql/schema/unique_within_type.rb +1 -2
  131. data/lib/graphql/schema/validation.rb +10 -0
  132. data/lib/graphql/schema/validator.rb +163 -0
  133. data/lib/graphql/schema/validator/exclusion_validator.rb +31 -0
  134. data/lib/graphql/schema/validator/format_validator.rb +49 -0
  135. data/lib/graphql/schema/validator/inclusion_validator.rb +33 -0
  136. data/lib/graphql/schema/validator/length_validator.rb +57 -0
  137. data/lib/graphql/schema/validator/numericality_validator.rb +71 -0
  138. data/lib/graphql/schema/validator/required_validator.rb +68 -0
  139. data/lib/graphql/schema/warden.rb +2 -3
  140. data/lib/graphql/static_validation.rb +1 -0
  141. data/lib/graphql/static_validation/all_rules.rb +1 -0
  142. data/lib/graphql/static_validation/rules/fields_will_merge.rb +25 -17
  143. data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
  144. data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
  145. data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
  146. data/lib/graphql/static_validation/validator.rb +31 -7
  147. data/lib/graphql/subscriptions.rb +23 -16
  148. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +21 -7
  149. data/lib/graphql/tracing.rb +2 -2
  150. data/lib/graphql/tracing/appoptics_tracing.rb +12 -2
  151. data/lib/graphql/tracing/platform_tracing.rb +4 -2
  152. data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
  153. data/lib/graphql/tracing/skylight_tracing.rb +1 -1
  154. data/lib/graphql/types/int.rb +9 -2
  155. data/lib/graphql/types/iso_8601_date_time.rb +2 -1
  156. data/lib/graphql/types/relay.rb +11 -3
  157. data/lib/graphql/types/relay/base_connection.rb +2 -90
  158. data/lib/graphql/types/relay/base_edge.rb +2 -34
  159. data/lib/graphql/types/relay/connection_behaviors.rb +123 -0
  160. data/lib/graphql/types/relay/default_relay.rb +27 -0
  161. data/lib/graphql/types/relay/edge_behaviors.rb +42 -0
  162. data/lib/graphql/types/relay/has_node_field.rb +41 -0
  163. data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
  164. data/lib/graphql/types/relay/node.rb +2 -4
  165. data/lib/graphql/types/relay/node_behaviors.rb +15 -0
  166. data/lib/graphql/types/relay/node_field.rb +1 -19
  167. data/lib/graphql/types/relay/nodes_field.rb +1 -19
  168. data/lib/graphql/types/relay/page_info.rb +2 -14
  169. data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
  170. data/lib/graphql/types/string.rb +7 -1
  171. data/lib/graphql/unauthorized_error.rb +1 -1
  172. data/lib/graphql/union_type.rb +2 -0
  173. data/lib/graphql/upgrader/member.rb +1 -0
  174. data/lib/graphql/upgrader/schema.rb +1 -0
  175. data/lib/graphql/version.rb +1 -1
  176. data/readme.md +1 -1
  177. metadata +38 -9
  178. data/lib/graphql/types/relay/base_field.rb +0 -22
  179. data/lib/graphql/types/relay/base_interface.rb +0 -29
  180. data/lib/graphql/types/relay/base_object.rb +0 -26
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ class InputObjectNamesAreUniqueError < StaticValidation::Error
5
+ attr_reader :name
6
+
7
+ def initialize(message, path: nil, nodes: [], name:)
8
+ super(message, path: path, nodes: nodes)
9
+ @name = name
10
+ end
11
+
12
+ # A hash representation of this Message
13
+ def to_h
14
+ extensions = {
15
+ "code" => code,
16
+ "name" => name
17
+ }
18
+
19
+ super.merge({
20
+ "extensions" => extensions
21
+ })
22
+ end
23
+
24
+ def code
25
+ "inputFieldNotUnique"
26
+ end
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module StaticValidation
4
+ class ValidationTimeoutError < StaticValidation::Error
5
+ def initialize(message, path: nil, nodes: [])
6
+ super(message, path: path, nodes: nodes)
7
+ end
8
+
9
+ # A hash representation of this Message
10
+ def to_h
11
+ extensions = {
12
+ "code" => code
13
+ }
14
+
15
+ super.merge({
16
+ "extensions" => extensions
17
+ })
18
+ end
19
+
20
+ def code
21
+ "validationTimeout"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -20,8 +20,10 @@ module GraphQL
20
20
 
21
21
  # Validate `query` against the schema. Returns an array of message hashes.
22
22
  # @param query [GraphQL::Query]
23
+ # @param validate [Boolean]
24
+ # @param timeout [Float] Number of seconds to wait before aborting validation. Any positive number may be used, including Floats to specify fractional seconds.
23
25
  # @return [Array<Hash>]
24
- def validate(query, validate: true)
26
+ def validate(query, validate: true, timeout: nil)
25
27
  query.trace("validate", { validate: validate, query: query }) do
26
28
  can_skip_rewrite = query.context.interpreter? && query.schema.using_ast_analysis? && query.schema.is_a?(Class)
27
29
  errors = if validate == false && can_skip_rewrite
@@ -32,18 +34,31 @@ module GraphQL
32
34
 
33
35
  context = GraphQL::StaticValidation::ValidationContext.new(query, visitor_class)
34
36
 
35
- # Attach legacy-style rules
36
- rules_to_use.each do |rule_class_or_module|
37
- if rule_class_or_module.method_defined?(:validate)
38
- rule_class_or_module.new.validate(context)
37
+ begin
38
+ # CAUTION: Usage of the timeout module makes the assumption that validation rules are stateless Ruby code that requires no cleanup if process was interrupted. This means no blocking IO calls, native gems, locks, or `rescue` clauses that must be reached.
39
+ # A timeout value of 0 or nil will execute the block without any timeout.
40
+ Timeout::timeout(timeout) do
41
+ # Attach legacy-style rules.
42
+ # Only loop through rules if it has legacy-style rules
43
+ unless (legacy_rules = rules_to_use - GraphQL::StaticValidation::ALL_RULES).empty?
44
+ legacy_rules.each do |rule_class_or_module|
45
+ if rule_class_or_module.method_defined?(:validate)
46
+ warn "Legacy validator rules will be removed from GraphQL-Ruby 2.0, use a module instead (see the built-in rules: https://github.com/rmosolgo/graphql-ruby/tree/master/lib/graphql/static_validation/rules)"
47
+ warn " -> Legacy validator: #{rule_class_or_module}"
48
+ rule_class_or_module.new.validate(context)
49
+ end
50
+ end
51
+ end
52
+
53
+ context.visitor.visit
39
54
  end
55
+ rescue Timeout::Error
56
+ handle_timeout(query, context)
40
57
  end
41
58
 
42
- context.visitor.visit
43
59
  context.errors
44
60
  end
45
61
 
46
-
47
62
  irep = if errors.empty? && context
48
63
  # Only return this if there are no errors and validation was actually run
49
64
  context.visitor.rewrite_document
@@ -57,6 +72,15 @@ module GraphQL
57
72
  }
58
73
  end
59
74
  end
75
+
76
+ # Invoked when static validation times out.
77
+ # @param query [GraphQL::Query]
78
+ # @param context [GraphQL::StaticValidation::ValidationContext]
79
+ def handle_timeout(query, context)
80
+ context.errors << GraphQL::StaticValidation::ValidationTimeoutError.new(
81
+ "Timeout on validation of query"
82
+ )
83
+ end
60
84
  end
61
85
  end
62
86
  end
@@ -4,9 +4,7 @@ require "graphql/subscriptions/broadcast_analyzer"
4
4
  require "graphql/subscriptions/event"
5
5
  require "graphql/subscriptions/instrumentation"
6
6
  require "graphql/subscriptions/serialize"
7
- if defined?(ActionCable)
8
- require "graphql/subscriptions/action_cable_subscriptions"
9
- end
7
+ require "graphql/subscriptions/action_cable_subscriptions"
10
8
  require "graphql/subscriptions/subscription_root"
11
9
  require "graphql/subscriptions/default_subscription_resolve_extension"
12
10
 
@@ -28,7 +26,9 @@ module GraphQL
28
26
 
29
27
  instrumentation = Subscriptions::Instrumentation.new(schema: schema)
30
28
  defn.instrument(:query, instrumentation)
31
- defn.instrument(:field, instrumentation)
29
+ if !schema.is_a?(Class)
30
+ defn.instrument(:field, instrumentation)
31
+ end
32
32
  options[:schema] = schema
33
33
  schema.subscriptions = self.new(**options)
34
34
  schema.add_subscription_extension_if_necessary
@@ -100,16 +100,16 @@ module GraphQL
100
100
  # Lookup the saved data for this subscription
101
101
  query_data = read_subscription(subscription_id)
102
102
  if query_data.nil?
103
- # Jump down to the `delete_subscription` call
104
- raise GraphQL::Schema::Subscription::UnsubscribedError
103
+ delete_subscription(subscription_id)
104
+ return nil
105
105
  end
106
+
106
107
  # Fetch the required keys from the saved data
107
108
  query_string = query_data.fetch(:query_string)
108
109
  variables = query_data.fetch(:variables)
109
110
  context = query_data.fetch(:context)
110
111
  operation_name = query_data.fetch(:operation_name)
111
- # Re-evaluate the saved query
112
- @schema.execute(
112
+ result = @schema.execute(
113
113
  query: query_string,
114
114
  context: context,
115
115
  subscription_topic: event.topic,
@@ -117,14 +117,21 @@ module GraphQL
117
117
  variables: variables,
118
118
  root_value: object,
119
119
  )
120
- rescue GraphQL::Schema::Subscription::NoUpdateError
121
- # This update was skipped in user code; do nothing.
122
- nil
123
- rescue GraphQL::Schema::Subscription::UnsubscribedError
124
- # `unsubscribe` was called, clean up on our side
125
- # TODO also send `{more: false}` to client?
126
- delete_subscription(subscription_id)
127
- nil
120
+ subscriptions_context = result.context.namespace(:subscriptions)
121
+ if subscriptions_context[:no_update]
122
+ result = nil
123
+ end
124
+
125
+ unsubscribed = subscriptions_context[:unsubscribed]
126
+
127
+ if unsubscribed
128
+ # `unsubscribe` was called, clean up on our side
129
+ # TODO also send `{more: false}` to client?
130
+ delete_subscription(subscription_id)
131
+ result = nil
132
+ end
133
+
134
+ result
128
135
  end
129
136
 
130
137
  # Run the update query for this subscription and deliver it
@@ -4,7 +4,7 @@ module GraphQL
4
4
  # A subscriptions implementation that sends data
5
5
  # as ActionCable broadcastings.
6
6
  #
7
- # Experimental, some things to keep in mind:
7
+ # Some things to keep in mind:
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?})
@@ -86,28 +86,32 @@ module GraphQL
86
86
  EVENT_PREFIX = "graphql-event:"
87
87
 
88
88
  # @param serializer [<#dump(obj), #load(string)] Used for serializing messages before handing them to `.broadcast(msg)`
89
- def initialize(serializer: Serialize, **rest)
89
+ # @param namespace [string] Used to namespace events and subscriptions (default: '')
90
+ def initialize(serializer: Serialize, namespace: '', action_cable: ActionCable, action_cable_coder: ActiveSupport::JSON, **rest)
90
91
  # A per-process map of subscriptions to deliver.
91
92
  # This is provided by Rails, so let's use it
92
93
  @subscriptions = Concurrent::Map.new
93
94
  @events = Concurrent::Map.new { |h, k| h[k] = Concurrent::Map.new { |h2, k2| h2[k2] = Concurrent::Array.new } }
95
+ @action_cable = action_cable
96
+ @action_cable_coder = action_cable_coder
94
97
  @serializer = serializer
98
+ @transmit_ns = namespace
95
99
  super
96
100
  end
97
101
 
98
102
  # An event was triggered; Push the data over ActionCable.
99
103
  # Subscribers will re-evaluate locally.
100
104
  def execute_all(event, object)
101
- stream = EVENT_PREFIX + event.topic
105
+ stream = stream_event_name(event)
102
106
  message = @serializer.dump(object)
103
- ActionCable.server.broadcast(stream, message)
107
+ @action_cable.server.broadcast(stream, message)
104
108
  end
105
109
 
106
110
  # This subscription was re-evaluated.
107
111
  # Send it to the specific stream where this client was waiting.
108
112
  def deliver(subscription_id, result)
109
113
  payload = { result: result.to_h, more: true }
110
- ActionCable.server.broadcast(SUBSCRIPTION_PREFIX + subscription_id, payload)
114
+ @action_cable.server.broadcast(stream_subscription_name(subscription_id), payload)
111
115
  end
112
116
 
113
117
  # A query was run where these events were subscribed to.
@@ -117,7 +121,7 @@ module GraphQL
117
121
  def write_subscription(query, events)
118
122
  channel = query.context.fetch(:channel)
119
123
  subscription_id = query.context[:subscription_id] ||= build_id
120
- stream = query.context[:action_cable_stream] ||= SUBSCRIPTION_PREFIX + subscription_id
124
+ stream = stream_subscription_name(subscription_id)
121
125
  channel.stream_from(stream)
122
126
  @subscriptions[subscription_id] = query
123
127
  events.each do |event|
@@ -141,7 +145,7 @@ module GraphQL
141
145
  #
142
146
  def setup_stream(channel, initial_event)
143
147
  topic = initial_event.topic
144
- channel.stream_from(EVENT_PREFIX + topic, coder: ActiveSupport::JSON) do |message|
148
+ channel.stream_from(stream_event_name(initial_event), coder: @action_cable_coder) do |message|
145
149
  object = @serializer.load(message)
146
150
  events_by_fingerprint = @events[topic]
147
151
  events_by_fingerprint.each do |_fingerprint, events|
@@ -197,6 +201,16 @@ module GraphQL
197
201
  end
198
202
  end
199
203
  end
204
+
205
+ private
206
+
207
+ def stream_subscription_name(subscription_id)
208
+ [SUBSCRIPTION_PREFIX, @transmit_ns, subscription_id].join
209
+ end
210
+
211
+ def stream_event_name(event)
212
+ [EVENT_PREFIX, @transmit_ns, event.topic].join
213
+ end
200
214
  end
201
215
  end
202
216
  end
@@ -42,8 +42,8 @@ module GraphQL
42
42
  # execute_multiplex | `{ multiplex: GraphQL::Execution::Multiplex }`
43
43
  # execute_query | `{ query: GraphQL::Query }`
44
44
  # execute_query_lazy | `{ query: GraphQL::Query?, multiplex: GraphQL::Execution::Multiplex? }`
45
- # execute_field | `{ context: GraphQL::Query::Context::FieldResolutionContext?, owner: Class?, field: GraphQL::Schema::Field?, query: GraphQL::Query?, path: Array<String, Integer>?}`
46
- # execute_field_lazy | `{ context: GraphQL::Query::Context::FieldResolutionContext?, owner: Class?, field: GraphQL::Schema::Field?, query: GraphQL::Query?, path: Array<String, Integer>?}`
45
+ # execute_field | `{ owner: Class, field: GraphQL::Schema::Field, query: GraphQL::Query, path: Array<String, Integer>, ast_node: GraphQL::Language::Nodes::Field}`
46
+ # execute_field_lazy | `{ owner: Class, field: GraphQL::Schema::Field, query: GraphQL::Query, path: Array<String, Integer>, ast_node: GraphQL::Language::Nodes::Field}`
47
47
  # authorized | `{ context: GraphQL::Query::Context, type: Class, object: Object, path: Array<String, Integer> }`
48
48
  # authorized_lazy | `{ context: GraphQL::Query::Context, type: Class, object: Object, path: Array<String, Integer> }`
49
49
  # resolve_type | `{ context: GraphQL::Query::Context, type: Class, object: Object, path: Array<String, Integer> }`
@@ -55,7 +55,15 @@ module GraphQL
55
55
  end
56
56
 
57
57
  def platform_field_key(type, field)
58
- "graphql.#{type.name}.#{field.name}"
58
+ "graphql.#{type.graphql_name}.#{field.graphql_name}"
59
+ end
60
+
61
+ def platform_authorized_key(type)
62
+ "graphql.authorized.#{type.graphql_name}"
63
+ end
64
+
65
+ def platform_resolve_type_key(type)
66
+ "graphql.resolve_type.#{type.graphql_name}"
59
67
  end
60
68
 
61
69
  private
@@ -104,10 +112,12 @@ module GraphQL
104
112
  graphql_query_string(data[key])
105
113
  when :multiplex
106
114
  graphql_multiplex(data[key])
115
+ when :path
116
+ [key, data[key].join(".")]
107
117
  else
108
118
  [key, data[key]]
109
119
  end
110
- end.flatten.each_slice(2).to_h.merge(Spec: 'graphql')
120
+ end.flatten(2).each_slice(2).to_h.merge(Spec: 'graphql')
111
121
  end
112
122
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
113
123
 
@@ -95,8 +95,10 @@ module GraphQL
95
95
  end
96
96
 
97
97
  def self.use(schema_defn, options = {})
98
- tracer = self.new(options)
99
- schema_defn.instrument(:field, tracer)
98
+ tracer = self.new(**options)
99
+ if !schema_defn.is_a?(Class)
100
+ schema_defn.instrument(:field, tracer)
101
+ end
100
102
  schema_defn.tracer(tracer)
101
103
  end
102
104
 
@@ -16,7 +16,10 @@ module GraphQL
16
16
  end
17
17
 
18
18
  def collect(object)
19
- labels = { key: object['key'], platform_key: object['platform_key'] }
19
+ default_labels = { key: object['key'], platform_key: object['platform_key'] }
20
+ custom = object['custom_labels']
21
+ labels = custom.nil? ? default_labels : default_labels.merge(custom)
22
+
20
23
  @graphql_gauge.observe object['duration'], labels
21
24
  end
22
25
 
@@ -18,7 +18,7 @@ module GraphQL
18
18
  # This is not advised if you run more than one query per HTTP request, for example, with `graphql-client` or multiplexing.
19
19
  # It can also be specified per-query with `context[:set_skylight_endpoint_name]`.
20
20
  def initialize(options = {})
21
- warn("GraphQL::Tracing::SkylightTracing is deprecated, please enable Skylight's GraphQL probe instead: https://www.skylight.io/support/getting-more-from-skylight#graphql.")
21
+ warn("GraphQL::Tracing::SkylightTracing is deprecated and will be removed in GraphQL-Ruby 2.0, please enable Skylight's GraphQL probe instead: https://www.skylight.io/support/getting-more-from-skylight#graphql.")
22
22
  @set_endpoint_name = options.fetch(:set_endpoint_name, false)
23
23
  super
24
24
  end
@@ -9,8 +9,15 @@ module GraphQL
9
9
  MIN = -(2**31)
10
10
  MAX = (2**31) - 1
11
11
 
12
- def self.coerce_input(value, _ctx)
13
- value.is_a?(Integer) ? value : nil
12
+ def self.coerce_input(value, ctx)
13
+ return if !value.is_a?(Integer)
14
+
15
+ if value >= MIN && value <= MAX
16
+ value
17
+ else
18
+ err = GraphQL::IntegerDecodingError.new(value)
19
+ ctx.schema.type_error(err, ctx)
20
+ end
14
21
  end
15
22
 
16
23
  def self.coerce_result(value, ctx)
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'time'
2
4
 
3
- # frozen_string_literal: true
4
5
  module GraphQL
5
6
  module Types
6
7
  # This scalar takes `Time`s and transmits them as strings,
@@ -1,7 +1,15 @@
1
1
  # frozen_string_literal: true
2
- require "graphql/types/relay/base_field"
3
- require "graphql/types/relay/base_object"
4
- require "graphql/types/relay/base_interface"
2
+
3
+ # behavior modules:
4
+ require "graphql/types/relay/default_relay"
5
+ require "graphql/types/relay/connection_behaviors"
6
+ require "graphql/types/relay/edge_behaviors"
7
+ require "graphql/types/relay/node_behaviors"
8
+ require "graphql/types/relay/page_info_behaviors"
9
+ require "graphql/types/relay/has_node_field"
10
+ require "graphql/types/relay/has_nodes_field"
11
+
12
+ # concrete classes based on the gem defaults:
5
13
  require "graphql/types/relay/page_info"
6
14
  require "graphql/types/relay/base_connection"
7
15
  require "graphql/types/relay/base_edge"
@@ -27,96 +27,8 @@ module GraphQL
27
27
  # end
28
28
  #
29
29
  # @see Relay::BaseEdge for edge types
30
- class BaseConnection < Types::Relay::BaseObject
31
- extend Forwardable
32
- def_delegators :@object, :cursor_from_node, :parent
33
-
34
- class << self
35
- # @return [Class]
36
- attr_reader :node_type
37
-
38
- # @return [Class]
39
- attr_reader :edge_class
40
-
41
- # Configure this connection to return `edges` and `nodes` based on `edge_type_class`.
42
- #
43
- # This method will use the inputs to create:
44
- # - `edges` field
45
- # - `nodes` field
46
- # - description
47
- #
48
- # It's called when you subclass this base connection, trying to use the
49
- # class name to set defaults. You can call it again in the class definition
50
- # to override the default (or provide a value, if the default lookup failed).
51
- def edge_type(edge_type_class, edge_class: GraphQL::Relay::Edge, node_type: edge_type_class.node_type, nodes_field: true)
52
- # Set this connection's graphql name
53
- node_type_name = node_type.graphql_name
54
-
55
- @node_type = node_type
56
- @edge_type = edge_type_class
57
- @edge_class = edge_class
58
-
59
- field :edges, [edge_type_class, null: true],
60
- null: true,
61
- description: "A list of edges.",
62
- edge_class: edge_class
63
-
64
- define_nodes_field if nodes_field
65
-
66
- description("The connection type for #{node_type_name}.")
67
- end
68
-
69
- # Filter this list according to the way its node type would scope them
70
- def scope_items(items, context)
71
- node_type.scope_items(items, context)
72
- end
73
-
74
- # Add the shortcut `nodes` field to this connection and its subclasses
75
- def nodes_field
76
- define_nodes_field
77
- end
78
-
79
- def authorized?(obj, ctx)
80
- true # Let nodes be filtered out
81
- end
82
-
83
- def accessible?(ctx)
84
- node_type.accessible?(ctx)
85
- end
86
-
87
- def visible?(ctx)
88
- node_type.visible?(ctx)
89
- end
90
-
91
- private
92
-
93
- def define_nodes_field
94
- field :nodes, [@node_type, null: true],
95
- null: true,
96
- description: "A list of nodes."
97
- end
98
- end
99
-
100
- field :page_info, GraphQL::Types::Relay::PageInfo, null: false, description: "Information to aid in pagination."
101
-
102
- # By default this calls through to the ConnectionWrapper's edge nodes method,
103
- # but sometimes you need to override it to support the `nodes` field
104
- def nodes
105
- @object.edge_nodes
106
- end
107
-
108
- def edges
109
- if @object.is_a?(GraphQL::Pagination::Connection)
110
- @object.edges
111
- elsif context.interpreter?
112
- context.schema.after_lazy(object.edge_nodes) do |nodes|
113
- nodes.map { |n| self.class.edge_class.new(n, object) }
114
- end
115
- else
116
- # This is done by edges_instrumentation
117
- @object.edge_nodes
118
- end
119
- end
30
+ class BaseConnection < Schema::Object
31
+ include ConnectionBehaviors
120
32
  end
121
33
  end
122
34
  end