graphql 1.11.3 → 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/core.rb +8 -0
- 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_argument.erb +2 -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/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_mutation.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -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/enum.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/interface.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/mutation_type.erb +2 -0
- data/lib/generators/graphql/templates/node_type.erb +9 -0
- data/lib/generators/graphql/templates/object.erb +3 -1
- data/lib/generators/graphql/templates/query_type.erb +3 -3
- data/lib/generators/graphql/templates/scalar.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +10 -35
- data/lib/generators/graphql/templates/union.erb +3 -1
- data/lib/graphql.rb +55 -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/argument.rb +3 -3
- 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 -8
- 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 +2 -2
- 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 +20 -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 +251 -138
- 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/introspection.rb +96 -0
- data/lib/graphql/introspection/field_type.rb +7 -3
- data/lib/graphql/introspection/input_value_type.rb +6 -0
- data/lib/graphql/introspection/introspection_query.rb +6 -92
- data/lib/graphql/introspection/type_type.rb +7 -3
- data/lib/graphql/invalid_null_error.rb +1 -1
- data/lib/graphql/language/block_string.rb +24 -5
- data/lib/graphql/language/document_from_schema_definition.rb +50 -23
- data/lib/graphql/language/lexer.rb +7 -3
- data/lib/graphql/language/lexer.rl +7 -3
- data/lib/graphql/language/nodes.rb +1 -1
- data/lib/graphql/language/parser.rb +107 -103
- data/lib/graphql/language/parser.y +4 -0
- data/lib/graphql/language/sanitized_printer.rb +59 -26
- data/lib/graphql/name_validator.rb +6 -7
- data/lib/graphql/object_type.rb +2 -0
- data/lib/graphql/pagination/connection.rb +5 -1
- data/lib/graphql/pagination/connections.rb +15 -17
- data/lib/graphql/query.rb +8 -3
- data/lib/graphql/query/context.rb +38 -4
- data/lib/graphql/query/fingerprint.rb +2 -0
- data/lib/graphql/query/serial_execution.rb +1 -0
- data/lib/graphql/query/validation_pipeline.rb +4 -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/range_add.rb +14 -5
- data/lib/graphql/relay/type_extensions.rb +2 -0
- data/lib/graphql/scalar_type.rb +2 -0
- data/lib/graphql/schema.rb +107 -38
- data/lib/graphql/schema/argument.rb +74 -5
- data/lib/graphql/schema/build_from_definition.rb +203 -86
- data/lib/graphql/schema/default_type_error.rb +2 -0
- data/lib/graphql/schema/directive.rb +76 -0
- data/lib/graphql/schema/directive/deprecated.rb +1 -1
- 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 +59 -24
- data/lib/graphql/schema/field/connection_extension.rb +11 -9
- data/lib/graphql/schema/field/scope_extension.rb +1 -1
- data/lib/graphql/schema/input_object.rb +38 -25
- data/lib/graphql/schema/interface.rb +2 -1
- data/lib/graphql/schema/late_bound_type.rb +2 -2
- data/lib/graphql/schema/loader.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 +17 -7
- data/lib/graphql/schema/member/has_arguments.rb +70 -51
- 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_fields.rb +2 -2
- data/lib/graphql/schema/member/has_validators.rb +31 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +3 -3
- data/lib/graphql/schema/object.rb +11 -0
- data/lib/graphql/schema/printer.rb +5 -4
- data/lib/graphql/schema/relay_classic_mutation.rb +4 -2
- 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 +20 -12
- data/lib/graphql/schema/timeout.rb +29 -15
- data/lib/graphql/schema/timeout_middleware.rb +2 -0
- data/lib/graphql/schema/unique_within_type.rb +1 -2
- data/lib/graphql/schema/validation.rb +10 -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/schema/warden.rb +2 -3
- 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 +31 -7
- data/lib/graphql/subscriptions.rb +23 -16
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +21 -7
- data/lib/graphql/tracing.rb +2 -2
- data/lib/graphql/tracing/appoptics_tracing.rb +12 -2
- 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/iso_8601_date_time.rb +2 -1
- data/lib/graphql/types/relay.rb +11 -3
- data/lib/graphql/types/relay/base_connection.rb +2 -90
- 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/unauthorized_error.rb +1 -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 +38 -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
@@ -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
|
@@ -4,7 +4,7 @@ module GraphQL
|
|
4
4
|
class Directive < GraphQL::Schema::Member
|
5
5
|
class Deprecated < GraphQL::Schema::Directive
|
6
6
|
description "Marks an element of a GraphQL schema as no longer supported."
|
7
|
-
locations(GraphQL::Schema::Directive::FIELD_DEFINITION, GraphQL::Schema::Directive::ENUM_VALUE)
|
7
|
+
locations(GraphQL::Schema::Directive::FIELD_DEFINITION, GraphQL::Schema::Directive::ENUM_VALUE, GraphQL::Schema::Directive::ARGUMENT_DEFINITION, GraphQL::Schema::Directive::INPUT_FIELD_DEFINITION)
|
8
8
|
|
9
9
|
reason_description = "Explains why this element was deprecated, usually also including a "\
|
10
10
|
"suggestion for how to access supported similar data. Formatted "\
|
@@ -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}`)"
|
@@ -250,7 +253,7 @@ module GraphQL
|
|
250
253
|
method_name = method || hash_key || name_s
|
251
254
|
resolver_method ||= name_s.to_sym
|
252
255
|
|
253
|
-
@method_str = method_name.to_s
|
256
|
+
@method_str = -method_name.to_s
|
254
257
|
@method_sym = method_name.to_sym
|
255
258
|
@resolver_method = resolver_method
|
256
259
|
@complexity = complexity
|
@@ -269,12 +272,13 @@ 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)
|
275
279
|
argument(name: name, **arg)
|
276
280
|
else
|
277
|
-
|
281
|
+
add_argument(arg)
|
278
282
|
end
|
279
283
|
end
|
280
284
|
|
@@ -282,7 +286,7 @@ module GraphQL
|
|
282
286
|
@subscription_scope = subscription_scope
|
283
287
|
|
284
288
|
# Do this last so we have as much context as possible when initializing them:
|
285
|
-
@extensions =
|
289
|
+
@extensions = EMPTY_ARRAY
|
286
290
|
if extensions.any?
|
287
291
|
self.extensions(extensions)
|
288
292
|
end
|
@@ -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
|
@@ -343,6 +355,9 @@ module GraphQL
|
|
343
355
|
# Read the value
|
344
356
|
@extensions
|
345
357
|
else
|
358
|
+
if @extensions.frozen?
|
359
|
+
@extensions = @extensions.dup
|
360
|
+
end
|
346
361
|
new_extensions.each do |extension|
|
347
362
|
if extension.is_a?(Hash)
|
348
363
|
extension = extension.to_a[0]
|
@@ -380,6 +395,9 @@ module GraphQL
|
|
380
395
|
# Read the value
|
381
396
|
@extras
|
382
397
|
else
|
398
|
+
if @extras.frozen?
|
399
|
+
@extras = @extras.dup
|
400
|
+
end
|
383
401
|
# Append to the set of extras on this field
|
384
402
|
@extras.concat(new_extras)
|
385
403
|
end
|
@@ -432,8 +450,8 @@ module GraphQL
|
|
432
450
|
field_defn.description = @description
|
433
451
|
end
|
434
452
|
|
435
|
-
if
|
436
|
-
field_defn.deprecation_reason =
|
453
|
+
if self.deprecation_reason
|
454
|
+
field_defn.deprecation_reason = self.deprecation_reason
|
437
455
|
end
|
438
456
|
|
439
457
|
if @resolver_class
|
@@ -455,6 +473,10 @@ module GraphQL
|
|
455
473
|
field_defn.relay_nodes_field = @relay_nodes_field
|
456
474
|
end
|
457
475
|
|
476
|
+
if @legacy_edge_class
|
477
|
+
field_defn.edge_class = @legacy_edge_class
|
478
|
+
end
|
479
|
+
|
458
480
|
field_defn.resolve = self.method(:resolve_field)
|
459
481
|
field_defn.connection = connection?
|
460
482
|
field_defn.connection_max_page_size = max_page_size
|
@@ -574,6 +596,9 @@ module GraphQL
|
|
574
596
|
begin
|
575
597
|
# Unwrap the GraphQL object to get the application object.
|
576
598
|
application_object = object.object
|
599
|
+
|
600
|
+
Schema::Validator.validate!(validators, application_object, ctx, args)
|
601
|
+
|
577
602
|
ctx.schema.after_lazy(self.authorized?(application_object, args, ctx)) do |is_authorized|
|
578
603
|
if is_authorized
|
579
604
|
public_send_field(object, args, ctx)
|
@@ -719,32 +744,42 @@ module GraphQL
|
|
719
744
|
if @extensions.empty?
|
720
745
|
yield(obj, args)
|
721
746
|
else
|
722
|
-
#
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
yield(extended_obj, extended_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|
|
752
|
+
yield(obj, args)
|
729
753
|
end
|
730
754
|
|
755
|
+
extended_obj = extended[:obj]
|
756
|
+
extended_args = extended[:args]
|
757
|
+
memos = extended[:memos] || EMPTY_HASH
|
758
|
+
|
731
759
|
ctx.schema.after_lazy(value) do |resolved_value|
|
732
|
-
|
760
|
+
idx = 0
|
761
|
+
@extensions.each do |ext|
|
733
762
|
memo = memos[idx]
|
734
763
|
# TODO after_lazy?
|
735
|
-
resolved_value = ext.after_resolve(object:
|
764
|
+
resolved_value = ext.after_resolve(object: extended_obj, arguments: extended_args, context: ctx, value: resolved_value, memo: memo)
|
765
|
+
idx += 1
|
736
766
|
end
|
737
767
|
resolved_value
|
738
768
|
end
|
739
769
|
end
|
740
770
|
end
|
741
771
|
|
742
|
-
def run_extensions_before_resolve(
|
772
|
+
def run_extensions_before_resolve(obj, args, ctx, extended, idx: 0)
|
743
773
|
extension = @extensions[idx]
|
744
774
|
if extension
|
745
775
|
extension.resolve(object: obj, arguments: args, context: ctx) do |extended_obj, extended_args, memo|
|
746
|
-
|
747
|
-
|
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) }
|
748
783
|
end
|
749
784
|
else
|
750
785
|
yield(obj, args)
|
@@ -18,10 +18,11 @@ module GraphQL
|
|
18
18
|
next_args.delete(:last)
|
19
19
|
next_args.delete(:before)
|
20
20
|
next_args.delete(:after)
|
21
|
-
yield(object, next_args)
|
21
|
+
yield(object, next_args, arguments)
|
22
22
|
end
|
23
23
|
|
24
24
|
def after_resolve(value:, object:, arguments:, context:, memo:)
|
25
|
+
original_arguments = memo
|
25
26
|
# rename some inputs to avoid conflicts inside the block
|
26
27
|
maybe_lazy = value
|
27
28
|
value = nil
|
@@ -37,20 +38,21 @@ module GraphQL
|
|
37
38
|
# update the connection with some things that may not have been provided
|
38
39
|
value.context ||= context
|
39
40
|
value.parent ||= object.object
|
40
|
-
value.first_value ||=
|
41
|
-
value.after_value ||=
|
42
|
-
value.last_value ||=
|
43
|
-
value.before_value ||=
|
41
|
+
value.first_value ||= original_arguments[:first]
|
42
|
+
value.after_value ||= original_arguments[:after]
|
43
|
+
value.last_value ||= original_arguments[:last]
|
44
|
+
value.before_value ||= original_arguments[:before]
|
45
|
+
value.field ||= field
|
44
46
|
if field.has_max_page_size? && !value.has_max_page_size_override?
|
45
47
|
value.max_page_size = field.max_page_size
|
46
48
|
end
|
47
|
-
if (custom_t = context.schema.connections.edge_class_for_field(@field))
|
49
|
+
if context.schema.new_connections? && (custom_t = context.schema.connections.edge_class_for_field(@field))
|
48
50
|
value.edge_class = custom_t
|
49
51
|
end
|
50
52
|
value
|
51
53
|
elsif context.schema.new_connections?
|
52
|
-
|
53
|
-
context.schema.connections.wrap(field, object.object, value,
|
54
|
+
context.namespace(:connections)[:all_wrappers] ||= context.schema.connections.all_wrappers
|
55
|
+
context.schema.connections.wrap(field, object.object, value, original_arguments, context)
|
54
56
|
else
|
55
57
|
if object.is_a?(GraphQL::Schema::Object)
|
56
58
|
object = object.object
|
@@ -58,7 +60,7 @@ module GraphQL
|
|
58
60
|
connection_class = GraphQL::Relay::BaseConnection.connection_for_nodes(value)
|
59
61
|
connection_class.new(
|
60
62
|
value,
|
61
|
-
|
63
|
+
original_arguments,
|
62
64
|
field: field,
|
63
65
|
max_page_size: field.max_page_size,
|
64
66
|
parent: object,
|