graphql 2.0.13 → 2.3.10
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/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
|