graphql 2.0.27 → 2.2.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +3 -0
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +2 -0
- data/lib/generators/graphql/templates/base_edge.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_resolver.erb +6 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/node_type.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +2 -0
- data/lib/graphql/analysis/ast/analyzer.rb +7 -0
- data/lib/graphql/analysis/ast/field_usage.rb +32 -7
- data/lib/graphql/analysis/ast/query_complexity.rb +80 -128
- data/lib/graphql/analysis/ast/query_depth.rb +7 -2
- data/lib/graphql/analysis/ast/visitor.rb +2 -2
- data/lib/graphql/analysis/ast.rb +21 -11
- data/lib/graphql/backtrace/trace.rb +12 -15
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/dataloader/async_dataloader.rb +85 -0
- data/lib/graphql/dataloader/source.rb +11 -3
- data/lib/graphql/dataloader.rb +109 -142
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +170 -0
- data/lib/graphql/execution/interpreter/runtime.rb +70 -248
- data/lib/graphql/execution/interpreter.rb +91 -157
- data/lib/graphql/execution/lookahead.rb +88 -21
- data/lib/graphql/introspection/dynamic_fields.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +11 -5
- data/lib/graphql/introspection/schema_type.rb +3 -1
- data/lib/graphql/language/block_string.rb +34 -18
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +37 -37
- data/lib/graphql/language/lexer.rb +271 -177
- data/lib/graphql/language/nodes.rb +74 -56
- data/lib/graphql/language/parser.rb +697 -1986
- data/lib/graphql/language/printer.rb +299 -146
- data/lib/graphql/language/sanitized_printer.rb +20 -22
- data/lib/graphql/language/static_visitor.rb +167 -0
- data/lib/graphql/language/visitor.rb +20 -81
- data/lib/graphql/language.rb +1 -0
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/array_connection.rb +3 -3
- data/lib/graphql/pagination/connection.rb +28 -1
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/pagination/relation_connection.rb +3 -3
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +36 -98
- data/lib/graphql/query/null_context.rb +4 -11
- data/lib/graphql/query/validation_pipeline.rb +2 -2
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +13 -22
- data/lib/graphql/railtie.rb +9 -6
- data/lib/graphql/rake_task.rb +3 -12
- data/lib/graphql/schema/argument.rb +6 -1
- data/lib/graphql/schema/build_from_definition.rb +0 -11
- data/lib/graphql/schema/directive/one_of.rb +12 -0
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive.rb +1 -1
- data/lib/graphql/schema/enum.rb +3 -3
- data/lib/graphql/schema/field/connection_extension.rb +1 -15
- data/lib/graphql/schema/field/scope_extension.rb +8 -1
- data/lib/graphql/schema/field.rb +8 -5
- data/lib/graphql/schema/has_single_input_argument.rb +156 -0
- data/lib/graphql/schema/input_object.rb +2 -2
- data/lib/graphql/schema/interface.rb +10 -10
- data/lib/graphql/schema/introspection_system.rb +2 -0
- data/lib/graphql/schema/loader.rb +0 -2
- data/lib/graphql/schema/member/base_dsl_methods.rb +2 -1
- data/lib/graphql/schema/member/has_arguments.rb +61 -38
- data/lib/graphql/schema/member/has_fields.rb +8 -5
- data/lib/graphql/schema/member/has_interfaces.rb +23 -9
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/object.rb +8 -0
- data/lib/graphql/schema/printer.rb +8 -7
- data/lib/graphql/schema/relay_classic_mutation.rb +6 -128
- data/lib/graphql/schema/resolver.rb +7 -3
- data/lib/graphql/schema/scalar.rb +3 -3
- data/lib/graphql/schema/subscription.rb +11 -4
- data/lib/graphql/schema/union.rb +1 -1
- data/lib/graphql/schema/warden.rb +96 -94
- data/lib/graphql/schema.rb +219 -72
- data/lib/graphql/static_validation/all_rules.rb +1 -1
- data/lib/graphql/static_validation/base_visitor.rb +1 -1
- data/lib/graphql/static_validation/literal_validator.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +1 -1
- data/lib/graphql/static_validation/validation_context.rb +5 -5
- data/lib/graphql/static_validation/validator.rb +3 -0
- data/lib/graphql/static_validation.rb +0 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +3 -2
- data/lib/graphql/subscriptions/event.rb +8 -2
- data/lib/graphql/subscriptions.rb +14 -12
- data/lib/graphql/testing/helpers.rb +125 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/appoptics_trace.rb +2 -2
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
- data/lib/graphql/tracing/data_dog_trace.rb +21 -34
- data/lib/graphql/tracing/data_dog_tracing.rb +7 -21
- data/lib/graphql/tracing/legacy_hooks_trace.rb +74 -0
- data/lib/graphql/tracing/platform_tracing.rb +2 -0
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +3 -1
- data/lib/graphql/tracing/sentry_trace.rb +94 -0
- data/lib/graphql/tracing/trace.rb +1 -0
- data/lib/graphql/tracing.rb +3 -1
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/connection_behaviors.rb +32 -2
- data/lib/graphql/types/relay/edge_behaviors.rb +7 -0
- data/lib/graphql/types.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +3 -3
- data/readme.md +12 -2
- metadata +33 -25
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/filter.rb +0 -59
- data/lib/graphql/language/parser.y +0 -560
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
@@ -1,4 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require "graphql/query/context/scoped_context"
|
3
|
+
|
2
4
|
module GraphQL
|
3
5
|
class Query
|
4
6
|
# Expose some query-specific info to field resolve functions.
|
@@ -90,104 +92,6 @@ module GraphQL
|
|
90
92
|
@scoped_context = ScopedContext.new(self)
|
91
93
|
end
|
92
94
|
|
93
|
-
class ScopedContext
|
94
|
-
NO_PATH = GraphQL::EmptyObjects::EMPTY_ARRAY
|
95
|
-
NO_CONTEXT = GraphQL::EmptyObjects::EMPTY_HASH
|
96
|
-
|
97
|
-
def initialize(query_context)
|
98
|
-
@query_context = query_context
|
99
|
-
@scoped_contexts = nil
|
100
|
-
@all_keys = nil
|
101
|
-
end
|
102
|
-
|
103
|
-
def merged_context
|
104
|
-
if @scoped_contexts.nil?
|
105
|
-
NO_CONTEXT
|
106
|
-
else
|
107
|
-
merged_ctx = {}
|
108
|
-
each_present_path_ctx do |path_ctx|
|
109
|
-
merged_ctx = path_ctx.merge(merged_ctx)
|
110
|
-
end
|
111
|
-
merged_ctx
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def merge!(hash)
|
116
|
-
@all_keys ||= Set.new
|
117
|
-
@all_keys.merge(hash.keys)
|
118
|
-
ctx = @scoped_contexts ||= {}
|
119
|
-
current_path.each do |path_part|
|
120
|
-
ctx = ctx[path_part] ||= { parent: ctx }
|
121
|
-
end
|
122
|
-
this_scoped_ctx = ctx[:scoped_context] ||= {}
|
123
|
-
this_scoped_ctx.merge!(hash)
|
124
|
-
end
|
125
|
-
|
126
|
-
def key?(key)
|
127
|
-
if @all_keys && @all_keys.include?(key)
|
128
|
-
each_present_path_ctx do |path_ctx|
|
129
|
-
if path_ctx.key?(key)
|
130
|
-
return true
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
false
|
135
|
-
end
|
136
|
-
|
137
|
-
def [](key)
|
138
|
-
each_present_path_ctx do |path_ctx|
|
139
|
-
if path_ctx.key?(key)
|
140
|
-
return path_ctx[key]
|
141
|
-
end
|
142
|
-
end
|
143
|
-
nil
|
144
|
-
end
|
145
|
-
|
146
|
-
def current_path
|
147
|
-
@query_context.current_path || NO_PATH
|
148
|
-
end
|
149
|
-
|
150
|
-
def dig(key, *other_keys)
|
151
|
-
each_present_path_ctx do |path_ctx|
|
152
|
-
if path_ctx.key?(key)
|
153
|
-
found_value = path_ctx[key]
|
154
|
-
if other_keys.any?
|
155
|
-
return found_value.dig(*other_keys)
|
156
|
-
else
|
157
|
-
return found_value
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
|
-
nil
|
162
|
-
end
|
163
|
-
|
164
|
-
private
|
165
|
-
|
166
|
-
# Start at the current location,
|
167
|
-
# but look up the tree for previously-assigned scoped values
|
168
|
-
def each_present_path_ctx
|
169
|
-
ctx = @scoped_contexts
|
170
|
-
if ctx.nil?
|
171
|
-
# no-op
|
172
|
-
else
|
173
|
-
current_path.each do |path_part|
|
174
|
-
if ctx.key?(path_part)
|
175
|
-
ctx = ctx[path_part]
|
176
|
-
else
|
177
|
-
break
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
while ctx
|
182
|
-
if (scoped_ctx = ctx[:scoped_context])
|
183
|
-
yield(scoped_ctx)
|
184
|
-
end
|
185
|
-
ctx = ctx[:parent]
|
186
|
-
end
|
187
|
-
end
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
95
|
# @return [Hash] A hash that will be added verbatim to the result hash, as `"extensions" => { ... }`
|
192
96
|
def response_extensions
|
193
97
|
namespace(:__query_result_extensions__)
|
@@ -333,6 +237,10 @@ module GraphQL
|
|
333
237
|
@storage.key?(ns)
|
334
238
|
end
|
335
239
|
|
240
|
+
def logger
|
241
|
+
@query && @query.logger
|
242
|
+
end
|
243
|
+
|
336
244
|
def inspect
|
337
245
|
"#<Query::Context ...>"
|
338
246
|
end
|
@@ -345,6 +253,36 @@ module GraphQL
|
|
345
253
|
scoped_merge!(key => value)
|
346
254
|
nil
|
347
255
|
end
|
256
|
+
|
257
|
+
# Use this when you need to do a scoped set _inside_ a lazy-loaded (or batch-loaded)
|
258
|
+
# block of code.
|
259
|
+
#
|
260
|
+
# @example using scoped context inside a promise
|
261
|
+
# scoped_ctx = context.scoped
|
262
|
+
# SomeBatchLoader.load(...).then do |thing|
|
263
|
+
# # use a scoped_ctx which was created _before_ dataloading:
|
264
|
+
# scoped_ctx.set!(:thing, thing)
|
265
|
+
# end
|
266
|
+
# @return [Context::Scoped]
|
267
|
+
def scoped
|
268
|
+
Scoped.new(@scoped_context, current_path)
|
269
|
+
end
|
270
|
+
|
271
|
+
class Scoped
|
272
|
+
def initialize(scoped_context, path)
|
273
|
+
@path = path
|
274
|
+
@scoped_context = scoped_context
|
275
|
+
end
|
276
|
+
|
277
|
+
def merge!(hash)
|
278
|
+
@scoped_context.merge!(hash, at: @path)
|
279
|
+
end
|
280
|
+
|
281
|
+
def set!(key, value)
|
282
|
+
@scoped_context.merge!({ key => value }, at: @path)
|
283
|
+
nil
|
284
|
+
end
|
285
|
+
end
|
348
286
|
end
|
349
287
|
end
|
350
288
|
end
|
@@ -1,8 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require "graphql/query/context"
|
2
3
|
module GraphQL
|
3
4
|
class Query
|
4
5
|
# This object can be `ctx` in places where there is no query
|
5
|
-
class NullContext
|
6
|
+
class NullContext < Context
|
7
|
+
include Singleton
|
8
|
+
|
6
9
|
class NullQuery
|
7
10
|
def after_lazy(value)
|
8
11
|
yield(value)
|
@@ -27,16 +30,6 @@ module GraphQL
|
|
27
30
|
def interpreter?
|
28
31
|
true
|
29
32
|
end
|
30
|
-
|
31
|
-
class << self
|
32
|
-
extend Forwardable
|
33
|
-
|
34
|
-
def instance
|
35
|
-
@instance ||= self.new
|
36
|
-
end
|
37
|
-
|
38
|
-
def_delegators :instance, :query, :warden, :schema, :interpreter?, :dataloader, :[], :fetch, :dig, :key?
|
39
|
-
end
|
40
33
|
end
|
41
34
|
end
|
42
35
|
end
|
@@ -14,7 +14,7 @@ module GraphQL
|
|
14
14
|
#
|
15
15
|
# @api private
|
16
16
|
class ValidationPipeline
|
17
|
-
attr_reader :max_depth, :max_complexity
|
17
|
+
attr_reader :max_depth, :max_complexity, :validate_timeout_remaining
|
18
18
|
|
19
19
|
def initialize(query:, parse_error:, operation_name_error:, max_depth:, max_complexity:)
|
20
20
|
@validation_errors = []
|
@@ -71,7 +71,7 @@ module GraphQL
|
|
71
71
|
validator = @query.static_validator || @schema.static_validator
|
72
72
|
validation_result = validator.validate(@query, validate: @query.validate, timeout: @schema.validate_timeout, max_errors: @schema.validate_max_errors)
|
73
73
|
@validation_errors.concat(validation_result[:errors])
|
74
|
-
|
74
|
+
@validate_timeout_remaining = validation_result[:remaining_timeout]
|
75
75
|
if @validation_errors.empty?
|
76
76
|
@validation_errors.concat(@query.variables.errors)
|
77
77
|
end
|
@@ -26,7 +26,7 @@ module GraphQL
|
|
26
26
|
# - Then, fall back to the default value from the query string
|
27
27
|
# If it's still nil, raise an error if it's required.
|
28
28
|
variable_type = schema.type_from_ast(ast_variable.type, context: ctx)
|
29
|
-
if variable_type.nil?
|
29
|
+
if variable_type.nil? || !variable_type.unwrap.kind.input?
|
30
30
|
# Pass -- it will get handled by a validator
|
31
31
|
else
|
32
32
|
variable_name = ast_variable.name
|
@@ -80,12 +80,12 @@ module GraphQL
|
|
80
80
|
else
|
81
81
|
val
|
82
82
|
end
|
83
|
-
end
|
83
|
+
end
|
84
84
|
|
85
85
|
def add_max_errors_reached_message
|
86
86
|
message = "Too many errors processing variables, max validation error limit reached. Execution aborted"
|
87
87
|
validation_result = GraphQL::Query::InputValidationResult.from_problem(message)
|
88
|
-
errors << GraphQL::Query::VariableValidationError.new(nil, nil, nil, validation_result, msg: message)
|
88
|
+
errors << GraphQL::Query::VariableValidationError.new(nil, nil, nil, validation_result, msg: message)
|
89
89
|
end
|
90
90
|
end
|
91
91
|
end
|
data/lib/graphql/query.rb
CHANGED
@@ -95,15 +95,10 @@ module GraphQL
|
|
95
95
|
# @param root_value [Object] the object used to resolve fields on the root type
|
96
96
|
# @param max_depth [Numeric] the maximum number of nested selections allowed for this query (falls back to schema-level value)
|
97
97
|
# @param max_complexity [Numeric] the maximum field complexity for this query (falls back to schema-level value)
|
98
|
-
|
99
|
-
# @param only [<#call(schema_member, context)>] If provided, objects will be hidden from the schema when `.call(schema_member, context)` returns false
|
100
|
-
def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, static_validator: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, except: nil, only: nil, warden: nil)
|
98
|
+
def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, static_validator: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, warden: nil)
|
101
99
|
# Even if `variables: nil` is passed, use an empty hash for simpler logic
|
102
100
|
variables ||= {}
|
103
101
|
@schema = schema
|
104
|
-
if only || except
|
105
|
-
merge_filters(except: except, only: only)
|
106
|
-
end
|
107
102
|
@context = schema.context_class.new(query: self, object: root_value, values: context)
|
108
103
|
@warden = warden
|
109
104
|
@subscription_topic = subscription_topic
|
@@ -120,8 +115,6 @@ module GraphQL
|
|
120
115
|
if schema.trace_class <= GraphQL::Tracing::CallLegacyTracers
|
121
116
|
context_tracers += [GraphQL::Backtrace::Tracer]
|
122
117
|
@tracers << GraphQL::Backtrace::Tracer
|
123
|
-
elsif !(current_trace.class <= GraphQL::Backtrace::Trace)
|
124
|
-
raise "Invariant: `backtrace: true` should have provided a trace class with Backtrace mixed in, but it didnt. (Found: #{current_trace.class.ancestors}). This is a bug in GraphQL-Ruby, please report it on GitHub."
|
125
118
|
end
|
126
119
|
end
|
127
120
|
|
@@ -129,7 +122,6 @@ module GraphQL
|
|
129
122
|
raise ArgumentError, "context[:tracers] are not supported without `trace_with(GraphQL::Tracing::CallLegacyTracers)` in the schema configuration, please add it."
|
130
123
|
end
|
131
124
|
|
132
|
-
|
133
125
|
@analysis_errors = []
|
134
126
|
if variables.is_a?(String)
|
135
127
|
raise ArgumentError, "Query variables should be a Hash, not a String. Try JSON.parse to prepare variables."
|
@@ -168,6 +160,14 @@ module GraphQL
|
|
168
160
|
|
169
161
|
@result_values = nil
|
170
162
|
@executed = false
|
163
|
+
|
164
|
+
@logger = if context && context[:logger] == false
|
165
|
+
Logger.new(IO::NULL)
|
166
|
+
elsif context && (l = context[:logger])
|
167
|
+
l
|
168
|
+
else
|
169
|
+
schema.default_logger
|
170
|
+
end
|
171
171
|
end
|
172
172
|
|
173
173
|
# If a document was provided to `GraphQL::Schema#execute` instead of the raw query string, we will need to get it from the document
|
@@ -317,7 +317,7 @@ module GraphQL
|
|
317
317
|
end
|
318
318
|
|
319
319
|
def_delegators :validation_pipeline, :validation_errors,
|
320
|
-
:analyzers, :ast_analyzers, :max_depth, :max_complexity
|
320
|
+
:analyzers, :ast_analyzers, :max_depth, :max_complexity, :validate_timeout_remaining
|
321
321
|
|
322
322
|
attr_accessor :analysis_errors
|
323
323
|
def valid?
|
@@ -354,17 +354,6 @@ module GraphQL
|
|
354
354
|
with_prepared_ast { @query }
|
355
355
|
end
|
356
356
|
|
357
|
-
# @return [void]
|
358
|
-
def merge_filters(only: nil, except: nil)
|
359
|
-
if @prepared_ast
|
360
|
-
raise "Can't add filters after preparing the query"
|
361
|
-
else
|
362
|
-
@filter ||= @schema.default_filter
|
363
|
-
@filter = @filter.merge(only: only, except: except)
|
364
|
-
end
|
365
|
-
nil
|
366
|
-
end
|
367
|
-
|
368
357
|
def subscription?
|
369
358
|
with_prepared_ast { @subscription }
|
370
359
|
end
|
@@ -386,6 +375,8 @@ module GraphQL
|
|
386
375
|
end
|
387
376
|
end
|
388
377
|
|
378
|
+
attr_reader :logger
|
379
|
+
|
389
380
|
private
|
390
381
|
|
391
382
|
def find_operation(operations, operation_name)
|
@@ -400,7 +391,7 @@ module GraphQL
|
|
400
391
|
|
401
392
|
def prepare_ast
|
402
393
|
@prepared_ast = true
|
403
|
-
@warden ||= @schema.warden_class.new(
|
394
|
+
@warden ||= @schema.warden_class.new(schema: @schema, context: @context)
|
404
395
|
parse_error = nil
|
405
396
|
@document ||= begin
|
406
397
|
if query_string
|
data/lib/graphql/railtie.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module GraphQL
|
3
4
|
class Railtie < Rails::Railtie
|
4
|
-
config.
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
if
|
9
|
-
Language::Parser.cache ||= Language::Cache.new(
|
5
|
+
config.graphql = ActiveSupport::OrderedOptions.new
|
6
|
+
config.graphql.parser_cache = false
|
7
|
+
|
8
|
+
initializer("graphql.cache") do |app|
|
9
|
+
if config.graphql.parser_cache
|
10
|
+
Language::Parser.cache ||= Language::Cache.new(
|
11
|
+
app.root.join("tmp/cache/graphql")
|
12
|
+
)
|
10
13
|
end
|
11
14
|
end
|
12
15
|
end
|
data/lib/graphql/rake_task.rb
CHANGED
@@ -9,8 +9,7 @@ module GraphQL
|
|
9
9
|
# By default, schemas are looked up by name as constants using `schema_name:`.
|
10
10
|
# You can provide a `load_schema` function to return your schema another way.
|
11
11
|
#
|
12
|
-
# `load_context
|
13
|
-
# you can keep an eye on how filters affect your schema.
|
12
|
+
# Use `load_context:` and `visible?` to dump schemas under certain visibility constraints.
|
14
13
|
#
|
15
14
|
# @example Dump a Schema to .graphql + .json files
|
16
15
|
# require "graphql/rake_task"
|
@@ -36,8 +35,6 @@ module GraphQL
|
|
36
35
|
schema_name: nil,
|
37
36
|
load_schema: ->(task) { Object.const_get(task.schema_name) },
|
38
37
|
load_context: ->(task) { {} },
|
39
|
-
only: nil,
|
40
|
-
except: nil,
|
41
38
|
directory: ".",
|
42
39
|
idl_outfile: "schema.graphql",
|
43
40
|
json_outfile: "schema.json",
|
@@ -68,12 +65,6 @@ module GraphQL
|
|
68
65
|
# @return [<#call(task)>] A callable for loading the query context
|
69
66
|
attr_accessor :load_context
|
70
67
|
|
71
|
-
# @return [<#call(member, ctx)>, nil] A filter for this task
|
72
|
-
attr_accessor :only
|
73
|
-
|
74
|
-
# @return [<#call(member, ctx)>, nil] A filter for this task
|
75
|
-
attr_accessor :except
|
76
|
-
|
77
68
|
# @return [String] target for IDL task
|
78
69
|
attr_accessor :idl_outfile
|
79
70
|
|
@@ -117,10 +108,10 @@ module GraphQL
|
|
117
108
|
include_is_repeatable: include_is_repeatable,
|
118
109
|
include_specified_by_url: include_specified_by_url,
|
119
110
|
include_schema_description: include_schema_description,
|
120
|
-
|
111
|
+
context: context
|
121
112
|
)
|
122
113
|
when :to_definition
|
123
|
-
schema.to_definition(
|
114
|
+
schema.to_definition(context: context)
|
124
115
|
else
|
125
116
|
raise ArgumentError, "Unexpected schema dump method: #{method_name.inspect}"
|
126
117
|
end
|
@@ -221,8 +221,13 @@ module GraphQL
|
|
221
221
|
#
|
222
222
|
# This will have to be called later, when the runtime object _is_ available.
|
223
223
|
value
|
224
|
-
|
224
|
+
elsif obj.respond_to?(@prepare)
|
225
225
|
obj.public_send(@prepare, value)
|
226
|
+
elsif owner.respond_to?(@prepare)
|
227
|
+
owner.public_send(@prepare, value, context || obj.context)
|
228
|
+
else
|
229
|
+
raise "Invalid prepare for #{@owner.name}.name: #{@prepare.inspect}. "\
|
230
|
+
"Could not find prepare method #{@prepare} on #{obj.class} or #{owner}."
|
226
231
|
end
|
227
232
|
elsif @prepare.respond_to?(:call)
|
228
233
|
@prepare.call(value, context || obj.context)
|
@@ -432,14 +432,12 @@ module GraphQL
|
|
432
432
|
builder = self
|
433
433
|
|
434
434
|
field_definitions.each do |field_definition|
|
435
|
-
type_name = resolve_type_name(field_definition.type)
|
436
435
|
resolve_method_name = -"resolve_field_#{field_definition.name}"
|
437
436
|
schema_field_defn = owner.field(
|
438
437
|
field_definition.name,
|
439
438
|
description: field_definition.description,
|
440
439
|
type: type_resolver.call(field_definition.type),
|
441
440
|
null: true,
|
442
|
-
connection: type_name.end_with?("Connection"),
|
443
441
|
connection_extension: nil,
|
444
442
|
deprecation_reason: build_deprecation_reason(field_definition.directives),
|
445
443
|
ast_node: field_definition,
|
@@ -487,15 +485,6 @@ module GraphQL
|
|
487
485
|
}
|
488
486
|
resolve_type_proc
|
489
487
|
end
|
490
|
-
|
491
|
-
def resolve_type_name(type)
|
492
|
-
case type
|
493
|
-
when GraphQL::Language::Nodes::TypeName
|
494
|
-
return type.name
|
495
|
-
else
|
496
|
-
resolve_type_name(type.of_type)
|
497
|
-
end
|
498
|
-
end
|
499
488
|
end
|
500
489
|
|
501
490
|
private_constant :Builder
|
@@ -6,6 +6,18 @@ module GraphQL
|
|
6
6
|
description "Requires that exactly one field must be supplied and that field must not be `null`."
|
7
7
|
locations(GraphQL::Schema::Directive::INPUT_OBJECT)
|
8
8
|
default_directive true
|
9
|
+
|
10
|
+
def initialize(...)
|
11
|
+
super
|
12
|
+
|
13
|
+
owner.extend(IsOneOf)
|
14
|
+
end
|
15
|
+
|
16
|
+
module IsOneOf
|
17
|
+
def one_of?
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
9
21
|
end
|
10
22
|
end
|
11
23
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
class Schema
|
4
|
+
class Directive < GraphQL::Schema::Member
|
5
|
+
class SpecifiedBy < GraphQL::Schema::Directive
|
6
|
+
description "Exposes a URL that specifies the behavior of this scalar."
|
7
|
+
locations(GraphQL::Schema::Directive::SCALAR)
|
8
|
+
default_directive true
|
9
|
+
|
10
|
+
argument :url, String, description: "The URL that specifies the behavior of this scalar."
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -119,7 +119,7 @@ module GraphQL
|
|
119
119
|
# - lazy resolution
|
120
120
|
# Probably, those won't be needed here, since these are configuration arguments,
|
121
121
|
# not runtime arguments.
|
122
|
-
@arguments = self.class.coerce_arguments(nil, arguments, Query::NullContext)
|
122
|
+
@arguments = self.class.coerce_arguments(nil, arguments, Query::NullContext.instance)
|
123
123
|
end
|
124
124
|
|
125
125
|
def graphql_name
|
data/lib/graphql/schema/enum.rb
CHANGED
@@ -14,7 +14,7 @@ module GraphQL
|
|
14
14
|
# # ONIONS
|
15
15
|
# # PEPPERS
|
16
16
|
# # }
|
17
|
-
# class PizzaTopping < GraphQL::Enum
|
17
|
+
# class PizzaTopping < GraphQL::Schema::Enum
|
18
18
|
# value :MUSHROOMS
|
19
19
|
# value :ONIONS
|
20
20
|
# value :PEPPERS
|
@@ -68,7 +68,7 @@ module GraphQL
|
|
68
68
|
end
|
69
69
|
|
70
70
|
# @return [Array<GraphQL::Schema::EnumValue>] Possible values of this enum
|
71
|
-
def enum_values(context = GraphQL::Query::NullContext)
|
71
|
+
def enum_values(context = GraphQL::Query::NullContext.instance)
|
72
72
|
inherited_values = superclass.respond_to?(:enum_values) ? superclass.enum_values(context) : nil
|
73
73
|
visible_values = []
|
74
74
|
warden = Warden.from_context(context)
|
@@ -110,7 +110,7 @@ module GraphQL
|
|
110
110
|
end
|
111
111
|
|
112
112
|
# @return [Hash<String => GraphQL::Schema::EnumValue>] Possible values of this enum, keyed by name.
|
113
|
-
def values(context = GraphQL::Query::NullContext)
|
113
|
+
def values(context = GraphQL::Query::NullContext.instance)
|
114
114
|
enum_values(context).each_with_object({}) { |val, obj| obj[val.graphql_name] = val }
|
115
115
|
end
|
116
116
|
|
@@ -54,23 +54,9 @@ module GraphQL
|
|
54
54
|
value.edge_class = custom_t
|
55
55
|
end
|
56
56
|
value
|
57
|
-
|
57
|
+
else
|
58
58
|
context.namespace(:connections)[:all_wrappers] ||= context.schema.connections.all_wrappers
|
59
59
|
context.schema.connections.wrap(field, object.object, value, original_arguments, context)
|
60
|
-
else
|
61
|
-
if object.is_a?(GraphQL::Schema::Object)
|
62
|
-
object = object.object
|
63
|
-
end
|
64
|
-
connection_class = GraphQL::Relay::BaseConnection.connection_for_nodes(value)
|
65
|
-
connection_class.new(
|
66
|
-
value,
|
67
|
-
original_arguments,
|
68
|
-
field: field,
|
69
|
-
max_page_size: field.max_page_size,
|
70
|
-
default_page_size: field.default_page_size,
|
71
|
-
parent: object,
|
72
|
-
context: context,
|
73
|
-
)
|
74
60
|
end
|
75
61
|
end
|
76
62
|
end
|
@@ -10,7 +10,14 @@ module GraphQL
|
|
10
10
|
else
|
11
11
|
ret_type = @field.type.unwrap
|
12
12
|
if ret_type.respond_to?(:scope_items)
|
13
|
-
ret_type.scope_items(value, context)
|
13
|
+
scoped_items = ret_type.scope_items(value, context)
|
14
|
+
if !scoped_items.equal?(value) && !ret_type.reauthorize_scoped_objects
|
15
|
+
if (current_runtime_state = Thread.current[:__graphql_runtime_info]) &&
|
16
|
+
(query_runtime_state = current_runtime_state[context.query])
|
17
|
+
query_runtime_state.was_authorized_by_scope_items = true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
scoped_items
|
14
21
|
else
|
15
22
|
value
|
16
23
|
end
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -138,7 +138,7 @@ module GraphQL
|
|
138
138
|
# As a last ditch, try to force loading the return type:
|
139
139
|
type.unwrap.name
|
140
140
|
end
|
141
|
-
@connection = return_type_name.end_with?("Connection")
|
141
|
+
@connection = return_type_name.end_with?("Connection") && return_type_name != "Connection"
|
142
142
|
else
|
143
143
|
@connection
|
144
144
|
end
|
@@ -218,8 +218,8 @@ module GraphQL
|
|
218
218
|
# @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
|
219
219
|
# @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
|
220
220
|
# @param validates [Array<Hash>] Configurations for validating this field
|
221
|
-
# @fallback_value [Object] A fallback value if the method is not defined
|
222
|
-
def initialize(type: nil, name: nil, owner: nil, null: nil, description: NOT_CONFIGURED, deprecation_reason: nil, method: nil, hash_key: nil, dig: nil, resolver_method: nil, connection: nil, max_page_size: NOT_CONFIGURED, default_page_size: NOT_CONFIGURED, scope: nil, introspection: false, camelize: true, trace: nil, complexity: nil, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: NOT_CONFIGURED, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, fallback_value: NOT_CONFIGURED, &definition_block)
|
221
|
+
# @param fallback_value [Object] A fallback value if the method is not defined
|
222
|
+
def initialize(type: nil, name: nil, owner: nil, null: nil, description: NOT_CONFIGURED, deprecation_reason: nil, method: nil, hash_key: nil, dig: nil, resolver_method: nil, connection: nil, max_page_size: NOT_CONFIGURED, default_page_size: NOT_CONFIGURED, scope: nil, introspection: false, camelize: true, trace: nil, complexity: nil, ast_node: nil, extras: EMPTY_ARRAY, extensions: EMPTY_ARRAY, connection_extension: self.class.connection_extension, resolver_class: nil, subscription_scope: nil, relay_node_field: false, relay_nodes_field: false, method_conflict_warning: true, broadcastable: NOT_CONFIGURED, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, fallback_value: NOT_CONFIGURED, dynamic_introspection: false, &definition_block)
|
223
223
|
if name.nil?
|
224
224
|
raise ArgumentError, "missing first `name` argument or keyword `name:`"
|
225
225
|
end
|
@@ -267,6 +267,7 @@ module GraphQL
|
|
267
267
|
@method_sym = method_name.to_sym
|
268
268
|
@resolver_method = (resolver_method || name_s).to_sym
|
269
269
|
@complexity = complexity
|
270
|
+
@dynamic_introspection = dynamic_introspection
|
270
271
|
@return_type_expr = type
|
271
272
|
@return_type_null = if !null.nil?
|
272
273
|
null
|
@@ -351,6 +352,8 @@ module GraphQL
|
|
351
352
|
@call_after_define = true
|
352
353
|
end
|
353
354
|
|
355
|
+
attr_accessor :dynamic_introspection
|
356
|
+
|
354
357
|
# If true, subscription updates with this field can be shared between viewers
|
355
358
|
# @return [Boolean, nil]
|
356
359
|
# @see GraphQL::Subscriptions::BroadcastAnalyzer
|
@@ -659,7 +662,7 @@ module GraphQL
|
|
659
662
|
method_to_call = nil
|
660
663
|
method_args = nil
|
661
664
|
|
662
|
-
Schema::Validator.validate!(validators, application_object, query_ctx, args)
|
665
|
+
@own_validators && Schema::Validator.validate!(validators, application_object, query_ctx, args)
|
663
666
|
|
664
667
|
query_ctx.query.after_lazy(self.authorized?(application_object, args, query_ctx)) do |is_authorized|
|
665
668
|
if is_authorized
|
@@ -701,7 +704,7 @@ module GraphQL
|
|
701
704
|
inner_object.dig(*@dig_keys)
|
702
705
|
elsif inner_object.key?(@method_sym)
|
703
706
|
inner_object[@method_sym]
|
704
|
-
elsif inner_object.key?(@method_str)
|
707
|
+
elsif inner_object.key?(@method_str) || !inner_object.default_proc.nil?
|
705
708
|
inner_object[@method_str]
|
706
709
|
elsif @fallback_value != NOT_CONFIGURED
|
707
710
|
@fallback_value
|