graphql 2.3.5 → 2.3.11
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 +46 -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/{ast/query_depth.rb → query_depth.rb} +23 -25
- data/lib/graphql/analysis/visitor.rb +283 -0
- data/lib/graphql/analysis.rb +92 -1
- data/lib/graphql/current.rb +52 -0
- data/lib/graphql/dataloader/async_dataloader.rb +2 -0
- data/lib/graphql/dataloader/source.rb +5 -2
- data/lib/graphql/dataloader.rb +4 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +5 -10
- data/lib/graphql/execution/interpreter/runtime.rb +8 -14
- data/lib/graphql/execution/interpreter.rb +3 -1
- data/lib/graphql/execution/lookahead.rb +10 -10
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +6 -11
- data/lib/graphql/introspection/type_type.rb +5 -5
- data/lib/graphql/language/document_from_schema_definition.rb +19 -26
- data/lib/graphql/language/lexer.rb +0 -3
- data/lib/graphql/language/nodes.rb +2 -2
- data/lib/graphql/language/parser.rb +9 -1
- data/lib/graphql/language/sanitized_printer.rb +1 -1
- data/lib/graphql/language.rb +0 -1
- data/lib/graphql/query/context.rb +7 -1
- data/lib/graphql/query/null_context.rb +2 -2
- data/lib/graphql/query/validation_pipeline.rb +2 -2
- data/lib/graphql/query.rb +26 -7
- data/lib/graphql/schema/always_visible.rb +1 -0
- data/lib/graphql/schema/argument.rb +19 -5
- data/lib/graphql/schema/build_from_definition.rb +8 -1
- data/lib/graphql/schema/directive/flagged.rb +1 -1
- data/lib/graphql/schema/directive.rb +2 -0
- data/lib/graphql/schema/enum.rb +9 -5
- data/lib/graphql/schema/field/connection_extension.rb +1 -1
- data/lib/graphql/schema/field.rb +13 -1
- data/lib/graphql/schema/has_single_input_argument.rb +2 -1
- data/lib/graphql/schema/input_object.rb +8 -7
- data/lib/graphql/schema/interface.rb +20 -4
- data/lib/graphql/schema/introspection_system.rb +5 -16
- data/lib/graphql/schema/member/has_arguments.rb +14 -9
- data/lib/graphql/schema/member/has_fields.rb +6 -4
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/resolver.rb +5 -5
- data/lib/graphql/schema/subset.rb +510 -0
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/types_migration.rb +185 -0
- data/lib/graphql/schema/validator/all_validator.rb +60 -0
- data/lib/graphql/schema/validator.rb +2 -0
- data/lib/graphql/schema/warden.rb +89 -5
- data/lib/graphql/schema.rb +74 -37
- data/lib/graphql/static_validation/base_visitor.rb +6 -5
- data/lib/graphql/static_validation/literal_validator.rb +4 -4
- 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_will_merge.rb +7 -7
- 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/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +3 -3
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +3 -3
- 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 +2 -2
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/event.rb +1 -1
- data/lib/graphql/subscriptions.rb +3 -3
- data/lib/graphql/testing/helpers.rb +8 -5
- data/lib/graphql/types/relay/connection_behaviors.rb +10 -0
- data/lib/graphql/types/relay/edge_behaviors.rb +10 -0
- data/lib/graphql/types/relay/page_info_behaviors.rb +4 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +1 -0
- metadata +14 -13
- data/lib/graphql/analysis/ast/analyzer.rb +0 -91
- data/lib/graphql/analysis/ast/field_usage.rb +0 -84
- 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 -185
- data/lib/graphql/analysis/ast/visitor.rb +0 -284
- data/lib/graphql/analysis/ast.rb +0 -94
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
@@ -20,31 +20,26 @@ module GraphQL
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def types
|
23
|
-
|
23
|
+
query_types = context.types.all_types
|
24
|
+
types = query_types + context.schema.extra_types
|
24
25
|
types.sort_by!(&:graphql_name)
|
25
26
|
types
|
26
27
|
end
|
27
28
|
|
28
29
|
def query_type
|
29
|
-
|
30
|
+
@context.types.query_root
|
30
31
|
end
|
31
32
|
|
32
33
|
def mutation_type
|
33
|
-
|
34
|
+
@context.types.mutation_root
|
34
35
|
end
|
35
36
|
|
36
37
|
def subscription_type
|
37
|
-
|
38
|
+
@context.types.subscription_root
|
38
39
|
end
|
39
40
|
|
40
41
|
def directives
|
41
|
-
@context.
|
42
|
-
end
|
43
|
-
|
44
|
-
private
|
45
|
-
|
46
|
-
def permitted_root_type(op_type)
|
47
|
-
@context.warden.root_type_for_operation(op_type)
|
42
|
+
@context.types.directives.sort_by(&:graphql_name)
|
48
43
|
end
|
49
44
|
end
|
50
45
|
end
|
@@ -52,7 +52,7 @@ module GraphQL
|
|
52
52
|
if !@object.kind.enum?
|
53
53
|
nil
|
54
54
|
else
|
55
|
-
enum_values = @context.
|
55
|
+
enum_values = @context.types.enum_values(@object)
|
56
56
|
|
57
57
|
if !include_deprecated
|
58
58
|
enum_values = enum_values.select {|f| !f.deprecation_reason }
|
@@ -64,7 +64,7 @@ module GraphQL
|
|
64
64
|
|
65
65
|
def interfaces
|
66
66
|
if @object.kind.object? || @object.kind.interface?
|
67
|
-
@context.
|
67
|
+
@context.types.interfaces(@object).sort_by(&:graphql_name)
|
68
68
|
else
|
69
69
|
nil
|
70
70
|
end
|
@@ -72,7 +72,7 @@ module GraphQL
|
|
72
72
|
|
73
73
|
def input_fields(include_deprecated:)
|
74
74
|
if @object.kind.input_object?
|
75
|
-
args = @context.
|
75
|
+
args = @context.types.arguments(@object)
|
76
76
|
args = args.reject(&:deprecation_reason) unless include_deprecated
|
77
77
|
args
|
78
78
|
else
|
@@ -82,7 +82,7 @@ module GraphQL
|
|
82
82
|
|
83
83
|
def possible_types
|
84
84
|
if @object.kind.abstract?
|
85
|
-
@context.
|
85
|
+
@context.types.possible_types(@object).sort_by(&:graphql_name)
|
86
86
|
else
|
87
87
|
nil
|
88
88
|
end
|
@@ -92,7 +92,7 @@ module GraphQL
|
|
92
92
|
if !@object.kind.fields?
|
93
93
|
nil
|
94
94
|
else
|
95
|
-
fields = @context.
|
95
|
+
fields = @context.types.fields(@object)
|
96
96
|
if !include_deprecated
|
97
97
|
fields = fields.select {|f| !f.deprecation_reason }
|
98
98
|
end
|
@@ -24,15 +24,8 @@ module GraphQL
|
|
24
24
|
@include_built_in_directives = include_built_in_directives
|
25
25
|
@include_one_of = false
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
@warden = @schema.warden_class.new(
|
31
|
-
schema: @schema,
|
32
|
-
context: schema_context,
|
33
|
-
)
|
34
|
-
|
35
|
-
schema_context.warden = @warden
|
27
|
+
dummy_query = @schema.query_class.new(@schema, "{ __typename }", validate: false, context: context)
|
28
|
+
@types = dummy_query.types # rubocop:disable Development/ContextIsPassedCop
|
36
29
|
end
|
37
30
|
|
38
31
|
def document
|
@@ -44,9 +37,9 @@ module GraphQL
|
|
44
37
|
def build_schema_node
|
45
38
|
if !schema_respects_root_name_conventions?(@schema)
|
46
39
|
GraphQL::Language::Nodes::SchemaDefinition.new(
|
47
|
-
query:
|
48
|
-
mutation:
|
49
|
-
subscription:
|
40
|
+
query: @types.query_root&.graphql_name,
|
41
|
+
mutation: @types.mutation_root&.graphql_name,
|
42
|
+
subscription: @types.subscription_root&.graphql_name,
|
50
43
|
directives: definition_directives(@schema, :schema_directives)
|
51
44
|
)
|
52
45
|
else
|
@@ -57,7 +50,7 @@ module GraphQL
|
|
57
50
|
end
|
58
51
|
|
59
52
|
def build_object_type_node(object_type)
|
60
|
-
ints =
|
53
|
+
ints = @types.interfaces(object_type)
|
61
54
|
if ints.any?
|
62
55
|
ints.sort_by!(&:graphql_name)
|
63
56
|
ints.map! { |iface| build_type_name_node(iface) }
|
@@ -66,7 +59,7 @@ module GraphQL
|
|
66
59
|
GraphQL::Language::Nodes::ObjectTypeDefinition.new(
|
67
60
|
name: object_type.graphql_name,
|
68
61
|
interfaces: ints,
|
69
|
-
fields: build_field_nodes(
|
62
|
+
fields: build_field_nodes(@types.fields(object_type)),
|
70
63
|
description: object_type.description,
|
71
64
|
directives: directives(object_type),
|
72
65
|
)
|
@@ -75,7 +68,7 @@ module GraphQL
|
|
75
68
|
def build_field_node(field)
|
76
69
|
GraphQL::Language::Nodes::FieldDefinition.new(
|
77
70
|
name: field.graphql_name,
|
78
|
-
arguments: build_argument_nodes(
|
71
|
+
arguments: build_argument_nodes(@types.arguments(field)),
|
79
72
|
type: build_type_name_node(field.type),
|
80
73
|
description: field.description,
|
81
74
|
directives: directives(field),
|
@@ -86,7 +79,7 @@ module GraphQL
|
|
86
79
|
GraphQL::Language::Nodes::UnionTypeDefinition.new(
|
87
80
|
name: union_type.graphql_name,
|
88
81
|
description: union_type.description,
|
89
|
-
types:
|
82
|
+
types: @types.possible_types(union_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
|
90
83
|
directives: directives(union_type),
|
91
84
|
)
|
92
85
|
end
|
@@ -94,9 +87,9 @@ module GraphQL
|
|
94
87
|
def build_interface_type_node(interface_type)
|
95
88
|
GraphQL::Language::Nodes::InterfaceTypeDefinition.new(
|
96
89
|
name: interface_type.graphql_name,
|
97
|
-
interfaces:
|
90
|
+
interfaces: @types.interfaces(interface_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
|
98
91
|
description: interface_type.description,
|
99
|
-
fields: build_field_nodes(
|
92
|
+
fields: build_field_nodes(@types.fields(interface_type)),
|
100
93
|
directives: directives(interface_type),
|
101
94
|
)
|
102
95
|
end
|
@@ -104,7 +97,7 @@ module GraphQL
|
|
104
97
|
def build_enum_type_node(enum_type)
|
105
98
|
GraphQL::Language::Nodes::EnumTypeDefinition.new(
|
106
99
|
name: enum_type.graphql_name,
|
107
|
-
values:
|
100
|
+
values: @types.enum_values(enum_type).sort_by(&:graphql_name).map do |enum_value|
|
108
101
|
build_enum_value_node(enum_value)
|
109
102
|
end,
|
110
103
|
description: enum_type.description,
|
@@ -149,7 +142,7 @@ module GraphQL
|
|
149
142
|
def build_input_object_node(input_object)
|
150
143
|
GraphQL::Language::Nodes::InputObjectTypeDefinition.new(
|
151
144
|
name: input_object.graphql_name,
|
152
|
-
fields: build_argument_nodes(
|
145
|
+
fields: build_argument_nodes(@types.arguments(input_object)),
|
153
146
|
description: input_object.description,
|
154
147
|
directives: directives(input_object),
|
155
148
|
)
|
@@ -159,7 +152,7 @@ module GraphQL
|
|
159
152
|
GraphQL::Language::Nodes::DirectiveDefinition.new(
|
160
153
|
name: directive.graphql_name,
|
161
154
|
repeatable: directive.repeatable?,
|
162
|
-
arguments: build_argument_nodes(
|
155
|
+
arguments: build_argument_nodes(@types.arguments(directive)),
|
163
156
|
locations: build_directive_location_nodes(directive.locations),
|
164
157
|
description: directive.description,
|
165
158
|
)
|
@@ -204,7 +197,7 @@ module GraphQL
|
|
204
197
|
when "INPUT_OBJECT"
|
205
198
|
GraphQL::Language::Nodes::InputObject.new(
|
206
199
|
arguments: default_value.to_h.map do |arg_name, arg_value|
|
207
|
-
args = @
|
200
|
+
args = @types.arguments(type)
|
208
201
|
arg = args.find { |a| a.keyword.to_s == arg_name.to_s }
|
209
202
|
if arg.nil?
|
210
203
|
raise ArgumentError, "No argument definition on #{type.graphql_name} for argument: #{arg_name.inspect} (expected one of: #{args.map(&:keyword)})"
|
@@ -260,13 +253,13 @@ module GraphQL
|
|
260
253
|
end
|
261
254
|
|
262
255
|
def build_definition_nodes
|
263
|
-
dirs_to_build =
|
256
|
+
dirs_to_build = @types.directives
|
264
257
|
if !include_built_in_directives
|
265
258
|
dirs_to_build = dirs_to_build.reject { |directive| directive.default_directive? }
|
266
259
|
end
|
267
260
|
definitions = build_directive_nodes(dirs_to_build)
|
268
|
-
|
269
|
-
type_nodes = build_type_definition_nodes(
|
261
|
+
all_types = @types.all_types
|
262
|
+
type_nodes = build_type_definition_nodes(all_types + schema.extra_types)
|
270
263
|
if @include_one_of
|
271
264
|
# This may have been set to true when iterating over all types
|
272
265
|
definitions.concat(build_directive_nodes([GraphQL::Schema::Directive::OneOf]))
|
@@ -351,7 +344,7 @@ module GraphQL
|
|
351
344
|
dirs
|
352
345
|
end
|
353
346
|
|
354
|
-
attr_reader :schema, :
|
347
|
+
attr_reader :schema, :always_include_schema,
|
355
348
|
:include_introspection_types, :include_built_in_directives, :include_built_in_scalars
|
356
349
|
end
|
357
350
|
end
|
@@ -345,17 +345,14 @@ module GraphQL
|
|
345
345
|
def self.tokenize(string)
|
346
346
|
lexer = GraphQL::Language::Lexer.new(string)
|
347
347
|
tokens = []
|
348
|
-
prev_token = nil
|
349
348
|
while (token_name = lexer.advance)
|
350
349
|
new_token = [
|
351
350
|
token_name,
|
352
351
|
lexer.line_number,
|
353
352
|
lexer.column_number,
|
354
353
|
lexer.debug_token_value(token_name),
|
355
|
-
prev_token,
|
356
354
|
]
|
357
355
|
tokens << new_token
|
358
|
-
prev_token = new_token
|
359
356
|
end
|
360
357
|
tokens
|
361
358
|
end
|
@@ -34,11 +34,11 @@ module GraphQL
|
|
34
34
|
attr_reader :filename
|
35
35
|
|
36
36
|
def line
|
37
|
-
@line ||= @source
|
37
|
+
@line ||= @source&.line_at(@pos)
|
38
38
|
end
|
39
39
|
|
40
40
|
def col
|
41
|
-
@col ||= @source
|
41
|
+
@col ||= @source&.column_at(@pos)
|
42
42
|
end
|
43
43
|
|
44
44
|
def definition_line
|
@@ -141,7 +141,12 @@ module GraphQL
|
|
141
141
|
parse_operation_type
|
142
142
|
end
|
143
143
|
|
144
|
-
op_name =
|
144
|
+
op_name = case token_name
|
145
|
+
when :LPAREN, :LCURLY, :DIR_SIGN
|
146
|
+
nil
|
147
|
+
else
|
148
|
+
parse_name
|
149
|
+
end
|
145
150
|
|
146
151
|
variable_definitions = if at?(:LPAREN)
|
147
152
|
expect_token(:LPAREN)
|
@@ -398,6 +403,9 @@ module GraphQL
|
|
398
403
|
def parse_union_members
|
399
404
|
if at?(:EQUALS)
|
400
405
|
expect_token :EQUALS
|
406
|
+
if at?(:PIPE)
|
407
|
+
advance_token
|
408
|
+
end
|
401
409
|
list = [parse_type_name]
|
402
410
|
while at?(:PIPE)
|
403
411
|
advance_token
|
@@ -113,7 +113,7 @@ module GraphQL
|
|
113
113
|
end
|
114
114
|
|
115
115
|
def print_field(field, indent: "")
|
116
|
-
@current_field = query.
|
116
|
+
@current_field = query.types.field(@current_type, field.name)
|
117
117
|
old_type = @current_type
|
118
118
|
@current_type = @current_field.type.unwrap
|
119
119
|
super
|
data/lib/graphql/language.rb
CHANGED
@@ -9,7 +9,6 @@ require "graphql/language/nodes"
|
|
9
9
|
require "graphql/language/cache"
|
10
10
|
require "graphql/language/parser"
|
11
11
|
require "graphql/language/static_visitor"
|
12
|
-
require "graphql/language/token"
|
13
12
|
require "graphql/language/visitor"
|
14
13
|
require "graphql/language/definition_slice"
|
15
14
|
require "strscan"
|
@@ -82,7 +82,13 @@ module GraphQL
|
|
82
82
|
@provided_values[key] = value
|
83
83
|
end
|
84
84
|
|
85
|
-
def_delegators :@query, :trace
|
85
|
+
def_delegators :@query, :trace
|
86
|
+
|
87
|
+
def types
|
88
|
+
@types ||= @query.types
|
89
|
+
end
|
90
|
+
|
91
|
+
attr_writer :types
|
86
92
|
|
87
93
|
RUNTIME_METADATA_KEYS = Set.new([:current_object, :current_arguments, :current_field, :current_path])
|
88
94
|
# @!method []=(key, value)
|
@@ -100,10 +100,10 @@ module GraphQL
|
|
100
100
|
# Depending on the analysis engine, we must use different analyzers
|
101
101
|
# remove this once everything has switched over to AST analyzers
|
102
102
|
if max_depth
|
103
|
-
qa << GraphQL::Analysis::
|
103
|
+
qa << GraphQL::Analysis::MaxQueryDepth
|
104
104
|
end
|
105
105
|
if max_complexity
|
106
|
-
qa << GraphQL::Analysis::
|
106
|
+
qa << GraphQL::Analysis::MaxQueryComplexity
|
107
107
|
end
|
108
108
|
qa
|
109
109
|
else
|
data/lib/graphql/query.rb
CHANGED
@@ -95,12 +95,24 @@ module GraphQL
|
|
95
95
|
# @param root_value [Object] the object used to resolve fields on the root type
|
96
96
|
# @param max_depth [Numeric] the maximum number of nested selections allowed for this query (falls back to schema-level value)
|
97
97
|
# @param max_complexity [Numeric] the maximum field complexity for this query (falls back to schema-level value)
|
98
|
-
def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, static_validator: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, warden: nil)
|
98
|
+
def initialize(schema, query_string = nil, query: nil, document: nil, context: nil, variables: nil, validate: true, static_validator: nil, subscription_topic: nil, operation_name: nil, root_value: nil, max_depth: schema.max_depth, max_complexity: schema.max_complexity, warden: nil, use_schema_subset: nil)
|
99
99
|
# Even if `variables: nil` is passed, use an empty hash for simpler logic
|
100
100
|
variables ||= {}
|
101
101
|
@schema = schema
|
102
102
|
@context = schema.context_class.new(query: self, values: context)
|
103
|
-
|
103
|
+
|
104
|
+
if use_schema_subset.nil?
|
105
|
+
use_schema_subset = warden ? false : schema.use_schema_subset?
|
106
|
+
end
|
107
|
+
|
108
|
+
if use_schema_subset
|
109
|
+
@schema_subset = @schema.subset_class.new(context: @context, schema: @schema)
|
110
|
+
@warden = Schema::Warden::NullWarden.new(context: @context, schema: @schema)
|
111
|
+
else
|
112
|
+
@schema_subset = nil
|
113
|
+
@warden = warden
|
114
|
+
end
|
115
|
+
|
104
116
|
@subscription_topic = subscription_topic
|
105
117
|
@root_value = root_value
|
106
118
|
@fragments = nil
|
@@ -175,10 +187,6 @@ module GraphQL
|
|
175
187
|
@query_string ||= (document ? document.to_query_string : nil)
|
176
188
|
end
|
177
189
|
|
178
|
-
def interpreter?
|
179
|
-
true
|
180
|
-
end
|
181
|
-
|
182
190
|
attr_accessor :multiplex
|
183
191
|
|
184
192
|
# @return [GraphQL::Tracing::Trace]
|
@@ -195,7 +203,14 @@ module GraphQL
|
|
195
203
|
def lookahead
|
196
204
|
@lookahead ||= begin
|
197
205
|
ast_node = selected_operation
|
198
|
-
root_type =
|
206
|
+
root_type = case ast_node.operation_type
|
207
|
+
when nil, "query"
|
208
|
+
types.query_root # rubocop:disable Development/ContextIsPassedCop
|
209
|
+
when "mutation"
|
210
|
+
types.mutation_root # rubocop:disable Development/ContextIsPassedCop
|
211
|
+
when "subscription"
|
212
|
+
types.subscription_root # rubocop:disable Development/ContextIsPassedCop
|
213
|
+
end
|
199
214
|
GraphQL::Execution::Lookahead.new(query: self, root_type: root_type, ast_nodes: [ast_node])
|
200
215
|
end
|
201
216
|
end
|
@@ -330,6 +345,10 @@ module GraphQL
|
|
330
345
|
|
331
346
|
def_delegators :warden, :get_type, :get_field, :possible_types, :root_type_for_operation
|
332
347
|
|
348
|
+
def types
|
349
|
+
@schema_subset || warden.schema_subset
|
350
|
+
end
|
351
|
+
|
333
352
|
# @param abstract_type [GraphQL::UnionType, GraphQL::InterfaceType]
|
334
353
|
# @param value [Object] Any runtime value
|
335
354
|
# @return [GraphQL::ObjectType, nil] The runtime type of `value` from {Schema#resolve_type}
|
@@ -312,10 +312,15 @@ module GraphQL
|
|
312
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)
|
@@ -127,11 +127,12 @@ module GraphQL
|
|
127
127
|
builder = self
|
128
128
|
|
129
129
|
found_types = types.values
|
130
|
+
object_types = found_types.select { |t| t.respond_to?(:kind) && t.kind.object? }
|
130
131
|
schema_class = Class.new(schema_superclass) do
|
131
132
|
begin
|
132
133
|
# Add these first so that there's some chance of resolving late-bound types
|
133
134
|
add_type_and_traverse(found_types, root: false)
|
134
|
-
orphan_types(
|
135
|
+
orphan_types(object_types)
|
135
136
|
query query_root_type
|
136
137
|
mutation mutation_root_type
|
137
138
|
subscription subscription_root_type
|
@@ -141,6 +142,12 @@ module GraphQL
|
|
141
142
|
raise InvalidDocumentError, "Type \"#{type_name}\" not found in document.", err_backtrace
|
142
143
|
end
|
143
144
|
|
145
|
+
object_types.each do |t|
|
146
|
+
t.interfaces.each do |int_t|
|
147
|
+
int_t.orphan_types(t)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
144
151
|
if default_resolve.respond_to?(:resolve_type)
|
145
152
|
def self.resolve_type(*args)
|
146
153
|
self.definition_default_resolve.resolve_type(*args)
|
@@ -7,7 +7,7 @@ module GraphQL
|
|
7
7
|
# In this case, the server hides types and fields _entirely_, unless the current context has certain `:flags` present.
|
8
8
|
class Flagged < GraphQL::Schema::Directive
|
9
9
|
def initialize(target, **options)
|
10
|
-
if target.is_a?(Module)
|
10
|
+
if target.is_a?(Module)
|
11
11
|
# This is type class of some kind, `include` will put this module
|
12
12
|
# in between the type class itself and its super class, so `super` will work fine
|
13
13
|
target.include(VisibleByFlag)
|
@@ -188,6 +188,8 @@ module GraphQL
|
|
188
188
|
assert_has_location(SCALAR)
|
189
189
|
elsif @owner < GraphQL::Schema
|
190
190
|
assert_has_location(SCHEMA)
|
191
|
+
elsif @owner < GraphQL::Schema::Resolver
|
192
|
+
assert_has_location(FIELD_DEFINITION)
|
191
193
|
else
|
192
194
|
raise "Unexpected directive owner class: #{@owner}"
|
193
195
|
end
|
data/lib/graphql/schema/enum.rb
CHANGED
@@ -130,7 +130,7 @@ module GraphQL
|
|
130
130
|
end
|
131
131
|
|
132
132
|
def validate_non_null_input(value_name, ctx, max_errors: nil)
|
133
|
-
allowed_values = ctx.
|
133
|
+
allowed_values = ctx.types.enum_values(self)
|
134
134
|
matching_value = allowed_values.find { |v| v.graphql_name == value_name }
|
135
135
|
|
136
136
|
if matching_value.nil?
|
@@ -141,8 +141,8 @@ module GraphQL
|
|
141
141
|
end
|
142
142
|
|
143
143
|
def coerce_result(value, ctx)
|
144
|
-
|
145
|
-
all_values =
|
144
|
+
types = ctx.types
|
145
|
+
all_values = types ? types.enum_values(self) : values.each_value
|
146
146
|
enum_value = all_values.find { |val| val.value == value }
|
147
147
|
if enum_value
|
148
148
|
enum_value.graphql_name
|
@@ -152,7 +152,7 @@ module GraphQL
|
|
152
152
|
end
|
153
153
|
|
154
154
|
def coerce_input(value_name, ctx)
|
155
|
-
all_values = ctx.
|
155
|
+
all_values = ctx.types ? ctx.types.enum_values(self) : values.each_value
|
156
156
|
|
157
157
|
if v = all_values.find { |val| val.graphql_name == value_name }
|
158
158
|
v.value
|
@@ -166,7 +166,11 @@ module GraphQL
|
|
166
166
|
end
|
167
167
|
|
168
168
|
def inherited(child_class)
|
169
|
-
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
|
170
174
|
super
|
171
175
|
end
|
172
176
|
|
@@ -50,7 +50,7 @@ module GraphQL
|
|
50
50
|
if field.has_default_page_size? && !value.has_default_page_size_override?
|
51
51
|
value.default_page_size = field.default_page_size
|
52
52
|
end
|
53
|
-
if
|
53
|
+
if (custom_t = context.schema.connections.edge_class_for_field(@field))
|
54
54
|
value.edge_class = custom_t
|
55
55
|
end
|
56
56
|
value
|
data/lib/graphql/schema/field.rb
CHANGED
@@ -41,6 +41,18 @@ module GraphQL
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
def directives
|
45
|
+
if @resolver_class && (r_dirs = @resolver_class.directives).any?
|
46
|
+
if (own_dirs = super).any?
|
47
|
+
own_dirs + r_dirs
|
48
|
+
else
|
49
|
+
r_dirs
|
50
|
+
end
|
51
|
+
else
|
52
|
+
super
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
44
56
|
# @return [Class] The thing this field was defined on (type, mutation, resolver)
|
45
57
|
attr_accessor :owner
|
46
58
|
|
@@ -606,7 +618,7 @@ module GraphQL
|
|
606
618
|
using_arg_values = false
|
607
619
|
end
|
608
620
|
|
609
|
-
args = context.
|
621
|
+
args = context.types.arguments(self)
|
610
622
|
args.each do |arg|
|
611
623
|
arg_key = arg.keyword
|
612
624
|
if arg_values.key?(arg_key)
|
@@ -149,7 +149,8 @@ module GraphQL
|
|
149
149
|
|
150
150
|
def authorize_arguments(args, values)
|
151
151
|
# remove the `input` wrapper to match values
|
152
|
-
|
152
|
+
input_type = args.find { |a| a.graphql_name == "input" }.type.unwrap
|
153
|
+
input_args = context.types.arguments(input_type)
|
153
154
|
super(input_args, values)
|
154
155
|
end
|
155
156
|
end
|
@@ -23,7 +23,8 @@ module GraphQL
|
|
23
23
|
@ruby_style_hash = ruby_kwargs
|
24
24
|
@arguments = arguments
|
25
25
|
# Apply prepares, not great to have it duplicated here.
|
26
|
-
self.class.arguments(context).each_value
|
26
|
+
arg_defns = context ? context.types.arguments(self.class) : self.class.arguments(context).each_value
|
27
|
+
arg_defns.each do |arg_defn|
|
27
28
|
ruby_kwargs_key = arg_defn.keyword
|
28
29
|
if @ruby_style_hash.key?(ruby_kwargs_key)
|
29
30
|
# Weirdly, procs are applied during coercion, but not methods.
|
@@ -58,7 +59,7 @@ module GraphQL
|
|
58
59
|
def self.authorized?(obj, value, ctx)
|
59
60
|
# Authorize each argument (but this doesn't apply if `prepare` is implemented):
|
60
61
|
if value.respond_to?(:key?)
|
61
|
-
arguments(
|
62
|
+
ctx.types.arguments(self).each do |input_obj_arg|
|
62
63
|
if value.key?(input_obj_arg.keyword) &&
|
63
64
|
!input_obj_arg.authorized?(obj, value[input_obj_arg.keyword], ctx)
|
64
65
|
return false
|
@@ -149,7 +150,7 @@ module GraphQL
|
|
149
150
|
INVALID_OBJECT_MESSAGE = "Expected %{object} to be a key-value object."
|
150
151
|
|
151
152
|
def validate_non_null_input(input, ctx, max_errors: nil)
|
152
|
-
|
153
|
+
types = ctx.types
|
153
154
|
|
154
155
|
if input.is_a?(Array)
|
155
156
|
return GraphQL::Query::InputValidationResult.from_problem(INVALID_OBJECT_MESSAGE % { object: JSON.generate(input, quirks_mode: true) })
|
@@ -161,9 +162,9 @@ module GraphQL
|
|
161
162
|
end
|
162
163
|
|
163
164
|
# Inject missing required arguments
|
164
|
-
missing_required_inputs =
|
165
|
-
if !input.key?(
|
166
|
-
m[
|
165
|
+
missing_required_inputs = ctx.types.arguments(self).reduce({}) do |m, (argument)|
|
166
|
+
if !input.key?(argument.graphql_name) && argument.type.non_null? && types.argument(self, argument.graphql_name)
|
167
|
+
m[argument.graphql_name] = nil
|
167
168
|
end
|
168
169
|
|
169
170
|
m
|
@@ -172,7 +173,7 @@ module GraphQL
|
|
172
173
|
result = nil
|
173
174
|
[input, missing_required_inputs].each do |args_to_validate|
|
174
175
|
args_to_validate.each do |argument_name, value|
|
175
|
-
argument =
|
176
|
+
argument = types.argument(self, argument_name)
|
176
177
|
# Items in the input that are unexpected
|
177
178
|
if argument.nil?
|
178
179
|
result ||= Query::InputValidationResult.new
|