graphql 2.0.13 → 2.3.10
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/mutation_root_generator.rb +2 -2
- 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/mutation_delete_generator.rb +1 -1
- data/lib/generators/graphql/mutation_update_generator.rb +1 -1
- data/lib/generators/graphql/relay.rb +18 -1
- 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 +8 -0
- data/lib/graphql/analysis/analyzer.rb +89 -0
- data/lib/graphql/analysis/field_usage.rb +82 -0
- data/lib/graphql/analysis/max_query_complexity.rb +20 -0
- data/lib/graphql/analysis/max_query_depth.rb +20 -0
- data/lib/graphql/analysis/query_complexity.rb +183 -0
- data/lib/graphql/analysis/query_depth.rb +58 -0
- data/lib/graphql/analysis/visitor.rb +283 -0
- data/lib/graphql/analysis.rb +92 -1
- data/lib/graphql/backtrace/inspect_result.rb +0 -12
- data/lib/graphql/backtrace/table.rb +2 -2
- data/lib/graphql/backtrace/trace.rb +93 -0
- data/lib/graphql/backtrace/tracer.rb +1 -1
- data/lib/graphql/backtrace.rb +2 -1
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/dataloader/async_dataloader.rb +88 -0
- data/lib/graphql/dataloader/null_dataloader.rb +1 -1
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +89 -45
- data/lib/graphql/dataloader.rb +115 -142
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +33 -33
- data/lib/graphql/execution/interpreter/resolve.rb +19 -0
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +175 -0
- data/lib/graphql/execution/interpreter/runtime.rb +331 -455
- data/lib/graphql/execution/interpreter.rb +125 -61
- data/lib/graphql/execution/lazy.rb +6 -12
- data/lib/graphql/execution/lookahead.rb +124 -46
- data/lib/graphql/execution/multiplex.rb +3 -117
- data/lib/graphql/execution.rb +0 -1
- data/lib/graphql/introspection/directive_type.rb +3 -3
- data/lib/graphql/introspection/dynamic_fields.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +11 -5
- data/lib/graphql/introspection/field_type.rb +2 -2
- data/lib/graphql/introspection/schema_type.rb +10 -13
- data/lib/graphql/introspection/type_type.rb +17 -10
- data/lib/graphql/introspection.rb +3 -2
- 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 +75 -59
- data/lib/graphql/language/lexer.rb +358 -1506
- data/lib/graphql/language/nodes.rb +166 -93
- data/lib/graphql/language/parser.rb +795 -1953
- data/lib/graphql/language/printer.rb +340 -160
- data/lib/graphql/language/sanitized_printer.rb +21 -23
- data/lib/graphql/language/static_visitor.rb +167 -0
- data/lib/graphql/language/visitor.rb +188 -141
- data/lib/graphql/language.rb +61 -1
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
- data/lib/graphql/pagination/array_connection.rb +6 -6
- data/lib/graphql/pagination/connection.rb +33 -6
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +117 -112
- data/lib/graphql/query/null_context.rb +12 -25
- data/lib/graphql/query/validation_pipeline.rb +6 -5
- data/lib/graphql/query/variables.rb +3 -3
- data/lib/graphql/query.rb +86 -30
- data/lib/graphql/railtie.rb +9 -6
- data/lib/graphql/rake_task.rb +29 -11
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
- data/lib/graphql/schema/addition.rb +59 -23
- data/lib/graphql/schema/always_visible.rb +11 -0
- data/lib/graphql/schema/argument.rb +55 -26
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +56 -32
- data/lib/graphql/schema/directive/one_of.rb +24 -0
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/directive.rb +15 -3
- data/lib/graphql/schema/enum.rb +35 -24
- data/lib/graphql/schema/enum_value.rb +2 -3
- data/lib/graphql/schema/field/connection_extension.rb +2 -16
- data/lib/graphql/schema/field/scope_extension.rb +8 -1
- data/lib/graphql/schema/field.rb +147 -107
- data/lib/graphql/schema/field_extension.rb +1 -4
- data/lib/graphql/schema/find_inherited_value.rb +2 -7
- data/lib/graphql/schema/has_single_input_argument.rb +158 -0
- data/lib/graphql/schema/input_object.rb +47 -11
- data/lib/graphql/schema/interface.rb +15 -21
- data/lib/graphql/schema/introspection_system.rb +7 -17
- data/lib/graphql/schema/late_bound_type.rb +10 -0
- data/lib/graphql/schema/list.rb +2 -2
- data/lib/graphql/schema/loader.rb +2 -3
- data/lib/graphql/schema/member/base_dsl_methods.rb +18 -14
- data/lib/graphql/schema/member/build_type.rb +11 -3
- data/lib/graphql/schema/member/has_arguments.rb +170 -130
- data/lib/graphql/schema/member/has_ast_node.rb +12 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_directives.rb +81 -61
- data/lib/graphql/schema/member/has_fields.rb +100 -38
- data/lib/graphql/schema/member/has_interfaces.rb +65 -10
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +32 -6
- data/lib/graphql/schema/member/relay_shortcuts.rb +19 -0
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +16 -0
- data/lib/graphql/schema/member/validates_input.rb +3 -3
- data/lib/graphql/schema/mutation.rb +7 -0
- data/lib/graphql/schema/object.rb +16 -5
- data/lib/graphql/schema/printer.rb +11 -8
- data/lib/graphql/schema/relay_classic_mutation.rb +7 -129
- data/lib/graphql/schema/resolver/has_payload_type.rb +9 -9
- data/lib/graphql/schema/resolver.rb +47 -32
- data/lib/graphql/schema/scalar.rb +3 -3
- data/lib/graphql/schema/subscription.rb +11 -4
- data/lib/graphql/schema/subset.rb +397 -0
- data/lib/graphql/schema/timeout.rb +25 -29
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/type_membership.rb +3 -0
- data/lib/graphql/schema/union.rb +11 -2
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/validator/all_validator.rb +60 -0
- data/lib/graphql/schema/validator.rb +4 -2
- data/lib/graphql/schema/warden.rb +238 -93
- data/lib/graphql/schema.rb +498 -103
- data/lib/graphql/static_validation/all_rules.rb +2 -1
- data/lib/graphql/static_validation/base_visitor.rb +7 -6
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
- data/lib/graphql/static_validation/literal_validator.rb +24 -7
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +1 -2
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +10 -10
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +1 -1
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -4
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +1 -1
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +1 -1
- data/lib/graphql/static_validation/validation_context.rb +5 -5
- data/lib/graphql/static_validation/validator.rb +4 -1
- data/lib/graphql/static_validation.rb +0 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +11 -4
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/event.rb +11 -10
- data/lib/graphql/subscriptions/serialize.rb +2 -0
- data/lib/graphql/subscriptions.rb +20 -13
- data/lib/graphql/testing/helpers.rb +151 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/appoptics_trace.rb +251 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
- data/lib/graphql/tracing/appsignal_trace.rb +77 -0
- data/lib/graphql/tracing/data_dog_trace.rb +183 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +9 -21
- data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +10 -28
- data/lib/graphql/tracing/legacy_trace.rb +69 -0
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/notifications_trace.rb +45 -0
- data/lib/graphql/tracing/platform_trace.rb +118 -0
- data/lib/graphql/tracing/platform_tracing.rb +17 -3
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +4 -2
- data/lib/graphql/tracing/prometheus_trace.rb +89 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
- data/lib/graphql/tracing/scout_trace.rb +72 -0
- data/lib/graphql/tracing/sentry_trace.rb +112 -0
- data/lib/graphql/tracing/statsd_trace.rb +56 -0
- data/lib/graphql/tracing/trace.rb +76 -0
- data/lib/graphql/tracing.rb +20 -40
- data/lib/graphql/type_kinds.rb +7 -4
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/base_connection.rb +1 -1
- data/lib/graphql/types/relay/connection_behaviors.rb +68 -6
- data/lib/graphql/types/relay/edge_behaviors.rb +33 -5
- data/lib/graphql/types/relay/node_behaviors.rb +8 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
- data/lib/graphql/types/relay.rb +0 -1
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/types.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +27 -20
- data/readme.md +13 -3
- metadata +96 -47
- data/lib/graphql/analysis/ast/analyzer.rb +0 -84
- data/lib/graphql/analysis/ast/field_usage.rb +0 -57
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -22
- data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
- data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
- data/lib/graphql/analysis/ast/query_depth.rb +0 -55
- data/lib/graphql/analysis/ast/visitor.rb +0 -269
- data/lib/graphql/analysis/ast.rb +0 -81
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/filter.rb +0 -53
- data/lib/graphql/language/lexer.rl +0 -280
- data/lib/graphql/language/parser.y +0 -554
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/subscriptions/instrumentation.rb +0 -28
- data/lib/graphql/types/relay/default_relay.rb +0 -21
@@ -7,9 +7,7 @@ module GraphQL
|
|
7
7
|
include GraphQL::Schema::Member::HasDirectives
|
8
8
|
include GraphQL::Schema::Member::HasDeprecationReason
|
9
9
|
include GraphQL::Schema::Member::HasValidators
|
10
|
-
include GraphQL::
|
11
|
-
|
12
|
-
NO_DEFAULT = :__no_default__
|
10
|
+
include GraphQL::EmptyObjects
|
13
11
|
|
14
12
|
# @return [String] the GraphQL name for this argument, camelized unless `camelize: false` is provided
|
15
13
|
attr_reader :name
|
@@ -20,8 +18,8 @@ module GraphQL
|
|
20
18
|
|
21
19
|
# @param new_prepare [Method, Proc]
|
22
20
|
# @return [Symbol] A method or proc to call to transform this value before sending it to field resolution method
|
23
|
-
def prepare(new_prepare =
|
24
|
-
if new_prepare !=
|
21
|
+
def prepare(new_prepare = NOT_CONFIGURED)
|
22
|
+
if new_prepare != NOT_CONFIGURED
|
25
23
|
@prepare = new_prepare
|
26
24
|
end
|
27
25
|
@prepare
|
@@ -52,7 +50,7 @@ module GraphQL
|
|
52
50
|
# @param deprecation_reason [String]
|
53
51
|
# @param validates [Hash, nil] Options for building validators, if any should be applied
|
54
52
|
# @param replace_null_with_default [Boolean] if `true`, incoming values of `null` will be replaced with the configured `default_value`
|
55
|
-
def initialize(arg_name = nil, type_expr = nil, desc = nil, required: true, type: nil, name: nil, loads: nil, description: nil, ast_node: nil, default_value:
|
53
|
+
def initialize(arg_name = nil, type_expr = nil, desc = nil, required: true, type: nil, name: nil, loads: nil, description: nil, ast_node: nil, default_value: NOT_CONFIGURED, as: nil, from_resolver: false, camelize: true, prepare: nil, owner:, validates: nil, directives: nil, deprecation_reason: nil, replace_null_with_default: false, &definition_block)
|
56
54
|
arg_name ||= name
|
57
55
|
@name = -(camelize ? Member::BuildType.camelize(arg_name.to_s) : arg_name.to_s)
|
58
56
|
@type_expr = type_expr || type
|
@@ -104,8 +102,8 @@ module GraphQL
|
|
104
102
|
|
105
103
|
# @param default_value [Object] The value to use when the client doesn't provide one
|
106
104
|
# @return [Object] the value used when the client doesn't provide a value for this argument
|
107
|
-
def default_value(new_default_value =
|
108
|
-
if new_default_value !=
|
105
|
+
def default_value(new_default_value = NOT_CONFIGURED)
|
106
|
+
if new_default_value != NOT_CONFIGURED
|
109
107
|
@default_value = new_default_value
|
110
108
|
end
|
111
109
|
@default_value
|
@@ -113,7 +111,7 @@ module GraphQL
|
|
113
111
|
|
114
112
|
# @return [Boolean] True if this argument has a default value
|
115
113
|
def default_value?
|
116
|
-
@default_value !=
|
114
|
+
@default_value != NOT_CONFIGURED
|
117
115
|
end
|
118
116
|
|
119
117
|
def replace_null_with_default?
|
@@ -149,10 +147,6 @@ module GraphQL
|
|
149
147
|
true
|
150
148
|
end
|
151
149
|
|
152
|
-
def accessible?(context)
|
153
|
-
true
|
154
|
-
end
|
155
|
-
|
156
150
|
def authorized?(obj, value, ctx)
|
157
151
|
authorized_as_type?(obj, value, ctx, as_type: type)
|
158
152
|
end
|
@@ -204,16 +198,16 @@ module GraphQL
|
|
204
198
|
|
205
199
|
def statically_coercible?
|
206
200
|
return @statically_coercible if defined?(@statically_coercible)
|
207
|
-
|
208
|
-
@statically_coercible =
|
201
|
+
requires_parent_object = @prepare.is_a?(String) || @prepare.is_a?(Symbol) || @own_validators
|
202
|
+
@statically_coercible = !requires_parent_object
|
209
203
|
end
|
210
204
|
|
211
205
|
# Apply the {prepare} configuration to `value`, using methods from `obj`.
|
212
206
|
# Used by the runtime.
|
213
207
|
# @api private
|
214
208
|
def prepare_value(obj, value, context: nil)
|
215
|
-
if
|
216
|
-
value = value
|
209
|
+
if type.unwrap.kind.input_object?
|
210
|
+
value = recursively_prepare_input_object(value, type)
|
217
211
|
end
|
218
212
|
|
219
213
|
Schema::Validator.validate!(validators, obj, context, value)
|
@@ -227,8 +221,13 @@ module GraphQL
|
|
227
221
|
#
|
228
222
|
# This will have to be called later, when the runtime object _is_ available.
|
229
223
|
value
|
230
|
-
|
224
|
+
elsif obj.respond_to?(@prepare)
|
231
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}."
|
232
231
|
end
|
233
232
|
elsif @prepare.respond_to?(:call)
|
234
233
|
@prepare.call(value, context || obj.context)
|
@@ -270,7 +269,7 @@ module GraphQL
|
|
270
269
|
|
271
270
|
# If this isn't lazy, then the block returns eagerly and assigns the result here
|
272
271
|
# If it _is_ lazy, then we write the lazy to the hash, then update it later
|
273
|
-
argument_values[arg_key] = context.
|
272
|
+
argument_values[arg_key] = context.query.after_lazy(coerced_value) do |resolved_coerced_value|
|
274
273
|
owner.validate_directive_argument(self, resolved_coerced_value)
|
275
274
|
prepared_value = begin
|
276
275
|
prepare_value(parent_object, resolved_coerced_value, context: context)
|
@@ -287,10 +286,11 @@ module GraphQL
|
|
287
286
|
end
|
288
287
|
|
289
288
|
maybe_loaded_value = loaded_value || prepared_value
|
290
|
-
context.
|
289
|
+
context.query.after_lazy(maybe_loaded_value) do |resolved_loaded_value|
|
291
290
|
# TODO code smell to access such a deeply-nested constant in a distant module
|
292
291
|
argument_values[arg_key] = GraphQL::Execution::Interpreter::ArgumentValue.new(
|
293
292
|
value: resolved_loaded_value,
|
293
|
+
original_value: resolved_coerced_value,
|
294
294
|
definition: self,
|
295
295
|
default_used: default_used,
|
296
296
|
)
|
@@ -309,13 +309,18 @@ module GraphQL
|
|
309
309
|
else
|
310
310
|
load_method_owner.public_send(arg_load_method, coerced_value)
|
311
311
|
end
|
312
|
-
context.
|
312
|
+
context.query.after_lazy(custom_loaded_value) do |custom_value|
|
313
313
|
if loads
|
314
314
|
if type.list?
|
315
|
-
loaded_values =
|
316
|
-
|
317
|
-
|
318
|
-
|
315
|
+
loaded_values = []
|
316
|
+
context.dataloader.run_isolated do
|
317
|
+
custom_value.each_with_index.map { |custom_val, idx|
|
318
|
+
id = coerced_value[idx]
|
319
|
+
context.dataloader.append_job do
|
320
|
+
loaded_values[idx] = load_method_owner.authorize_application_object(self, id, context, custom_val)
|
321
|
+
end
|
322
|
+
}
|
323
|
+
end
|
319
324
|
context.schema.after_any_lazies(loaded_values, &:itself)
|
320
325
|
else
|
321
326
|
load_method_owner.authorize_application_object(self, coerced_value, context, custom_loaded_value)
|
@@ -326,7 +331,16 @@ module GraphQL
|
|
326
331
|
end
|
327
332
|
elsif loads
|
328
333
|
if type.list?
|
329
|
-
loaded_values =
|
334
|
+
loaded_values = []
|
335
|
+
# We want to run these list items all together,
|
336
|
+
# but we also need to wait for the result so we can return it :S
|
337
|
+
context.dataloader.run_isolated do
|
338
|
+
coerced_value.each_with_index { |val, idx|
|
339
|
+
context.dataloader.append_job do
|
340
|
+
loaded_values[idx] = load_method_owner.load_and_authorize_application_object(self, val, context)
|
341
|
+
end
|
342
|
+
}
|
343
|
+
end
|
330
344
|
context.schema.after_any_lazies(loaded_values, &:itself)
|
331
345
|
else
|
332
346
|
load_method_owner.load_and_authorize_application_object(self, coerced_value, context)
|
@@ -373,6 +387,21 @@ module GraphQL
|
|
373
387
|
|
374
388
|
private
|
375
389
|
|
390
|
+
def recursively_prepare_input_object(value, type)
|
391
|
+
if type.non_null?
|
392
|
+
type = type.of_type
|
393
|
+
end
|
394
|
+
|
395
|
+
if type.list? && !value.nil?
|
396
|
+
inner_type = type.of_type
|
397
|
+
value.map { |v| recursively_prepare_input_object(v, inner_type) }
|
398
|
+
elsif value.is_a?(GraphQL::Schema::InputObject)
|
399
|
+
value.prepare
|
400
|
+
else
|
401
|
+
value
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
376
405
|
def validate_input_type(input_type)
|
377
406
|
if input_type.is_a?(String) || input_type.is_a?(GraphQL::Schema::LateBoundType)
|
378
407
|
# Do nothing; assume this will be validated later
|
@@ -1,18 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'graphql/schema/base_64_bp'
|
4
|
-
|
2
|
+
require "base64"
|
5
3
|
module GraphQL
|
6
4
|
class Schema
|
7
5
|
# @api private
|
8
6
|
module Base64Encoder
|
9
7
|
def self.encode(unencoded_text, nonce: false)
|
10
|
-
|
8
|
+
Base64.urlsafe_encode64(unencoded_text, padding: false)
|
11
9
|
end
|
12
10
|
|
13
11
|
def self.decode(encoded_text, nonce: false)
|
14
12
|
# urlsafe_decode64 is for forward compatibility
|
15
|
-
|
13
|
+
Base64.urlsafe_decode64(encoded_text)
|
16
14
|
rescue ArgumentError
|
17
15
|
raise GraphQL::ExecutionError, "Invalid input: #{encoded_text.inspect}"
|
18
16
|
end
|
@@ -6,24 +6,31 @@ module GraphQL
|
|
6
6
|
module BuildFromDefinition
|
7
7
|
class << self
|
8
8
|
# @see {Schema.from_definition}
|
9
|
-
def from_definition(definition_string, parser: GraphQL.default_parser, **kwargs)
|
10
|
-
|
9
|
+
def from_definition(schema_superclass, definition_string, parser: GraphQL.default_parser, **kwargs)
|
10
|
+
if defined?(parser::SchemaParser)
|
11
|
+
parser = parser::SchemaParser
|
12
|
+
end
|
13
|
+
from_document(schema_superclass, parser.parse(definition_string), **kwargs)
|
11
14
|
end
|
12
15
|
|
13
|
-
def from_definition_path(definition_path, parser: GraphQL.default_parser, **kwargs)
|
14
|
-
|
16
|
+
def from_definition_path(schema_superclass, definition_path, parser: GraphQL.default_parser, **kwargs)
|
17
|
+
if defined?(parser::SchemaParser)
|
18
|
+
parser = parser::SchemaParser
|
19
|
+
end
|
20
|
+
from_document(schema_superclass, parser.parse_file(definition_path), **kwargs)
|
15
21
|
end
|
16
22
|
|
17
|
-
def from_document(document, default_resolve:, using: {}, relay: false)
|
18
|
-
Builder.build(document, default_resolve: default_resolve || {}, relay: relay, using: using)
|
23
|
+
def from_document(schema_superclass, document, default_resolve:, using: {}, relay: false)
|
24
|
+
Builder.build(schema_superclass, document, default_resolve: default_resolve || {}, relay: relay, using: using)
|
19
25
|
end
|
20
26
|
end
|
21
27
|
|
22
28
|
# @api private
|
23
29
|
module Builder
|
30
|
+
include GraphQL::EmptyObjects
|
24
31
|
extend self
|
25
32
|
|
26
|
-
def build(document, default_resolve:, using: {}, relay:)
|
33
|
+
def build(schema_superclass, document, default_resolve:, using: {}, relay:)
|
27
34
|
raise InvalidDocumentError.new('Must provide a document ast.') if !document || !document.is_a?(GraphQL::Language::Nodes::Document)
|
28
35
|
|
29
36
|
if default_resolve.is_a?(Hash)
|
@@ -36,7 +43,7 @@ module GraphQL
|
|
36
43
|
end
|
37
44
|
schema_definition = schema_defns.first
|
38
45
|
types = {}
|
39
|
-
directives =
|
46
|
+
directives = schema_superclass.directives.dup
|
40
47
|
type_resolver = build_resolve_type(types, directives, ->(type_name) { types[type_name] ||= Schema::LateBoundType.new(type_name)})
|
41
48
|
# Make a different type resolver because we need to coerce directive arguments
|
42
49
|
# _while_ building the schema.
|
@@ -55,21 +62,24 @@ module GraphQL
|
|
55
62
|
end
|
56
63
|
})
|
57
64
|
|
65
|
+
directives.merge!(GraphQL::Schema.default_directives)
|
58
66
|
document.definitions.each do |definition|
|
59
67
|
if definition.is_a?(GraphQL::Language::Nodes::DirectiveDefinition)
|
60
68
|
directives[definition.name] = build_directive(definition, directive_type_resolver)
|
61
69
|
end
|
62
70
|
end
|
63
71
|
|
64
|
-
directives = GraphQL::Schema.default_directives.merge(directives)
|
65
|
-
|
66
72
|
# In case any directives referenced built-in types for their arguments:
|
67
73
|
replace_late_bound_types_with_built_in(types)
|
68
74
|
|
75
|
+
schema_extensions = nil
|
69
76
|
document.definitions.each do |definition|
|
70
77
|
case definition
|
71
78
|
when GraphQL::Language::Nodes::SchemaDefinition, GraphQL::Language::Nodes::DirectiveDefinition
|
72
79
|
nil # already handled
|
80
|
+
when GraphQL::Language::Nodes::SchemaExtension
|
81
|
+
schema_extensions ||= []
|
82
|
+
schema_extensions << definition
|
73
83
|
else
|
74
84
|
# It's possible that this was already loaded by the directives
|
75
85
|
prev_type = types[definition.name]
|
@@ -96,6 +106,16 @@ module GraphQL
|
|
96
106
|
raise InvalidDocumentError.new("Specified subscription type \"#{schema_definition.subscription}\" not found in document.") unless types[schema_definition.subscription]
|
97
107
|
subscription_root_type = types[schema_definition.subscription]
|
98
108
|
end
|
109
|
+
|
110
|
+
if schema_definition.query.nil? &&
|
111
|
+
schema_definition.mutation.nil? &&
|
112
|
+
schema_definition.subscription.nil?
|
113
|
+
# This schema may have been given with directives only,
|
114
|
+
# check for defaults:
|
115
|
+
query_root_type = types['Query']
|
116
|
+
mutation_root_type = types['Mutation']
|
117
|
+
subscription_root_type = types['Subscription']
|
118
|
+
end
|
99
119
|
else
|
100
120
|
query_root_type = types['Query']
|
101
121
|
mutation_root_type = types['Mutation']
|
@@ -104,10 +124,14 @@ module GraphQL
|
|
104
124
|
|
105
125
|
raise InvalidDocumentError.new('Must provide schema definition with query type or a type named Query.') unless query_root_type
|
106
126
|
|
107
|
-
|
127
|
+
builder = self
|
128
|
+
|
129
|
+
found_types = types.values
|
130
|
+
schema_class = Class.new(schema_superclass) do
|
108
131
|
begin
|
109
132
|
# Add these first so that there's some chance of resolving late-bound types
|
110
|
-
|
133
|
+
add_type_and_traverse(found_types, root: false)
|
134
|
+
orphan_types(found_types.select { |t| t.respond_to?(:kind) && t.kind.object? })
|
111
135
|
query query_root_type
|
112
136
|
mutation mutation_root_type
|
113
137
|
subscription subscription_root_type
|
@@ -131,6 +155,7 @@ module GraphQL
|
|
131
155
|
|
132
156
|
if schema_definition
|
133
157
|
ast_node(schema_definition)
|
158
|
+
builder.build_directives(self, schema_definition, type_resolver)
|
134
159
|
end
|
135
160
|
|
136
161
|
using.each do |plugin, options|
|
@@ -158,6 +183,14 @@ module GraphQL
|
|
158
183
|
child_class.definition_default_resolve = self.definition_default_resolve
|
159
184
|
end
|
160
185
|
end
|
186
|
+
|
187
|
+
if schema_extensions
|
188
|
+
schema_extensions.each do |ext|
|
189
|
+
build_directives(schema_class, ext, type_resolver)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
schema_class
|
161
194
|
end
|
162
195
|
|
163
196
|
NullResolveType = ->(type, obj, ctx) {
|
@@ -197,13 +230,18 @@ module GraphQL
|
|
197
230
|
|
198
231
|
def build_directives(definition, ast_node, type_resolver)
|
199
232
|
dirs = prepare_directives(ast_node, type_resolver)
|
200
|
-
dirs.each do |dir_class, options|
|
201
|
-
definition.
|
233
|
+
dirs.each do |(dir_class, options)|
|
234
|
+
if definition.respond_to?(:schema_directive)
|
235
|
+
# it's a schema
|
236
|
+
definition.schema_directive(dir_class, **options)
|
237
|
+
else
|
238
|
+
definition.directive(dir_class, **options)
|
239
|
+
end
|
202
240
|
end
|
203
241
|
end
|
204
242
|
|
205
243
|
def prepare_directives(ast_node, type_resolver)
|
206
|
-
dirs =
|
244
|
+
dirs = []
|
207
245
|
ast_node.directives.each do |dir_node|
|
208
246
|
if dir_node.name == "deprecated"
|
209
247
|
# This is handled using `deprecation_reason`
|
@@ -211,10 +249,10 @@ module GraphQL
|
|
211
249
|
else
|
212
250
|
dir_class = type_resolver.call(dir_node.name)
|
213
251
|
if dir_class.nil?
|
214
|
-
raise ArgumentError, "No definition for @#{dir_node.name} on #{ast_node.name} at #{ast_node.line}:#{ast_node.col}"
|
252
|
+
raise ArgumentError, "No definition for @#{dir_node.name} #{ast_node.respond_to?(:name) ? "on #{ast_node.name} " : ""}at #{ast_node.line}:#{ast_node.col}"
|
215
253
|
end
|
216
254
|
options = args_to_kwargs(dir_class, dir_node)
|
217
|
-
dirs[dir_class
|
255
|
+
dirs << [dir_class, options]
|
218
256
|
end
|
219
257
|
end
|
220
258
|
dirs
|
@@ -345,8 +383,6 @@ module GraphQL
|
|
345
383
|
end
|
346
384
|
end
|
347
385
|
|
348
|
-
NO_DEFAULT_VALUE = {}.freeze
|
349
|
-
|
350
386
|
def build_arguments(type_class, arguments, type_resolver)
|
351
387
|
builder = self
|
352
388
|
|
@@ -354,7 +390,7 @@ module GraphQL
|
|
354
390
|
default_value_kwargs = if !argument_defn.default_value.nil?
|
355
391
|
{ default_value: builder.build_default_value(argument_defn.default_value) }
|
356
392
|
else
|
357
|
-
|
393
|
+
EMPTY_HASH
|
358
394
|
end
|
359
395
|
|
360
396
|
type_class.argument(
|
@@ -390,7 +426,6 @@ module GraphQL
|
|
390
426
|
graphql_name(interface_type_definition.name)
|
391
427
|
description(interface_type_definition.description)
|
392
428
|
interface_type_definition.interfaces.each do |interface_name|
|
393
|
-
"Implements: #{interface_type_definition} -> #{interface_name}"
|
394
429
|
interface_defn = type_resolver.call(interface_name)
|
395
430
|
implements(interface_defn)
|
396
431
|
end
|
@@ -405,14 +440,12 @@ module GraphQL
|
|
405
440
|
builder = self
|
406
441
|
|
407
442
|
field_definitions.each do |field_definition|
|
408
|
-
type_name = resolve_type_name(field_definition.type)
|
409
443
|
resolve_method_name = -"resolve_field_#{field_definition.name}"
|
410
444
|
schema_field_defn = owner.field(
|
411
445
|
field_definition.name,
|
412
446
|
description: field_definition.description,
|
413
447
|
type: type_resolver.call(field_definition.type),
|
414
448
|
null: true,
|
415
|
-
connection: type_name.end_with?("Connection"),
|
416
449
|
connection_extension: nil,
|
417
450
|
deprecation_reason: build_deprecation_reason(field_definition.directives),
|
418
451
|
ast_node: field_definition,
|
@@ -460,15 +493,6 @@ module GraphQL
|
|
460
493
|
}
|
461
494
|
resolve_type_proc
|
462
495
|
end
|
463
|
-
|
464
|
-
def resolve_type_name(type)
|
465
|
-
case type
|
466
|
-
when GraphQL::Language::Nodes::TypeName
|
467
|
-
return type.name
|
468
|
-
else
|
469
|
-
resolve_type_name(type.of_type)
|
470
|
-
end
|
471
|
-
end
|
472
496
|
end
|
473
497
|
|
474
498
|
private_constant :Builder
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
class Schema
|
4
|
+
class Directive < GraphQL::Schema::Member
|
5
|
+
class OneOf < GraphQL::Schema::Directive
|
6
|
+
description "Requires that exactly one field must be supplied and that field must not be `null`."
|
7
|
+
locations(GraphQL::Schema::Directive::INPUT_OBJECT)
|
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
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
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
|
@@ -39,7 +39,7 @@ module GraphQL
|
|
39
39
|
transform_name = arguments[:by]
|
40
40
|
if TRANSFORMS.include?(transform_name) && return_value.respond_to?(transform_name)
|
41
41
|
return_value = return_value.public_send(transform_name)
|
42
|
-
response = context.namespace(:
|
42
|
+
response = context.namespace(:interpreter_runtime)[:runtime].final_result
|
43
43
|
*keys, last = path
|
44
44
|
keys.each do |key|
|
45
45
|
if response && (response = response[key])
|
@@ -8,6 +8,7 @@ module GraphQL
|
|
8
8
|
# - {.resolve}: Wraps field resolution (so it should call `yield` to continue)
|
9
9
|
class Directive < GraphQL::Schema::Member
|
10
10
|
extend GraphQL::Schema::Member::HasArguments
|
11
|
+
extend GraphQL::Schema::Member::HasArguments::HasDirectiveArguments
|
11
12
|
|
12
13
|
class << self
|
13
14
|
# Directives aren't types, they don't have kinds.
|
@@ -21,9 +22,9 @@ module GraphQL
|
|
21
22
|
# but downcase the first letter.
|
22
23
|
def default_graphql_name
|
23
24
|
@default_graphql_name ||= begin
|
24
|
-
camelized_name = super
|
25
|
+
camelized_name = super.dup
|
25
26
|
camelized_name[0] = camelized_name[0].downcase
|
26
|
-
camelized_name
|
27
|
+
-camelized_name
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
@@ -93,6 +94,15 @@ module GraphQL
|
|
93
94
|
def repeatable(new_value)
|
94
95
|
@repeatable = new_value
|
95
96
|
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def inherited(subclass)
|
101
|
+
super
|
102
|
+
subclass.class_eval do
|
103
|
+
@default_graphql_name ||= nil
|
104
|
+
end
|
105
|
+
end
|
96
106
|
end
|
97
107
|
|
98
108
|
# @return [GraphQL::Schema::Field, GraphQL::Schema::Argument, Class, Module]
|
@@ -109,7 +119,7 @@ module GraphQL
|
|
109
119
|
# - lazy resolution
|
110
120
|
# Probably, those won't be needed here, since these are configuration arguments,
|
111
121
|
# not runtime arguments.
|
112
|
-
@arguments = self.class.coerce_arguments(nil, arguments, Query::NullContext)
|
122
|
+
@arguments = self.class.coerce_arguments(nil, arguments, Query::NullContext.instance)
|
113
123
|
end
|
114
124
|
|
115
125
|
def graphql_name
|
@@ -178,6 +188,8 @@ module GraphQL
|
|
178
188
|
assert_has_location(SCALAR)
|
179
189
|
elsif @owner < GraphQL::Schema
|
180
190
|
assert_has_location(SCHEMA)
|
191
|
+
elsif @owner < GraphQL::Schema::Resolver
|
192
|
+
assert_has_location(FIELD_DEFINITION)
|
181
193
|
else
|
182
194
|
raise "Unexpected directive owner class: #{@owner}"
|
183
195
|
end
|
data/lib/graphql/schema/enum.rb
CHANGED
@@ -1,24 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module GraphQL
|
4
|
-
# Extend this class to define GraphQL enums in your schema.
|
5
|
-
#
|
6
|
-
# By default, GraphQL enum values are translated into Ruby strings.
|
7
|
-
# You can provide a custom value with the `value:` keyword.
|
8
|
-
#
|
9
|
-
# @example
|
10
|
-
# # equivalent to
|
11
|
-
# # enum PizzaTopping {
|
12
|
-
# # MUSHROOMS
|
13
|
-
# # ONIONS
|
14
|
-
# # PEPPERS
|
15
|
-
# # }
|
16
|
-
# class PizzaTopping < GraphQL::Enum
|
17
|
-
# value :MUSHROOMS
|
18
|
-
# value :ONIONS
|
19
|
-
# value :PEPPERS
|
20
|
-
# end
|
21
4
|
class Schema
|
5
|
+
# Extend this class to define GraphQL enums in your schema.
|
6
|
+
#
|
7
|
+
# By default, GraphQL enum values are translated into Ruby strings.
|
8
|
+
# You can provide a custom value with the `value:` keyword.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# # equivalent to
|
12
|
+
# # enum PizzaTopping {
|
13
|
+
# # MUSHROOMS
|
14
|
+
# # ONIONS
|
15
|
+
# # PEPPERS
|
16
|
+
# # }
|
17
|
+
# class PizzaTopping < GraphQL::Schema::Enum
|
18
|
+
# value :MUSHROOMS
|
19
|
+
# value :ONIONS
|
20
|
+
# value :PEPPERS
|
21
|
+
# end
|
22
22
|
class Enum < GraphQL::Schema::Member
|
23
23
|
extend GraphQL::Schema::Member::ValidatesInput
|
24
24
|
|
@@ -34,6 +34,13 @@ module GraphQL
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
+
class MissingValuesError < GraphQL::Error
|
38
|
+
def initialize(enum_type)
|
39
|
+
@enum_type = enum_type
|
40
|
+
super("Enum types require at least one value, but #{enum_type.graphql_name} didn't provide any for this query. Make sure at least one value is defined and visible for this query.")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
37
44
|
class << self
|
38
45
|
# Define a value for this enum
|
39
46
|
# @param graphql_name [String, Symbol] the GraphQL value for this, usually `SCREAMING_CASE`
|
@@ -61,7 +68,7 @@ module GraphQL
|
|
61
68
|
end
|
62
69
|
|
63
70
|
# @return [Array<GraphQL::Schema::EnumValue>] Possible values of this enum
|
64
|
-
def enum_values(context = GraphQL::Query::NullContext)
|
71
|
+
def enum_values(context = GraphQL::Query::NullContext.instance)
|
65
72
|
inherited_values = superclass.respond_to?(:enum_values) ? superclass.enum_values(context) : nil
|
66
73
|
visible_values = []
|
67
74
|
warden = Warden.from_context(context)
|
@@ -103,7 +110,7 @@ module GraphQL
|
|
103
110
|
end
|
104
111
|
|
105
112
|
# @return [Hash<String => GraphQL::Schema::EnumValue>] Possible values of this enum, keyed by name.
|
106
|
-
def values(context = GraphQL::Query::NullContext)
|
113
|
+
def values(context = GraphQL::Query::NullContext.instance)
|
107
114
|
enum_values(context).each_with_object({}) { |val, obj| obj[val.graphql_name] = val }
|
108
115
|
end
|
109
116
|
|
@@ -123,7 +130,7 @@ module GraphQL
|
|
123
130
|
end
|
124
131
|
|
125
132
|
def validate_non_null_input(value_name, ctx, max_errors: nil)
|
126
|
-
allowed_values = ctx.
|
133
|
+
allowed_values = ctx.types.enum_values(self)
|
127
134
|
matching_value = allowed_values.find { |v| v.graphql_name == value_name }
|
128
135
|
|
129
136
|
if matching_value.nil?
|
@@ -134,8 +141,8 @@ module GraphQL
|
|
134
141
|
end
|
135
142
|
|
136
143
|
def coerce_result(value, ctx)
|
137
|
-
|
138
|
-
all_values =
|
144
|
+
types = ctx.types
|
145
|
+
all_values = types ? types.enum_values(self) : values.each_value
|
139
146
|
enum_value = all_values.find { |val| val.value == value }
|
140
147
|
if enum_value
|
141
148
|
enum_value.graphql_name
|
@@ -145,7 +152,7 @@ module GraphQL
|
|
145
152
|
end
|
146
153
|
|
147
154
|
def coerce_input(value_name, ctx)
|
148
|
-
all_values = ctx.
|
155
|
+
all_values = ctx.types ? ctx.types.enum_values(self) : values.each_value
|
149
156
|
|
150
157
|
if v = all_values.find { |val| val.graphql_name == value_name }
|
151
158
|
v.value
|
@@ -159,7 +166,11 @@ module GraphQL
|
|
159
166
|
end
|
160
167
|
|
161
168
|
def inherited(child_class)
|
162
|
-
child_class.
|
169
|
+
if child_class.name
|
170
|
+
# Don't assign a custom error class to anonymous classes
|
171
|
+
# because they would end up with names like `#<Class0x1234>::UnresolvedValueError` which messes up bug trackers
|
172
|
+
child_class.const_set(:UnresolvedValueError, Class.new(Schema::Enum::UnresolvedValueError))
|
173
|
+
end
|
163
174
|
super
|
164
175
|
end
|
165
176
|
|
@@ -30,11 +30,11 @@ module GraphQL
|
|
30
30
|
# @return [Class] The enum type that owns this value
|
31
31
|
attr_reader :owner
|
32
32
|
|
33
|
-
def initialize(graphql_name, desc = nil, owner:, ast_node: nil, directives: nil, description: nil, value:
|
33
|
+
def initialize(graphql_name, desc = nil, owner:, ast_node: nil, directives: nil, description: nil, value: NOT_CONFIGURED, deprecation_reason: nil, &block)
|
34
34
|
@graphql_name = graphql_name.to_s
|
35
35
|
GraphQL::NameValidator.validate!(@graphql_name)
|
36
36
|
@description = desc || description
|
37
|
-
@value = value
|
37
|
+
@value = value == NOT_CONFIGURED ? @graphql_name : value
|
38
38
|
if deprecation_reason
|
39
39
|
self.deprecation_reason = deprecation_reason
|
40
40
|
end
|
@@ -70,7 +70,6 @@ module GraphQL
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def visible?(_ctx); true; end
|
73
|
-
def accessible?(_ctx); true; end
|
74
73
|
def authorized?(_ctx); true; end
|
75
74
|
end
|
76
75
|
end
|