graphql 1.11.6 → 1.12.3
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_generator.rb +5 -5
- data/lib/generators/graphql/object_generator.rb +2 -0
- data/lib/generators/graphql/relay_generator.rb +63 -0
- data/lib/generators/graphql/templates/base_connection.erb +8 -0
- data/lib/generators/graphql/templates/base_edge.erb +8 -0
- data/lib/generators/graphql/templates/node_type.erb +9 -0
- data/lib/generators/graphql/templates/object.erb +1 -1
- data/lib/generators/graphql/templates/query_type.erb +1 -3
- data/lib/generators/graphql/templates/schema.erb +8 -35
- data/lib/graphql.rb +39 -4
- data/lib/graphql/analysis/analyze_query.rb +7 -0
- data/lib/graphql/analysis/ast.rb +11 -2
- data/lib/graphql/analysis/ast/visitor.rb +9 -1
- data/lib/graphql/backtrace.rb +28 -19
- data/lib/graphql/backtrace/legacy_tracer.rb +56 -0
- data/lib/graphql/backtrace/table.rb +22 -2
- data/lib/graphql/backtrace/tracer.rb +40 -9
- data/lib/graphql/backwards_compatibility.rb +2 -1
- data/lib/graphql/base_type.rb +1 -1
- data/lib/graphql/compatibility/execution_specification.rb +1 -0
- data/lib/graphql/compatibility/lazy_execution_specification.rb +2 -0
- data/lib/graphql/compatibility/query_parser_specification.rb +2 -0
- data/lib/graphql/compatibility/schema_parser_specification.rb +2 -0
- data/lib/graphql/dataloader.rb +198 -0
- data/lib/graphql/dataloader/null_dataloader.rb +21 -0
- data/lib/graphql/dataloader/request.rb +24 -0
- data/lib/graphql/dataloader/request_all.rb +22 -0
- data/lib/graphql/dataloader/source.rb +93 -0
- data/lib/graphql/define/assign_global_id_field.rb +1 -1
- data/lib/graphql/define/instance_definable.rb +32 -2
- data/lib/graphql/define/type_definer.rb +5 -5
- data/lib/graphql/deprecated_dsl.rb +7 -2
- data/lib/graphql/deprecation.rb +13 -0
- data/lib/graphql/enum_type.rb +2 -0
- data/lib/graphql/execution/errors.rb +4 -0
- data/lib/graphql/execution/execute.rb +7 -0
- data/lib/graphql/execution/interpreter.rb +10 -6
- data/lib/graphql/execution/interpreter/arguments.rb +57 -5
- data/lib/graphql/execution/interpreter/arguments_cache.rb +8 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +0 -7
- data/lib/graphql/execution/interpreter/runtime.rb +219 -117
- data/lib/graphql/execution/multiplex.rb +20 -6
- data/lib/graphql/function.rb +4 -0
- data/lib/graphql/input_object_type.rb +2 -0
- data/lib/graphql/integer_decoding_error.rb +17 -0
- data/lib/graphql/interface_type.rb +3 -1
- data/lib/graphql/internal_representation/document.rb +2 -2
- data/lib/graphql/internal_representation/rewrite.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +50 -23
- data/lib/graphql/object_type.rb +2 -0
- data/lib/graphql/pagination/connection.rb +5 -1
- data/lib/graphql/pagination/connections.rb +6 -16
- data/lib/graphql/query.rb +6 -1
- data/lib/graphql/query/arguments.rb +1 -1
- data/lib/graphql/query/context.rb +8 -1
- data/lib/graphql/query/serial_execution.rb +1 -0
- data/lib/graphql/query/validation_pipeline.rb +1 -1
- data/lib/graphql/relay/array_connection.rb +2 -2
- data/lib/graphql/relay/base_connection.rb +7 -0
- data/lib/graphql/relay/connection_instrumentation.rb +4 -4
- data/lib/graphql/relay/connection_type.rb +1 -1
- data/lib/graphql/relay/mutation.rb +1 -0
- data/lib/graphql/relay/node.rb +3 -0
- data/lib/graphql/relay/type_extensions.rb +2 -0
- data/lib/graphql/scalar_type.rb +2 -0
- data/lib/graphql/schema.rb +80 -29
- data/lib/graphql/schema/argument.rb +25 -7
- data/lib/graphql/schema/build_from_definition.rb +139 -51
- data/lib/graphql/schema/default_type_error.rb +2 -0
- data/lib/graphql/schema/directive.rb +76 -0
- data/lib/graphql/schema/directive/flagged.rb +57 -0
- data/lib/graphql/schema/enum.rb +3 -0
- data/lib/graphql/schema/enum_value.rb +12 -6
- data/lib/graphql/schema/field.rb +50 -22
- data/lib/graphql/schema/field/connection_extension.rb +3 -2
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/input_object.rb +33 -22
- data/lib/graphql/schema/interface.rb +1 -0
- data/lib/graphql/schema/member.rb +4 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +1 -0
- data/lib/graphql/schema/member/build_type.rb +3 -3
- data/lib/graphql/schema/member/has_arguments.rb +67 -50
- data/lib/graphql/schema/member/has_deprecation_reason.rb +25 -0
- data/lib/graphql/schema/member/has_directives.rb +98 -0
- data/lib/graphql/schema/member/has_validators.rb +31 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +1 -1
- data/lib/graphql/schema/middleware_chain.rb +1 -1
- data/lib/graphql/schema/object.rb +11 -0
- data/lib/graphql/schema/printer.rb +5 -4
- data/lib/graphql/schema/relay_classic_mutation.rb +1 -1
- data/lib/graphql/schema/resolver.rb +7 -0
- data/lib/graphql/schema/resolver/has_payload_type.rb +2 -0
- data/lib/graphql/schema/subscription.rb +19 -1
- data/lib/graphql/schema/timeout_middleware.rb +3 -1
- data/lib/graphql/schema/validation.rb +4 -2
- data/lib/graphql/schema/validator.rb +163 -0
- data/lib/graphql/schema/validator/exclusion_validator.rb +31 -0
- data/lib/graphql/schema/validator/format_validator.rb +49 -0
- data/lib/graphql/schema/validator/inclusion_validator.rb +33 -0
- data/lib/graphql/schema/validator/length_validator.rb +57 -0
- data/lib/graphql/schema/validator/numericality_validator.rb +71 -0
- data/lib/graphql/schema/validator/required_validator.rb +68 -0
- data/lib/graphql/static_validation.rb +1 -0
- data/lib/graphql/static_validation/all_rules.rb +1 -0
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +25 -17
- data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +30 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +30 -0
- data/lib/graphql/static_validation/validation_timeout_error.rb +25 -0
- data/lib/graphql/static_validation/validator.rb +32 -9
- data/lib/graphql/subscriptions.rb +17 -20
- data/lib/graphql/subscriptions/subscription_root.rb +1 -1
- data/lib/graphql/tracing.rb +2 -2
- data/lib/graphql/tracing/appoptics_tracing.rb +3 -1
- data/lib/graphql/tracing/platform_tracing.rb +4 -2
- data/lib/graphql/tracing/prometheus_tracing/graphql_collector.rb +4 -1
- data/lib/graphql/tracing/skylight_tracing.rb +1 -1
- data/lib/graphql/types/int.rb +9 -2
- data/lib/graphql/types/relay.rb +11 -3
- data/lib/graphql/types/relay/base_connection.rb +2 -91
- data/lib/graphql/types/relay/base_edge.rb +2 -34
- data/lib/graphql/types/relay/connection_behaviors.rb +123 -0
- data/lib/graphql/types/relay/default_relay.rb +27 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +42 -0
- data/lib/graphql/types/relay/has_node_field.rb +41 -0
- data/lib/graphql/types/relay/has_nodes_field.rb +41 -0
- data/lib/graphql/types/relay/node.rb +2 -4
- data/lib/graphql/types/relay/node_behaviors.rb +15 -0
- data/lib/graphql/types/relay/node_field.rb +1 -19
- data/lib/graphql/types/relay/nodes_field.rb +1 -19
- data/lib/graphql/types/relay/page_info.rb +2 -14
- data/lib/graphql/types/relay/page_info_behaviors.rb +25 -0
- data/lib/graphql/types/string.rb +7 -1
- data/lib/graphql/union_type.rb +2 -0
- data/lib/graphql/upgrader/member.rb +1 -0
- data/lib/graphql/upgrader/schema.rb +1 -0
- data/lib/graphql/version.rb +1 -1
- data/readme.md +1 -1
- metadata +53 -9
- data/lib/graphql/types/relay/base_field.rb +0 -22
- data/lib/graphql/types/relay/base_interface.rb +0 -29
- data/lib/graphql/types/relay/base_object.rb +0 -26
data/lib/graphql/schema/enum.rb
CHANGED
@@ -37,6 +37,9 @@ module GraphQL
|
|
37
37
|
def value(*args, **kwargs, &block)
|
38
38
|
kwargs[:owner] = self
|
39
39
|
value = enum_value_class.new(*args, **kwargs, &block)
|
40
|
+
if own_values.key?(value.graphql_name)
|
41
|
+
raise ArgumentError, "#{value.graphql_name} is already defined for #{self.graphql_name}, please remove one of the definitions."
|
42
|
+
end
|
40
43
|
own_values[value.graphql_name] = value
|
41
44
|
nil
|
42
45
|
end
|
@@ -30,23 +30,29 @@ module GraphQL
|
|
30
30
|
include GraphQL::Schema::Member::AcceptsDefinition
|
31
31
|
include GraphQL::Schema::Member::HasPath
|
32
32
|
include GraphQL::Schema::Member::HasAstNode
|
33
|
+
include GraphQL::Schema::Member::HasDirectives
|
34
|
+
include GraphQL::Schema::Member::HasDeprecationReason
|
33
35
|
|
34
36
|
attr_reader :graphql_name
|
35
37
|
|
36
38
|
# @return [Class] The enum type that owns this value
|
37
39
|
attr_reader :owner
|
38
40
|
|
39
|
-
|
40
|
-
attr_accessor :deprecation_reason
|
41
|
-
|
42
|
-
def initialize(graphql_name, desc = nil, owner:, ast_node: nil, description: nil, value: nil, deprecation_reason: nil, &block)
|
41
|
+
def initialize(graphql_name, desc = nil, owner:, ast_node: nil, directives: nil, description: nil, value: nil, deprecation_reason: nil, &block)
|
43
42
|
@graphql_name = graphql_name.to_s
|
44
43
|
GraphQL::NameValidator.validate!(@graphql_name)
|
45
44
|
@description = desc || description
|
46
45
|
@value = value.nil? ? @graphql_name : value
|
47
|
-
|
46
|
+
if deprecation_reason
|
47
|
+
self.deprecation_reason = deprecation_reason
|
48
|
+
end
|
48
49
|
@owner = owner
|
49
50
|
@ast_node = ast_node
|
51
|
+
if directives
|
52
|
+
directives.each do |dir_class, dir_options|
|
53
|
+
directive(dir_class, **dir_options)
|
54
|
+
end
|
55
|
+
end
|
50
56
|
|
51
57
|
if block_given?
|
52
58
|
instance_eval(&block)
|
@@ -73,7 +79,7 @@ module GraphQL
|
|
73
79
|
enum_value.name = @graphql_name
|
74
80
|
enum_value.description = @description
|
75
81
|
enum_value.value = @value
|
76
|
-
enum_value.deprecation_reason =
|
82
|
+
enum_value.deprecation_reason = self.deprecation_reason
|
77
83
|
enum_value.metadata[:type_class] = self
|
78
84
|
enum_value.ast_node = ast_node
|
79
85
|
enum_value
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -15,8 +15,11 @@ module GraphQL
|
|
15
15
|
include GraphQL::Schema::Member::HasArguments
|
16
16
|
include GraphQL::Schema::Member::HasAstNode
|
17
17
|
include GraphQL::Schema::Member::HasPath
|
18
|
+
include GraphQL::Schema::Member::HasValidators
|
18
19
|
extend GraphQL::Schema::FindInheritedValue
|
19
20
|
include GraphQL::Schema::FindInheritedValue::EmptyObjects
|
21
|
+
include GraphQL::Schema::Member::HasDirectives
|
22
|
+
include GraphQL::Schema::Member::HasDeprecationReason
|
20
23
|
|
21
24
|
# @return [String] the GraphQL name for this field, camelized unless `camelize: false` is provided
|
22
25
|
attr_reader :name
|
@@ -24,9 +27,6 @@ module GraphQL
|
|
24
27
|
|
25
28
|
attr_writer :description
|
26
29
|
|
27
|
-
# @return [String, nil] If present, the field is marked as deprecated with this documentation
|
28
|
-
attr_accessor :deprecation_reason
|
29
|
-
|
30
30
|
# @return [Symbol] Method or hash key on the underlying object to look up
|
31
31
|
attr_reader :method_sym
|
32
32
|
|
@@ -82,11 +82,11 @@ module GraphQL
|
|
82
82
|
# @see {.initialize} for other options
|
83
83
|
def self.from_options(name = nil, type = nil, desc = nil, resolver: nil, mutation: nil, subscription: nil,**kwargs, &block)
|
84
84
|
if kwargs[:field]
|
85
|
-
if kwargs[:field] == GraphQL::Relay::
|
86
|
-
warn("Legacy-style `GraphQL::Relay::Node.field` is being added to a class-based type. See `GraphQL::Types::Relay::NodeField` for a replacement.")
|
85
|
+
if kwargs[:field].is_a?(GraphQL::Field) && kwargs[:field] == GraphQL::Types::Relay::NodeField.graphql_definition
|
86
|
+
GraphQL::Deprecation.warn("Legacy-style `GraphQL::Relay::Node.field` is being added to a class-based type. See `GraphQL::Types::Relay::NodeField` for a replacement.")
|
87
87
|
return GraphQL::Types::Relay::NodeField
|
88
|
-
elsif kwargs[:field] == GraphQL::Relay::
|
89
|
-
warn("Legacy-style `GraphQL::Relay::Node.plural_field` is being added to a class-based type. See `GraphQL::Types::Relay::NodesField` for a replacement.")
|
88
|
+
elsif kwargs[:field].is_a?(GraphQL::Field) && kwargs[:field] == GraphQL::Types::Relay::NodesField.graphql_definition
|
89
|
+
GraphQL::Deprecation.warn("Legacy-style `GraphQL::Relay::Node.plural_field` is being added to a class-based type. See `GraphQL::Types::Relay::NodesField` for a replacement.")
|
90
90
|
return GraphQL::Types::Relay::NodesField
|
91
91
|
end
|
92
92
|
end
|
@@ -199,11 +199,14 @@ module GraphQL
|
|
199
199
|
# @param scope [Boolean] If true, the return type's `.scope_items` method will be called on the return value
|
200
200
|
# @param subscription_scope [Symbol, String] A key in `context` which will be used to scope subscription payloads
|
201
201
|
# @param extensions [Array<Class, Hash<Class => Object>>] Named extensions to apply to this field (see also {#extension})
|
202
|
+
# @param directives [Hash{Class => Hash}] Directives to apply to this field
|
202
203
|
# @param trace [Boolean] If true, a {GraphQL::Tracing} tracer will measure this scalar field
|
203
204
|
# @param broadcastable [Boolean] Whether or not this field can be distributed in subscription broadcasts
|
204
205
|
# @param ast_node [Language::Nodes::FieldDefinition, nil] If this schema was parsed from definition, this AST node defined the field
|
205
206
|
# @param method_conflict_warning [Boolean] If false, skip the warning if this field's method conflicts with a built-in method
|
206
|
-
|
207
|
+
# @param validates [Array<Hash>] Configurations for validating this field
|
208
|
+
# @param legacy_edge_class [Class, nil] (DEPRECATED) If present, pass this along to the legacy field definition
|
209
|
+
def initialize(type: nil, name: nil, owner: nil, null: nil, field: nil, function: nil, description: nil, deprecation_reason: nil, method: nil, hash_key: nil, resolver_method: nil, resolve: nil, connection: nil, max_page_size: :not_given, scope: nil, introspection: false, camelize: true, trace: nil, complexity: 1, 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: nil, arguments: EMPTY_HASH, directives: EMPTY_HASH, validates: EMPTY_ARRAY, legacy_edge_class: nil, &definition_block)
|
207
210
|
if name.nil?
|
208
211
|
raise ArgumentError, "missing first `name` argument or keyword `name:`"
|
209
212
|
end
|
@@ -230,7 +233,7 @@ module GraphQL
|
|
230
233
|
end
|
231
234
|
@function = function
|
232
235
|
@resolve = resolve
|
233
|
-
|
236
|
+
self.deprecation_reason = deprecation_reason
|
234
237
|
|
235
238
|
if method && hash_key
|
236
239
|
raise ArgumentError, "Provide `method:` _or_ `hash_key:`, not both. (called with: `method: #{method.inspect}, hash_key: #{hash_key.inspect}`)"
|
@@ -269,6 +272,7 @@ module GraphQL
|
|
269
272
|
@relay_nodes_field = relay_nodes_field
|
270
273
|
@ast_node = ast_node
|
271
274
|
@method_conflict_warning = method_conflict_warning
|
275
|
+
@legacy_edge_class = legacy_edge_class
|
272
276
|
|
273
277
|
arguments.each do |name, arg|
|
274
278
|
if arg.is_a?(Hash)
|
@@ -297,6 +301,14 @@ module GraphQL
|
|
297
301
|
self.extension(connection_extension)
|
298
302
|
end
|
299
303
|
|
304
|
+
if directives.any?
|
305
|
+
directives.each do |(dir_class, options)|
|
306
|
+
self.directive(dir_class, **options)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
self.validates(validates)
|
311
|
+
|
300
312
|
if definition_block
|
301
313
|
if definition_block.arity == 1
|
302
314
|
yield self
|
@@ -438,8 +450,8 @@ module GraphQL
|
|
438
450
|
field_defn.description = @description
|
439
451
|
end
|
440
452
|
|
441
|
-
if
|
442
|
-
field_defn.deprecation_reason =
|
453
|
+
if self.deprecation_reason
|
454
|
+
field_defn.deprecation_reason = self.deprecation_reason
|
443
455
|
end
|
444
456
|
|
445
457
|
if @resolver_class
|
@@ -461,6 +473,10 @@ module GraphQL
|
|
461
473
|
field_defn.relay_nodes_field = @relay_nodes_field
|
462
474
|
end
|
463
475
|
|
476
|
+
if @legacy_edge_class
|
477
|
+
field_defn.edge_class = @legacy_edge_class
|
478
|
+
end
|
479
|
+
|
464
480
|
field_defn.resolve = self.method(:resolve_field)
|
465
481
|
field_defn.connection = connection?
|
466
482
|
field_defn.connection_max_page_size = max_page_size
|
@@ -580,6 +596,9 @@ module GraphQL
|
|
580
596
|
begin
|
581
597
|
# Unwrap the GraphQL object to get the application object.
|
582
598
|
application_object = object.object
|
599
|
+
|
600
|
+
Schema::Validator.validate!(validators, application_object, ctx, args)
|
601
|
+
|
583
602
|
ctx.schema.after_lazy(self.authorized?(application_object, args, ctx)) do |is_authorized|
|
584
603
|
if is_authorized
|
585
604
|
public_send_field(object, args, ctx)
|
@@ -725,33 +744,42 @@ module GraphQL
|
|
725
744
|
if @extensions.empty?
|
726
745
|
yield(obj, args)
|
727
746
|
else
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
value = run_extensions_before_resolve(
|
733
|
-
extended_obj = obj
|
734
|
-
extended_args = args
|
747
|
+
# This is a hack to get the _last_ value for extended obj and args,
|
748
|
+
# in case one of the extensions doesn't `yield`.
|
749
|
+
# (There's another implementation that uses multiple-return, but I'm wary of the perf cost of the extra arrays)
|
750
|
+
extended = { args: args, obj: obj, memos: nil }
|
751
|
+
value = run_extensions_before_resolve(obj, args, ctx, extended) do |obj, args|
|
735
752
|
yield(obj, args)
|
736
753
|
end
|
737
754
|
|
755
|
+
extended_obj = extended[:obj]
|
756
|
+
extended_args = extended[:args]
|
757
|
+
memos = extended[:memos] || EMPTY_HASH
|
758
|
+
|
738
759
|
ctx.schema.after_lazy(value) do |resolved_value|
|
739
|
-
|
760
|
+
idx = 0
|
761
|
+
@extensions.each do |ext|
|
740
762
|
memo = memos[idx]
|
741
763
|
# TODO after_lazy?
|
742
764
|
resolved_value = ext.after_resolve(object: extended_obj, arguments: extended_args, context: ctx, value: resolved_value, memo: memo)
|
765
|
+
idx += 1
|
743
766
|
end
|
744
767
|
resolved_value
|
745
768
|
end
|
746
769
|
end
|
747
770
|
end
|
748
771
|
|
749
|
-
def run_extensions_before_resolve(
|
772
|
+
def run_extensions_before_resolve(obj, args, ctx, extended, idx: 0)
|
750
773
|
extension = @extensions[idx]
|
751
774
|
if extension
|
752
775
|
extension.resolve(object: obj, arguments: args, context: ctx) do |extended_obj, extended_args, memo|
|
753
|
-
|
754
|
-
|
776
|
+
if memo
|
777
|
+
memos = extended[:memos] ||= {}
|
778
|
+
memos[idx] = memo
|
779
|
+
end
|
780
|
+
extended[:obj] = extended_obj
|
781
|
+
extended[:args] = extended_args
|
782
|
+
run_extensions_before_resolve(extended_obj, extended_args, ctx, extended, idx: idx + 1) { |o, a| yield(o, a) }
|
755
783
|
end
|
756
784
|
else
|
757
785
|
yield(obj, args)
|
@@ -42,6 +42,7 @@ module GraphQL
|
|
42
42
|
value.after_value ||= original_arguments[:after]
|
43
43
|
value.last_value ||= original_arguments[:last]
|
44
44
|
value.before_value ||= original_arguments[:before]
|
45
|
+
value.field ||= field
|
45
46
|
if field.has_max_page_size? && !value.has_max_page_size_override?
|
46
47
|
value.max_page_size = field.max_page_size
|
47
48
|
end
|
@@ -50,8 +51,8 @@ module GraphQL
|
|
50
51
|
end
|
51
52
|
value
|
52
53
|
elsif context.schema.new_connections?
|
53
|
-
|
54
|
-
context.schema.connections.wrap(field, object.object, value, original_arguments, context
|
54
|
+
context.namespace(:connections)[:all_wrappers] ||= context.schema.connections.all_wrappers
|
55
|
+
context.schema.connections.wrap(field, object.object, value, original_arguments, context)
|
55
56
|
else
|
56
57
|
if object.is_a?(GraphQL::Schema::Object)
|
57
58
|
object = object.object
|
@@ -7,6 +7,7 @@ module GraphQL
|
|
7
7
|
extend GraphQL::Schema::Member::HasArguments
|
8
8
|
extend GraphQL::Schema::Member::HasArguments::ArgumentObjectLoader
|
9
9
|
extend GraphQL::Schema::Member::ValidatesInput
|
10
|
+
extend GraphQL::Schema::Member::HasValidators
|
10
11
|
|
11
12
|
include GraphQL::Dig
|
12
13
|
|
@@ -37,14 +38,15 @@ module GraphQL
|
|
37
38
|
load_application_object(arg_defn, loads, value, context)
|
38
39
|
end
|
39
40
|
maybe_lazies << context.schema.after_lazy(loaded_value) do |loaded_value|
|
40
|
-
|
41
|
+
overwrite_argument(ruby_kwargs_key, loaded_value)
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
44
45
|
# Weirdly, procs are applied during coercion, but not methods.
|
45
46
|
# Probably because these methods require a `self`.
|
46
47
|
if arg_defn.prepare.is_a?(Symbol) || context.nil? || !context.interpreter?
|
47
|
-
|
48
|
+
prepared_value = arg_defn.prepare_value(self, @ruby_style_hash[ruby_kwargs_key])
|
49
|
+
overwrite_argument(ruby_kwargs_key, prepared_value)
|
48
50
|
end
|
49
51
|
end
|
50
52
|
end
|
@@ -74,6 +76,9 @@ module GraphQL
|
|
74
76
|
def prepare
|
75
77
|
if context
|
76
78
|
context.schema.after_any_lazies(@maybe_lazies) do
|
79
|
+
object = context[:current_object]
|
80
|
+
# Pass this object's class with `as` so that messages are rendered correctly from inherited validators
|
81
|
+
Schema::Validator.validate!(self.class.validators, object, context, @ruby_style_hash, as: self.class)
|
77
82
|
self
|
78
83
|
end
|
79
84
|
else
|
@@ -168,17 +173,10 @@ module GraphQL
|
|
168
173
|
return result
|
169
174
|
end
|
170
175
|
|
171
|
-
input
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
# Handle ActionController::Parameters:
|
176
|
-
input.to_unsafe_h
|
177
|
-
rescue
|
178
|
-
# We're not sure it'll act like a hash, so reject it:
|
179
|
-
result.add_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
|
180
|
-
return result
|
181
|
-
end
|
176
|
+
if !(input.respond_to?(:to_h) || input.respond_to?(:to_unsafe_h))
|
177
|
+
# We're not sure it'll act like a hash, so reject it:
|
178
|
+
result.add_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
|
179
|
+
return result
|
182
180
|
end
|
183
181
|
|
184
182
|
# Inject missing required arguments
|
@@ -190,16 +188,19 @@ module GraphQL
|
|
190
188
|
m
|
191
189
|
end
|
192
190
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
191
|
+
|
192
|
+
[input, missing_required_inputs].each do |args_to_validate|
|
193
|
+
args_to_validate.each do |argument_name, value|
|
194
|
+
argument = warden.get_argument(self, argument_name)
|
195
|
+
# Items in the input that are unexpected
|
196
|
+
unless argument
|
197
|
+
result.add_problem("Field is not defined on #{self.graphql_name}", [argument_name])
|
198
|
+
next
|
199
|
+
end
|
200
|
+
# Items in the input that are expected, but have invalid values
|
201
|
+
argument_result = argument.type.validate_input(value, ctx)
|
202
|
+
result.merge_result!(argument_name, argument_result) unless argument_result.valid?
|
199
203
|
end
|
200
|
-
# Items in the input that are expected, but have invalid values
|
201
|
-
argument_result = argument.type.validate_input(value, ctx)
|
202
|
-
result.merge_result!(argument_name, argument_result) unless argument_result.valid?
|
203
204
|
end
|
204
205
|
|
205
206
|
result
|
@@ -240,6 +241,16 @@ module GraphQL
|
|
240
241
|
result
|
241
242
|
end
|
242
243
|
end
|
244
|
+
|
245
|
+
private
|
246
|
+
|
247
|
+
def overwrite_argument(key, value)
|
248
|
+
# Argument keywords come in frozen from the interpreter, dup them before modifying them.
|
249
|
+
if @ruby_style_hash.frozen?
|
250
|
+
@ruby_style_hash = @ruby_style_hash.dup
|
251
|
+
end
|
252
|
+
@ruby_style_hash[key] = value
|
253
|
+
end
|
243
254
|
end
|
244
255
|
end
|
245
256
|
end
|
@@ -15,6 +15,7 @@ module GraphQL
|
|
15
15
|
include GraphQL::Schema::Member::Scoped
|
16
16
|
include GraphQL::Schema::Member::HasAstNode
|
17
17
|
include GraphQL::Schema::Member::HasUnresolvedTypeError
|
18
|
+
include GraphQL::Schema::Member::HasDirectives
|
18
19
|
|
19
20
|
# Methods defined in this block will be:
|
20
21
|
# - Added as class methods to this interface
|
@@ -4,8 +4,11 @@ require 'graphql/schema/member/base_dsl_methods'
|
|
4
4
|
require 'graphql/schema/member/cached_graphql_definition'
|
5
5
|
require 'graphql/schema/member/graphql_type_names'
|
6
6
|
require 'graphql/schema/member/has_ast_node'
|
7
|
+
require 'graphql/schema/member/has_directives'
|
8
|
+
require 'graphql/schema/member/has_deprecation_reason'
|
7
9
|
require 'graphql/schema/member/has_path'
|
8
10
|
require 'graphql/schema/member/has_unresolved_type_error'
|
11
|
+
require 'graphql/schema/member/has_validators'
|
9
12
|
require 'graphql/schema/member/relay_shortcuts'
|
10
13
|
require 'graphql/schema/member/scoped'
|
11
14
|
require 'graphql/schema/member/type_system_helpers'
|
@@ -30,6 +33,7 @@ module GraphQL
|
|
30
33
|
extend RelayShortcuts
|
31
34
|
extend HasPath
|
32
35
|
extend HasAstNode
|
36
|
+
extend HasDirectives
|
33
37
|
end
|
34
38
|
end
|
35
39
|
end
|
@@ -60,11 +60,11 @@ module GraphQL
|
|
60
60
|
parse_type(type_expr.first, null: false)
|
61
61
|
when 2
|
62
62
|
inner_type, nullable_option = type_expr
|
63
|
-
if nullable_option.keys != [:null] || nullable_option
|
63
|
+
if nullable_option.keys != [:null] || (nullable_option[:null] != true && nullable_option[:null] != false)
|
64
64
|
raise ArgumentError, LIST_TYPE_ERROR
|
65
65
|
end
|
66
66
|
list_type = true
|
67
|
-
parse_type(inner_type, null:
|
67
|
+
parse_type(inner_type, null: nullable_option[:null])
|
68
68
|
else
|
69
69
|
raise ArgumentError, LIST_TYPE_ERROR
|
70
70
|
end
|
@@ -75,7 +75,7 @@ module GraphQL
|
|
75
75
|
if type_expr.respond_to?(:graphql_definition)
|
76
76
|
type_expr
|
77
77
|
else
|
78
|
-
# Eg `String` => GraphQL::
|
78
|
+
# Eg `String` => GraphQL::Types::String
|
79
79
|
parse_type(type_expr.name, null: true)
|
80
80
|
end
|
81
81
|
when Proc
|
@@ -85,70 +85,87 @@ module GraphQL
|
|
85
85
|
# @param context [GraphQL::Query::Context]
|
86
86
|
# @return [Hash<Symbol, Object>, Execution::Lazy<Hash>]
|
87
87
|
def coerce_arguments(parent_object, values, context)
|
88
|
-
argument_values = {}
|
89
|
-
kwarg_arguments = {}
|
90
88
|
# Cache this hash to avoid re-merging it
|
91
89
|
arg_defns = self.arguments
|
92
90
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
has_value =
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
loads = arg_defn.loads
|
112
|
-
loaded_value = nil
|
113
|
-
if loads && !arg_defn.from_resolver?
|
114
|
-
loaded_value = if arg_defn.type.list?
|
115
|
-
loaded_values = value.map { |val| load_application_object(arg_defn, loads, val, context) }
|
116
|
-
context.schema.after_any_lazies(loaded_values) { |result| result }
|
117
|
-
else
|
118
|
-
load_application_object(arg_defn, loads, value, context)
|
119
|
-
end
|
91
|
+
if arg_defns.empty?
|
92
|
+
GraphQL::Execution::Interpreter::Arguments::EMPTY
|
93
|
+
else
|
94
|
+
argument_values = {}
|
95
|
+
arg_lazies = arg_defns.map do |arg_name, arg_defn|
|
96
|
+
arg_key = arg_defn.keyword
|
97
|
+
has_value = false
|
98
|
+
default_used = false
|
99
|
+
if values.key?(arg_name)
|
100
|
+
has_value = true
|
101
|
+
value = values[arg_name]
|
102
|
+
elsif values.key?(arg_key)
|
103
|
+
has_value = true
|
104
|
+
value = values[arg_key]
|
105
|
+
elsif arg_defn.default_value?
|
106
|
+
has_value = true
|
107
|
+
value = arg_defn.default_value
|
108
|
+
default_used = true
|
120
109
|
end
|
121
110
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
context.schema.error_handler.with_error_handling(context) do
|
111
|
+
if has_value
|
112
|
+
loads = arg_defn.loads
|
113
|
+
loaded_value = nil
|
114
|
+
coerced_value = context.schema.error_handler.with_error_handling(context) do
|
126
115
|
arg_defn.type.coerce_input(value, context)
|
127
116
|
end
|
128
|
-
end
|
129
117
|
|
130
|
-
|
131
|
-
|
132
|
-
|
118
|
+
# TODO this should probably be inside after_lazy
|
119
|
+
if loads && !arg_defn.from_resolver?
|
120
|
+
loaded_value = if arg_defn.type.list?
|
121
|
+
loaded_values = coerced_value.map { |val| load_application_object(arg_defn, loads, val, context) }
|
122
|
+
context.schema.after_any_lazies(loaded_values) { |result| result }
|
123
|
+
else
|
124
|
+
load_application_object(arg_defn, loads, coerced_value, context)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
coerced_value = if loaded_value
|
129
|
+
loaded_value
|
130
|
+
else
|
131
|
+
coerced_value
|
133
132
|
end
|
134
133
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
134
|
+
context.schema.after_lazy(coerced_value) do |coerced_value|
|
135
|
+
validate_directive_argument(arg_defn, coerced_value)
|
136
|
+
prepared_value = context.schema.error_handler.with_error_handling(context) do
|
137
|
+
arg_defn.prepare_value(parent_object, coerced_value, context: context)
|
138
|
+
end
|
139
|
+
|
140
|
+
# TODO code smell to access such a deeply-nested constant in a distant module
|
141
|
+
argument_values[arg_key] = GraphQL::Execution::Interpreter::ArgumentValue.new(
|
142
|
+
value: prepared_value,
|
143
|
+
definition: arg_defn,
|
144
|
+
default_used: default_used,
|
145
|
+
)
|
146
|
+
end
|
147
|
+
else
|
148
|
+
# has_value is false
|
149
|
+
validate_directive_argument(arg_defn, nil)
|
142
150
|
end
|
143
151
|
end
|
152
|
+
|
153
|
+
context.schema.after_any_lazies(arg_lazies) do
|
154
|
+
GraphQL::Execution::Interpreter::Arguments.new(
|
155
|
+
argument_values: argument_values,
|
156
|
+
)
|
157
|
+
end
|
144
158
|
end
|
159
|
+
end
|
145
160
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
161
|
+
# Usually, this is validated statically by RequiredArgumentsArePresent,
|
162
|
+
# but not for directives.
|
163
|
+
# TODO apply static validations on schema definitions?
|
164
|
+
def validate_directive_argument(arg_defn, value)
|
165
|
+
if arg_defn.owner.is_a?(Class) && arg_defn.owner < GraphQL::Schema::Directive
|
166
|
+
if value.nil? && arg_defn.type.non_null?
|
167
|
+
raise ArgumentError, "#{arg_defn.path} is required, but no value was given"
|
168
|
+
end
|
152
169
|
end
|
153
170
|
end
|
154
171
|
|