graphql 1.11.7 → 1.12.0
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/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 +38 -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 +1 -0
- 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 +197 -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 +5 -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 +51 -14
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +0 -7
- data/lib/graphql/execution/interpreter/runtime.rb +210 -124
- 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/interface_type.rb +3 -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 +2 -0
- data/lib/graphql/query/context.rb +4 -0
- data/lib/graphql/query/serial_execution.rb +1 -0
- 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 +61 -23
- data/lib/graphql/schema/argument.rb +25 -7
- data/lib/graphql/schema/build_from_definition.rb +139 -51
- 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 +28 -9
- data/lib/graphql/schema/field/connection_extension.rb +3 -2
- 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 +24 -6
- 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/object.rb +11 -0
- data/lib/graphql/schema/printer.rb +5 -4
- 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 +2 -0
- data/lib/graphql/schema/validation.rb +2 -0
- 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/validator.rb +2 -0
- data/lib/graphql/subscriptions.rb +17 -20
- data/lib/graphql/tracing.rb +2 -2
- data/lib/graphql/tracing/appoptics_tracing.rb +3 -1
- data/lib/graphql/tracing/platform_tracing.rb +3 -1
- data/lib/graphql/tracing/skylight_tracing.rb +1 -1
- data/lib/graphql/types/relay.rb +11 -3
- data/lib/graphql/types/relay/base_connection.rb +2 -92
- data/lib/graphql/types/relay/base_edge.rb +2 -35
- 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/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
- metadata +30 -5
- 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
@@ -9,6 +9,13 @@ module GraphQL
|
|
9
9
|
class Directive < GraphQL::Schema::Member
|
10
10
|
extend GraphQL::Schema::Member::HasArguments
|
11
11
|
class << self
|
12
|
+
# Directives aren't types, they don't have kinds.
|
13
|
+
undef_method :kind
|
14
|
+
|
15
|
+
def path
|
16
|
+
"@#{super}"
|
17
|
+
end
|
18
|
+
|
12
19
|
# Return a name based on the class name,
|
13
20
|
# but downcase the first letter.
|
14
21
|
def default_graphql_name
|
@@ -21,6 +28,11 @@ module GraphQL
|
|
21
28
|
|
22
29
|
def locations(*new_locations)
|
23
30
|
if new_locations.any?
|
31
|
+
new_locations.each do |new_loc|
|
32
|
+
if !LOCATIONS.include?(new_loc.to_sym)
|
33
|
+
raise ArgumentError, "#{self} (#{self.graphql_name}) has an invalid directive location: `locations #{new_loc}` "
|
34
|
+
end
|
35
|
+
end
|
24
36
|
@locations = new_locations
|
25
37
|
else
|
26
38
|
@locations ||= (superclass.respond_to?(:locations) ? superclass.locations : [])
|
@@ -87,6 +99,23 @@ module GraphQL
|
|
87
99
|
end
|
88
100
|
end
|
89
101
|
|
102
|
+
# @return [GraphQL::Schema::Field, GraphQL::Schema::Argument, Class, Module]
|
103
|
+
attr_reader :owner
|
104
|
+
|
105
|
+
# @return [GraphQL::Interpreter::Arguments]
|
106
|
+
attr_reader :arguments
|
107
|
+
|
108
|
+
def initialize(owner, **arguments)
|
109
|
+
@owner = owner
|
110
|
+
assert_valid_owner
|
111
|
+
# It's be nice if we had the real context here, but we don't. What we _would_ get is:
|
112
|
+
# - error handling
|
113
|
+
# - lazy resolution
|
114
|
+
# Probably, those won't be needed here, since these are configuration arguments,
|
115
|
+
# not runtime arguments.
|
116
|
+
@arguments = self.class.coerce_arguments(nil, arguments, Query::NullContext)
|
117
|
+
end
|
118
|
+
|
90
119
|
LOCATIONS = [
|
91
120
|
QUERY = :QUERY,
|
92
121
|
MUTATION = :MUTATION,
|
@@ -129,6 +158,53 @@ module GraphQL
|
|
129
158
|
INPUT_OBJECT: 'Location adjacent to an input object type definition.',
|
130
159
|
INPUT_FIELD_DEFINITION: 'Location adjacent to an input object field definition.',
|
131
160
|
}
|
161
|
+
|
162
|
+
private
|
163
|
+
|
164
|
+
def assert_valid_owner
|
165
|
+
case @owner
|
166
|
+
when Class
|
167
|
+
if @owner < GraphQL::Schema::Object
|
168
|
+
assert_has_location(OBJECT)
|
169
|
+
elsif @owner < GraphQL::Schema::Union
|
170
|
+
assert_has_location(UNION)
|
171
|
+
elsif @owner < GraphQL::Schema::Enum
|
172
|
+
assert_has_location(ENUM)
|
173
|
+
elsif @owner < GraphQL::Schema::InputObject
|
174
|
+
assert_has_location(INPUT_OBJECT)
|
175
|
+
elsif @owner < GraphQL::Schema::Scalar
|
176
|
+
assert_has_location(SCALAR)
|
177
|
+
elsif @owner < GraphQL::Schema
|
178
|
+
assert_has_location(SCHEMA)
|
179
|
+
else
|
180
|
+
raise "Unexpected directive owner class: #{@owner}"
|
181
|
+
end
|
182
|
+
when Module
|
183
|
+
assert_has_location(INTERFACE)
|
184
|
+
when GraphQL::Schema::Argument
|
185
|
+
if @owner.owner.is_a?(GraphQL::Schema::Field)
|
186
|
+
assert_has_location(ARGUMENT_DEFINITION)
|
187
|
+
else
|
188
|
+
assert_has_location(INPUT_FIELD_DEFINITION)
|
189
|
+
end
|
190
|
+
when GraphQL::Schema::Field
|
191
|
+
assert_has_location(FIELD_DEFINITION)
|
192
|
+
when GraphQL::Schema::EnumValue
|
193
|
+
assert_has_location(ENUM_VALUE)
|
194
|
+
else
|
195
|
+
raise "Unexpected directive owner: #{@owner.inspect}"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def assert_has_location(location)
|
200
|
+
if !self.class.locations.include?(location)
|
201
|
+
raise ArgumentError, <<-MD
|
202
|
+
Directive `@#{self.class.graphql_name}` can't be attached to #{@owner.graphql_name} because #{location} isn't included in its locations (#{self.class.locations.join(", ")}).
|
203
|
+
|
204
|
+
Use `locations(#{location})` to update this directive's definition, or remove it from #{@owner.graphql_name}.
|
205
|
+
MD
|
206
|
+
end
|
207
|
+
end
|
132
208
|
end
|
133
209
|
end
|
134
210
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
class Schema
|
4
|
+
class Directive < GraphQL::Schema::Member
|
5
|
+
# This is _similar_ to {Directive::Feature}, except it's prescribed by the server, not the client.
|
6
|
+
#
|
7
|
+
# In this case, the server hides types and fields _entirely_, unless the current context has certain `:flags` present.
|
8
|
+
class Flagged < GraphQL::Schema::Directive
|
9
|
+
def initialize(target, **options)
|
10
|
+
if target.is_a?(Module) && !target.ancestors.include?(VisibleByFlag)
|
11
|
+
# This is type class of some kind, `include` will put this module
|
12
|
+
# in between the type class itself and its super class, so `super` will work fine
|
13
|
+
target.include(VisibleByFlag)
|
14
|
+
elsif !target.is_a?(VisibleByFlag)
|
15
|
+
# This is an instance of a base class. `include` won't put this in front of the
|
16
|
+
# base class implementation, so we need to `.prepend`.
|
17
|
+
# `#visible?` could probably be moved to a module and then this could use `include` instead.
|
18
|
+
target.class.prepend(VisibleByFlag)
|
19
|
+
end
|
20
|
+
super
|
21
|
+
end
|
22
|
+
|
23
|
+
description "Hides this part of the schema unless the named flag is present in context[:flags]"
|
24
|
+
|
25
|
+
locations(
|
26
|
+
GraphQL::Schema::Directive::FIELD_DEFINITION,
|
27
|
+
GraphQL::Schema::Directive::OBJECT,
|
28
|
+
GraphQL::Schema::Directive::SCALAR,
|
29
|
+
GraphQL::Schema::Directive::ENUM,
|
30
|
+
GraphQL::Schema::Directive::UNION,
|
31
|
+
GraphQL::Schema::Directive::INTERFACE,
|
32
|
+
GraphQL::Schema::Directive::INPUT_OBJECT,
|
33
|
+
GraphQL::Schema::Directive::ENUM_VALUE,
|
34
|
+
GraphQL::Schema::Directive::ARGUMENT_DEFINITION,
|
35
|
+
GraphQL::Schema::Directive::INPUT_FIELD_DEFINITION,
|
36
|
+
)
|
37
|
+
|
38
|
+
argument :by, [String], "Flags to check for this schema member", required: true
|
39
|
+
|
40
|
+
module VisibleByFlag
|
41
|
+
def self.included(schema_class)
|
42
|
+
schema_class.extend(self)
|
43
|
+
end
|
44
|
+
|
45
|
+
def visible?(context)
|
46
|
+
if dir = self.directives.find { |d| d.is_a?(Flagged) }
|
47
|
+
relevant_flags = (f = context[:flags]) && dir.arguments[:by] & f
|
48
|
+
relevant_flags && relevant_flags.any? && super
|
49
|
+
else
|
50
|
+
super
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
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,10 +82,10 @@ 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::
|
85
|
+
if kwargs[:field].is_a?(GraphQL::Field) && kwargs[:field] == GraphQL::Types::Relay::NodeField.graphql_definition
|
86
86
|
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::
|
88
|
+
elsif kwargs[:field].is_a?(GraphQL::Field) && kwargs[:field] == GraphQL::Types::Relay::NodesField.graphql_definition
|
89
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.")
|
90
90
|
return GraphQL::Types::Relay::NodesField
|
91
91
|
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)
|
@@ -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
|