graphql 2.0.15 → 2.0.16
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.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- 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
|