graphql 2.0.15 → 2.0.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql/query/context.rb +28 -16
- data/lib/graphql/rake_task.rb +28 -1
- data/lib/graphql/schema/union.rb +10 -1
- data/lib/graphql/schema.rb +15 -2
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +7 -1
- data/lib/graphql/subscriptions.rb +5 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +4 -0
- data/lib/graphql/types/relay/default_relay.rb +7 -1
- data/lib/graphql/types/relay/edge_behaviors.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- metadata +3 -4
- data/lib/graphql/tracing/instrumentation_tracing.rb +0 -83
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d626d72a5ae0bfb10f8fcdb9cbd781f04b5bb38b3f90b20de062a78679c254a8
|
4
|
+
data.tar.gz: 6793ba627f3f59a43426258e187567f391a44f8973816fb0b1e1eb7784ae19b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5958721b08e45d886036f8afe0a5942e443117d9aa71d94450b727ec20d13b63a945a97c247f8605d4eb1ae8631ba301599e95b938355f18dc7c5bf64e2b1b44
|
7
|
+
data.tar.gz: 9d029e7d0288c87cc9c09e627538b5e93b3d1ec7e785914b135088ec7bafcf8172458fa1d68a95a6385786d472c7260f6bc82b719e86743b5dac1f2a87501f7c
|
@@ -93,7 +93,7 @@ module GraphQL
|
|
93
93
|
class ScopedContext
|
94
94
|
def initialize(query_context)
|
95
95
|
@query_context = query_context
|
96
|
-
@
|
96
|
+
@scoped_contexts = {}
|
97
97
|
@no_path = [].freeze
|
98
98
|
end
|
99
99
|
|
@@ -106,12 +106,17 @@ module GraphQL
|
|
106
106
|
end
|
107
107
|
|
108
108
|
def merge!(hash)
|
109
|
-
|
110
|
-
|
109
|
+
ctx = @scoped_contexts
|
110
|
+
current_path.each do |path_part|
|
111
|
+
ctx = ctx[path_part] ||= { parent: ctx }
|
112
|
+
end
|
113
|
+
this_scoped_ctx = ctx[:scoped_context] ||= {}
|
114
|
+
this_scoped_ctx.merge!(hash)
|
111
115
|
end
|
112
116
|
|
113
117
|
def current_path
|
114
|
-
|
118
|
+
thread_info = Thread.current[:__graphql_runtime_info]
|
119
|
+
(thread_info && thread_info[:current_path]) || @no_path
|
115
120
|
end
|
116
121
|
|
117
122
|
def key?(key)
|
@@ -151,16 +156,20 @@ module GraphQL
|
|
151
156
|
# Start at the current location,
|
152
157
|
# but look up the tree for previously-assigned scoped values
|
153
158
|
def each_present_path_ctx
|
154
|
-
|
155
|
-
|
156
|
-
|
159
|
+
ctx = @scoped_contexts
|
160
|
+
current_path.each do |path_part|
|
161
|
+
if ctx.key?(path_part)
|
162
|
+
ctx = ctx[path_part]
|
163
|
+
else
|
164
|
+
break
|
165
|
+
end
|
157
166
|
end
|
158
167
|
|
159
|
-
while
|
160
|
-
|
161
|
-
|
162
|
-
yield(search_path_ctx)
|
168
|
+
while ctx
|
169
|
+
if (scoped_ctx = ctx[:scoped_context])
|
170
|
+
yield(scoped_ctx)
|
163
171
|
end
|
172
|
+
ctx = ctx[:parent]
|
164
173
|
end
|
165
174
|
end
|
166
175
|
end
|
@@ -195,13 +204,16 @@ module GraphQL
|
|
195
204
|
|
196
205
|
# Lookup `key` from the hash passed to {Schema#execute} as `context:`
|
197
206
|
def [](key)
|
198
|
-
if
|
207
|
+
if @scoped_context.key?(key)
|
208
|
+
@scoped_context[key]
|
209
|
+
elsif @provided_values.key?(key)
|
210
|
+
@provided_values[key]
|
211
|
+
elsif RUNTIME_METADATA_KEYS.include?(key)
|
199
212
|
thread_info = Thread.current[:__graphql_runtime_info]
|
200
213
|
thread_info && thread_info[key]
|
201
|
-
elsif @scoped_context.key?(key)
|
202
|
-
@scoped_context[key]
|
203
214
|
else
|
204
|
-
|
215
|
+
# not found
|
216
|
+
nil
|
205
217
|
end
|
206
218
|
end
|
207
219
|
|
@@ -235,7 +247,7 @@ module GraphQL
|
|
235
247
|
def dig(key, *other_keys)
|
236
248
|
if RUNTIME_METADATA_KEYS.include?(key)
|
237
249
|
(thread_info = Thread.current[:__graphql_runtime_info]).key?(key) &&
|
238
|
-
thread_info.dig(key)
|
250
|
+
thread_info.dig(key, *other_keys)
|
239
251
|
elsif @scoped_context.key?(key)
|
240
252
|
@scoped_context.dig(key, *other_keys)
|
241
253
|
else
|
data/lib/graphql/rake_task.rb
CHANGED
@@ -23,6 +23,10 @@ module GraphQL
|
|
23
23
|
# @example Invoking the task from Ruby
|
24
24
|
# require "rake"
|
25
25
|
# Rake::Task["graphql:schema:dump"].invoke
|
26
|
+
#
|
27
|
+
# @example Providing arguments to build the introspection query
|
28
|
+
# require "graphql/rake_task"
|
29
|
+
# GraphQL::RakeTask.new(schema_name: "MySchema", include_is_one_of: true)
|
26
30
|
class RakeTask
|
27
31
|
include Rake::DSL
|
28
32
|
|
@@ -37,6 +41,11 @@ module GraphQL
|
|
37
41
|
directory: ".",
|
38
42
|
idl_outfile: "schema.graphql",
|
39
43
|
json_outfile: "schema.json",
|
44
|
+
include_deprecated_args: true,
|
45
|
+
include_schema_description: false,
|
46
|
+
include_is_repeatable: false,
|
47
|
+
include_specified_by_url: false,
|
48
|
+
include_is_one_of: false
|
40
49
|
}
|
41
50
|
|
42
51
|
# @return [String] Namespace for generated tasks
|
@@ -74,6 +83,10 @@ module GraphQL
|
|
74
83
|
# @return [String] directory for IDL & JSON files
|
75
84
|
attr_accessor :directory
|
76
85
|
|
86
|
+
# @return [Boolean] Options for additional fields in the introspection query JSON response
|
87
|
+
# @see GraphQL::Schema.as_json
|
88
|
+
attr_accessor :include_deprecated_args, :include_schema_description, :include_is_repeatable, :include_specified_by_url, :include_is_one_of
|
89
|
+
|
77
90
|
# Set the parameters of this task by passing keyword arguments
|
78
91
|
# or assigning attributes inside the block
|
79
92
|
def initialize(options = {})
|
@@ -96,7 +109,21 @@ module GraphQL
|
|
96
109
|
def write_outfile(method_name, file)
|
97
110
|
schema = @load_schema.call(self)
|
98
111
|
context = @load_context.call(self)
|
99
|
-
result =
|
112
|
+
result = case method_name
|
113
|
+
when :to_json
|
114
|
+
schema.to_json(
|
115
|
+
include_is_one_of: include_is_one_of,
|
116
|
+
include_deprecated_args: include_deprecated_args,
|
117
|
+
include_is_repeatable: include_is_repeatable,
|
118
|
+
include_specified_by_url: include_specified_by_url,
|
119
|
+
include_schema_description: include_schema_description,
|
120
|
+
only: @only, except: @except, context: context
|
121
|
+
)
|
122
|
+
when :to_definition
|
123
|
+
schema.to_definition(only: @only, except: @except, context: context)
|
124
|
+
else
|
125
|
+
raise ArgumentError, "Unexpected schema dump method: #{method_name.inspect}"
|
126
|
+
end
|
100
127
|
dir = File.dirname(file)
|
101
128
|
FileUtils.mkdir_p(dir)
|
102
129
|
if !result.end_with?("\n")
|
data/lib/graphql/schema/union.rb
CHANGED
@@ -70,9 +70,18 @@ module GraphQL
|
|
70
70
|
private
|
71
71
|
|
72
72
|
def assert_valid_union_member(type_defn)
|
73
|
-
|
73
|
+
case type_defn
|
74
|
+
when Class
|
75
|
+
if !type_defn.kind.object?
|
76
|
+
raise ArgumentError, "Union possible_types can only be object types (not #{type_defn.kind.name}, #{type_defn.inspect})"
|
77
|
+
end
|
78
|
+
when Module
|
74
79
|
# it's an interface type, defined as a module
|
75
80
|
raise ArgumentError, "Union possible_types can only be object types (not interface types), remove #{type_defn.graphql_name} (#{type_defn.inspect})"
|
81
|
+
when String, GraphQL::Schema::LateBoundType
|
82
|
+
# Ok - assume it will get checked later
|
83
|
+
else
|
84
|
+
raise ArgumentError, "Union possible_types can only be class-based GraphQL types (not #{type_defn.inspect} (#{type_defn.class.name}))."
|
76
85
|
end
|
77
86
|
end
|
78
87
|
end
|
data/lib/graphql/schema.rb
CHANGED
@@ -154,9 +154,22 @@ module GraphQL
|
|
154
154
|
# @param context [Hash]
|
155
155
|
# @param only [<#call(member, ctx)>]
|
156
156
|
# @param except [<#call(member, ctx)>]
|
157
|
+
# @param include_deprecated_args [Boolean] If true, deprecated arguments will be included in the JSON response
|
158
|
+
# @param include_schema_description [Boolean] If true, the schema's description will be queried and included in the response
|
159
|
+
# @param include_is_repeatable [Boolean] If true, `isRepeatable: true|false` will be included with the schema's directives
|
160
|
+
# @param include_specified_by_url [Boolean] If true, scalar types' `specifiedByUrl:` will be included in the response
|
161
|
+
# @param include_is_one_of [Boolean] If true, `isOneOf: true|false` will be included with input objects
|
157
162
|
# @return [Hash] GraphQL result
|
158
|
-
def as_json(only: nil, except: nil, context: {})
|
159
|
-
|
163
|
+
def as_json(only: nil, except: nil, context: {}, include_deprecated_args: true, include_schema_description: false, include_is_repeatable: false, include_specified_by_url: false, include_is_one_of: false)
|
164
|
+
introspection_query = Introspection.query(
|
165
|
+
include_deprecated_args: include_deprecated_args,
|
166
|
+
include_schema_description: include_schema_description,
|
167
|
+
include_is_repeatable: include_is_repeatable,
|
168
|
+
include_is_one_of: include_is_one_of,
|
169
|
+
include_specified_by_url: include_specified_by_url,
|
170
|
+
)
|
171
|
+
|
172
|
+
execute(introspection_query, only: only, except: except, context: context).to_h
|
160
173
|
end
|
161
174
|
|
162
175
|
# Return the GraphQL IDL for the schema
|
@@ -127,8 +127,14 @@ module GraphQL
|
|
127
127
|
# same name as if they were the same name. If _any_ of the fragments
|
128
128
|
# with that name has a dependency, we record it.
|
129
129
|
independent_fragment_nodes = @defdep_fragment_definitions.values.flatten - @defdep_immediate_dependencies.keys
|
130
|
-
|
130
|
+
visited_fragment_names = Set.new
|
131
131
|
while fragment_node = independent_fragment_nodes.pop
|
132
|
+
if visited_fragment_names.add?(fragment_node.name)
|
133
|
+
# this is a new fragment name
|
134
|
+
else
|
135
|
+
# this is a duplicate fragment name
|
136
|
+
next
|
137
|
+
end
|
132
138
|
loops += 1
|
133
139
|
if loops > max_loops
|
134
140
|
raise("Resolution loops exceeded the number of definitions; infinite loop detected. (Max: #{max_loops}, Current: #{loops})")
|
@@ -91,7 +91,13 @@ module GraphQL
|
|
91
91
|
# A per-process map of subscriptions to deliver.
|
92
92
|
# This is provided by Rails, so let's use it
|
93
93
|
@subscriptions = Concurrent::Map.new
|
94
|
-
@events = Concurrent::Map.new
|
94
|
+
@events = Concurrent::Map.new do |h, k|
|
95
|
+
h.compute_if_absent(k) do
|
96
|
+
Concurrent::Map.new do |h2, k2|
|
97
|
+
h2.compute_if_absent(k2) { Concurrent::Array.new }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
95
101
|
@action_cable = action_cable
|
96
102
|
@action_cable_coder = action_cable_coder
|
97
103
|
@serializer = serializer
|
@@ -90,6 +90,7 @@ module GraphQL
|
|
90
90
|
arguments: normalized_args,
|
91
91
|
field: field,
|
92
92
|
scope: scope,
|
93
|
+
context: context,
|
93
94
|
)
|
94
95
|
execute_all(event, object)
|
95
96
|
end
|
@@ -124,6 +125,10 @@ module GraphQL
|
|
124
125
|
variables: variables,
|
125
126
|
root_value: object,
|
126
127
|
}
|
128
|
+
|
129
|
+
# merge event's and query's context together
|
130
|
+
context.merge!(event.context) unless event.context.nil? || context.nil?
|
131
|
+
|
127
132
|
execute_options[:validate] = validate_update?(**execute_options)
|
128
133
|
result = @schema.execute(**execute_options)
|
129
134
|
subscriptions_context = result.context.namespace(:subscriptions)
|
@@ -50,6 +50,8 @@ module GraphQL
|
|
50
50
|
null: edges_nullable,
|
51
51
|
description: "A list of edges.",
|
52
52
|
connection: false,
|
53
|
+
# Assume that the connection was scoped before this step:
|
54
|
+
scope: false,
|
53
55
|
}
|
54
56
|
|
55
57
|
if field_options
|
@@ -135,6 +137,8 @@ module GraphQL
|
|
135
137
|
null: nullable,
|
136
138
|
description: "A list of nodes.",
|
137
139
|
connection: false,
|
140
|
+
# Assume that the connection was scoped before this step:
|
141
|
+
scope: false,
|
138
142
|
}
|
139
143
|
if field_options
|
140
144
|
base_field_options.merge!(field_options)
|
@@ -13,7 +13,13 @@ module GraphQL
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def default_relay?
|
16
|
-
|
16
|
+
if defined?(@default_relay)
|
17
|
+
@default_relay
|
18
|
+
elsif self.is_a?(Class)
|
19
|
+
superclass.respond_to?(:default_relay?) && superclass.default_relay?
|
20
|
+
else
|
21
|
+
false
|
22
|
+
end
|
17
23
|
end
|
18
24
|
end
|
19
25
|
end
|
@@ -8,6 +8,7 @@ module GraphQL
|
|
8
8
|
child_class.description("An edge in a connection.")
|
9
9
|
child_class.field(:cursor, String, null: false, description: "A cursor for use in pagination.")
|
10
10
|
child_class.extend(ClassMethods)
|
11
|
+
child_class.extend(GraphQL::Types::Relay::DefaultRelay)
|
11
12
|
child_class.node_nullable(true)
|
12
13
|
end
|
13
14
|
|
data/lib/graphql/version.rb
CHANGED
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: 2.0.
|
4
|
+
version: 2.0.16
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|
@@ -538,7 +538,6 @@ files:
|
|
538
538
|
- lib/graphql/tracing/appoptics_tracing.rb
|
539
539
|
- lib/graphql/tracing/appsignal_tracing.rb
|
540
540
|
- lib/graphql/tracing/data_dog_tracing.rb
|
541
|
-
- lib/graphql/tracing/instrumentation_tracing.rb
|
542
541
|
- lib/graphql/tracing/new_relic_tracing.rb
|
543
542
|
- lib/graphql/tracing/notifications_tracing.rb
|
544
543
|
- lib/graphql/tracing/platform_tracing.rb
|
@@ -598,7 +597,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
598
597
|
- !ruby/object:Gem::Version
|
599
598
|
version: '0'
|
600
599
|
requirements: []
|
601
|
-
rubygems_version: 3.
|
600
|
+
rubygems_version: 3.3.3
|
602
601
|
signing_key:
|
603
602
|
specification_version: 4
|
604
603
|
summary: A GraphQL language and runtime for Ruby
|
@@ -1,83 +0,0 @@
|
|
1
|
-
module GraphQL
|
2
|
-
module Tracing
|
3
|
-
class InstrumentationTracing
|
4
|
-
def initialize(schema)
|
5
|
-
@schema = schema
|
6
|
-
end
|
7
|
-
|
8
|
-
def trace(event, data)
|
9
|
-
instrumenters = nil
|
10
|
-
query_instrumenters = nil
|
11
|
-
case event
|
12
|
-
when "execute_multiplex"
|
13
|
-
instrumenters = @schema.instrumenters
|
14
|
-
multiplex_instrumenters = instrumenters[:multiplex]
|
15
|
-
query_instrumenters = instrumenters[:query]
|
16
|
-
call_hooks(multiplex_instrumenters, data[:multiplex], :before_multiplex, :after_multiplex) {
|
17
|
-
each_query_call_hooks(query_instrumenters, data[:multiplex].queries) {
|
18
|
-
yield
|
19
|
-
}
|
20
|
-
}
|
21
|
-
else
|
22
|
-
yield
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
# Call the before_ hooks of each query,
|
29
|
-
# Then yield if no errors.
|
30
|
-
# `call_hooks` takes care of appropriate cleanup.
|
31
|
-
def each_query_call_hooks(instrumenters, queries, i = 0)
|
32
|
-
if i >= queries.length
|
33
|
-
yield
|
34
|
-
else
|
35
|
-
query = queries[i]
|
36
|
-
call_hooks(instrumenters, query, :before_query, :after_query) {
|
37
|
-
each_query_call_hooks(instrumenters, queries, i + 1) {
|
38
|
-
yield
|
39
|
-
}
|
40
|
-
}
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
# Call each before hook, and if they all succeed, yield.
|
45
|
-
# If they don't all succeed, call after_ for each one that succeeded.
|
46
|
-
def call_hooks(instrumenters, object, before_hook_name, after_hook_name)
|
47
|
-
begin
|
48
|
-
successful = []
|
49
|
-
instrumenters.each do |instrumenter|
|
50
|
-
instrumenter.public_send(before_hook_name, object)
|
51
|
-
successful << instrumenter
|
52
|
-
end
|
53
|
-
|
54
|
-
# if any before hooks raise an exception, quit calling before hooks,
|
55
|
-
# but call the after hooks on anything that succeeded but also
|
56
|
-
# raise the exception that came from the before hook.
|
57
|
-
rescue GraphQL::ExecutionError => err
|
58
|
-
object.context.errors << err
|
59
|
-
rescue => e
|
60
|
-
raise call_after_hooks(successful, object, after_hook_name, e)
|
61
|
-
end
|
62
|
-
|
63
|
-
begin
|
64
|
-
yield # Call the user code
|
65
|
-
ensure
|
66
|
-
ex = call_after_hooks(successful, object, after_hook_name, nil)
|
67
|
-
raise ex if ex
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def call_after_hooks(instrumenters, object, after_hook_name, ex)
|
72
|
-
instrumenters.reverse_each do |instrumenter|
|
73
|
-
begin
|
74
|
-
instrumenter.public_send(after_hook_name, object)
|
75
|
-
rescue => e
|
76
|
-
ex = e
|
77
|
-
end
|
78
|
-
end
|
79
|
-
ex
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|