graphql 2.0.27 → 2.1.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/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +2 -0
- data/lib/generators/graphql/templates/base_edge.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/node_type.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +2 -0
- data/lib/graphql/analysis/ast/analyzer.rb +7 -0
- data/lib/graphql/analysis/ast/query_depth.rb +7 -2
- data/lib/graphql/analysis/ast/visitor.rb +2 -2
- data/lib/graphql/analysis/ast.rb +15 -11
- data/lib/graphql/dataloader/source.rb +7 -0
- data/lib/graphql/dataloader.rb +38 -10
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +170 -0
- data/lib/graphql/execution/interpreter/runtime.rb +95 -254
- data/lib/graphql/execution/interpreter.rb +0 -6
- data/lib/graphql/execution/lookahead.rb +1 -1
- data/lib/graphql/introspection/dynamic_fields.rb +1 -1
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/language/block_string.rb +28 -16
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +36 -35
- data/lib/graphql/language/nodes.rb +2 -2
- data/lib/graphql/language/printer.rb +294 -145
- data/lib/graphql/language/sanitized_printer.rb +20 -22
- data/lib/graphql/language/static_visitor.rb +167 -0
- data/lib/graphql/language/visitor.rb +20 -81
- data/lib/graphql/language.rb +1 -0
- data/lib/graphql/pagination/connection.rb +23 -1
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +32 -98
- data/lib/graphql/query.rb +2 -19
- data/lib/graphql/rake_task.rb +3 -12
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/field/connection_extension.rb +1 -15
- data/lib/graphql/schema/field/scope_extension.rb +7 -1
- data/lib/graphql/schema/field.rb +7 -4
- data/lib/graphql/schema/has_single_input_argument.rb +156 -0
- data/lib/graphql/schema/introspection_system.rb +2 -0
- data/lib/graphql/schema/member/base_dsl_methods.rb +2 -1
- data/lib/graphql/schema/member/has_arguments.rb +19 -4
- data/lib/graphql/schema/member/has_fields.rb +4 -1
- data/lib/graphql/schema/member/has_interfaces.rb +21 -7
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/object.rb +8 -0
- data/lib/graphql/schema/printer.rb +8 -7
- data/lib/graphql/schema/relay_classic_mutation.rb +6 -128
- data/lib/graphql/schema/resolver.rb +4 -0
- data/lib/graphql/schema/scalar.rb +3 -3
- data/lib/graphql/schema/subscription.rb +11 -4
- data/lib/graphql/schema/warden.rb +87 -89
- data/lib/graphql/schema.rb +125 -55
- data/lib/graphql/static_validation/all_rules.rb +1 -1
- data/lib/graphql/static_validation/base_visitor.rb +1 -1
- data/lib/graphql/static_validation/literal_validator.rb +1 -1
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +1 -1
- data/lib/graphql/static_validation/validation_context.rb +5 -5
- data/lib/graphql/static_validation.rb +0 -1
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +2 -1
- data/lib/graphql/subscriptions.rb +11 -6
- data/lib/graphql/tracing/appoptics_trace.rb +2 -2
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
- data/lib/graphql/types/relay/connection_behaviors.rb +19 -2
- data/lib/graphql/types/relay/edge_behaviors.rb +7 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +1 -2
- metadata +23 -20
- data/lib/graphql/filter.rb +0 -59
- data/lib/graphql/static_validation/type_stack.rb +0 -216
@@ -40,7 +40,7 @@ module GraphQL
|
|
40
40
|
case node
|
41
41
|
when FalseClass, Float, Integer, String, TrueClass
|
42
42
|
if @current_argument && redact_argument_value?(@current_argument, node)
|
43
|
-
redacted_argument_value(@current_argument)
|
43
|
+
print_string(redacted_argument_value(@current_argument))
|
44
44
|
else
|
45
45
|
super
|
46
46
|
end
|
@@ -51,9 +51,8 @@ module GraphQL
|
|
51
51
|
@current_input_type = @current_input_type.of_type if @current_input_type.non_null?
|
52
52
|
end
|
53
53
|
|
54
|
-
|
54
|
+
super
|
55
55
|
@current_input_type = old_input_type
|
56
|
-
res
|
57
56
|
else
|
58
57
|
super
|
59
58
|
end
|
@@ -89,11 +88,12 @@ module GraphQL
|
|
89
88
|
else
|
90
89
|
argument.value
|
91
90
|
end
|
92
|
-
|
91
|
+
|
92
|
+
print_string("#{argument.name}: ")
|
93
|
+
print_node(argument_value)
|
93
94
|
|
94
95
|
@current_input_type = old_input_type
|
95
96
|
@current_argument = old_current_argument
|
96
|
-
res
|
97
97
|
end
|
98
98
|
|
99
99
|
def coerce_argument_value_to_list?(type, value)
|
@@ -116,9 +116,8 @@ module GraphQL
|
|
116
116
|
@current_field = query.get_field(@current_type, field.name)
|
117
117
|
old_type = @current_type
|
118
118
|
@current_type = @current_field.type.unwrap
|
119
|
-
|
119
|
+
super
|
120
120
|
@current_type = old_type
|
121
|
-
res
|
122
121
|
end
|
123
122
|
|
124
123
|
def print_inline_fragment(inline_fragment, indent: "")
|
@@ -128,31 +127,26 @@ module GraphQL
|
|
128
127
|
@current_type = query.get_type(inline_fragment.type.name)
|
129
128
|
end
|
130
129
|
|
131
|
-
|
130
|
+
super
|
132
131
|
|
133
132
|
@current_type = old_type
|
134
|
-
|
135
|
-
res
|
136
133
|
end
|
137
134
|
|
138
135
|
def print_fragment_definition(fragment_def, indent: "")
|
139
136
|
old_type = @current_type
|
140
137
|
@current_type = query.get_type(fragment_def.type.name)
|
141
138
|
|
142
|
-
|
139
|
+
super
|
143
140
|
|
144
141
|
@current_type = old_type
|
145
|
-
|
146
|
-
res
|
147
142
|
end
|
148
143
|
|
149
144
|
def print_directive(directive)
|
150
145
|
@current_directive = query.schema.directives[directive.name]
|
151
146
|
|
152
|
-
|
147
|
+
super
|
153
148
|
|
154
149
|
@current_directive = nil
|
155
|
-
res
|
156
150
|
end
|
157
151
|
|
158
152
|
# Print the operation definition but do not include the variable
|
@@ -162,16 +156,15 @@ module GraphQL
|
|
162
156
|
@current_type = query.schema.public_send(operation_definition.operation_type)
|
163
157
|
|
164
158
|
if @inline_variables
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
159
|
+
print_string("#{indent}#{operation_definition.operation_type}")
|
160
|
+
print_string(" #{operation_definition.name}") if operation_definition.name
|
161
|
+
print_directives(operation_definition.directives)
|
162
|
+
print_selections(operation_definition.selections, indent: indent)
|
169
163
|
else
|
170
|
-
|
164
|
+
super
|
171
165
|
end
|
172
166
|
|
173
167
|
@current_type = old_type
|
174
|
-
out
|
175
168
|
end
|
176
169
|
|
177
170
|
private
|
@@ -210,7 +203,12 @@ module GraphQL
|
|
210
203
|
[value].map { |v| value_to_ast(v, type.of_type) }
|
211
204
|
end
|
212
205
|
when "ENUM"
|
213
|
-
GraphQL::Language::Nodes::Enum
|
206
|
+
if value.is_a?(GraphQL::Language::Nodes::Enum)
|
207
|
+
# if it was a default value, it's already wrapped
|
208
|
+
value
|
209
|
+
else
|
210
|
+
GraphQL::Language::Nodes::Enum.new(name: value)
|
211
|
+
end
|
214
212
|
else
|
215
213
|
value
|
216
214
|
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
module Language
|
4
|
+
# Like `GraphQL::Language::Visitor` except it doesn't support
|
5
|
+
# making changes to the document -- only visiting it as-is.
|
6
|
+
class StaticVisitor
|
7
|
+
def initialize(document)
|
8
|
+
@document = document
|
9
|
+
end
|
10
|
+
|
11
|
+
# Visit `document` and all children
|
12
|
+
# @return [void]
|
13
|
+
def visit
|
14
|
+
# `@document` may be any kind of node:
|
15
|
+
visit_method = @document.visit_method
|
16
|
+
result = public_send(visit_method, @document, nil)
|
17
|
+
@result = if result.is_a?(Array)
|
18
|
+
result.first
|
19
|
+
else
|
20
|
+
# The node wasn't modified
|
21
|
+
@document
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# We don't use `alias` here because it breaks `super`
|
26
|
+
def self.make_visit_methods(ast_node_class)
|
27
|
+
node_method = ast_node_class.visit_method
|
28
|
+
children_of_type = ast_node_class.children_of_type
|
29
|
+
child_visit_method = :"#{node_method}_children"
|
30
|
+
|
31
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
32
|
+
# The default implementation for visiting an AST node.
|
33
|
+
# It doesn't _do_ anything, but it continues to visiting the node's children.
|
34
|
+
# To customize this hook, override one of its make_visit_methods (or the base method?)
|
35
|
+
# in your subclasses.
|
36
|
+
#
|
37
|
+
# @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
|
38
|
+
# @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
|
39
|
+
# @return [void]
|
40
|
+
def #{node_method}(node, parent)
|
41
|
+
#{
|
42
|
+
if method_defined?(child_visit_method)
|
43
|
+
"#{child_visit_method}(node)"
|
44
|
+
elsif children_of_type
|
45
|
+
children_of_type.map do |child_accessor, child_class|
|
46
|
+
"node.#{child_accessor}.each do |child_node|
|
47
|
+
#{child_class.visit_method}(child_node, node)
|
48
|
+
end"
|
49
|
+
end.join("\n")
|
50
|
+
else
|
51
|
+
""
|
52
|
+
end
|
53
|
+
}
|
54
|
+
end
|
55
|
+
RUBY
|
56
|
+
end
|
57
|
+
|
58
|
+
def on_document_children(document_node)
|
59
|
+
document_node.children.each do |child_node|
|
60
|
+
visit_method = child_node.visit_method
|
61
|
+
public_send(visit_method, child_node, document_node)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def on_field_children(new_node)
|
66
|
+
new_node.arguments.each do |arg_node| # rubocop:disable Development/ContextIsPassedCop
|
67
|
+
on_argument(arg_node, new_node)
|
68
|
+
end
|
69
|
+
visit_directives(new_node)
|
70
|
+
visit_selections(new_node)
|
71
|
+
end
|
72
|
+
|
73
|
+
def visit_directives(new_node)
|
74
|
+
new_node.directives.each do |dir_node|
|
75
|
+
on_directive(dir_node, new_node)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def visit_selections(new_node)
|
80
|
+
new_node.selections.each do |selection|
|
81
|
+
case selection
|
82
|
+
when GraphQL::Language::Nodes::Field
|
83
|
+
on_field(selection, new_node)
|
84
|
+
when GraphQL::Language::Nodes::InlineFragment
|
85
|
+
on_inline_fragment(selection, new_node)
|
86
|
+
when GraphQL::Language::Nodes::FragmentSpread
|
87
|
+
on_fragment_spread(selection, new_node)
|
88
|
+
else
|
89
|
+
raise ArgumentError, "Invariant: unexpected field selection #{selection.class} (#{selection.inspect})"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def on_fragment_definition_children(new_node)
|
95
|
+
visit_directives(new_node)
|
96
|
+
visit_selections(new_node)
|
97
|
+
end
|
98
|
+
|
99
|
+
alias :on_inline_fragment_children :on_fragment_definition_children
|
100
|
+
|
101
|
+
def on_operation_definition_children(new_node)
|
102
|
+
new_node.variables.each do |arg_node|
|
103
|
+
on_variable_definition(arg_node, new_node)
|
104
|
+
end
|
105
|
+
visit_directives(new_node)
|
106
|
+
visit_selections(new_node)
|
107
|
+
end
|
108
|
+
|
109
|
+
def on_argument_children(new_node)
|
110
|
+
new_node.children.each do |value_node|
|
111
|
+
case value_node
|
112
|
+
when Language::Nodes::VariableIdentifier
|
113
|
+
on_variable_identifier(value_node, new_node)
|
114
|
+
when Language::Nodes::InputObject
|
115
|
+
on_input_object(value_node, new_node)
|
116
|
+
when Language::Nodes::Enum
|
117
|
+
on_enum(value_node, new_node)
|
118
|
+
when Language::Nodes::NullValue
|
119
|
+
on_null_value(value_node, new_node)
|
120
|
+
else
|
121
|
+
raise ArgumentError, "Invariant: unexpected argument value node #{value_node.class} (#{value_node.inspect})"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
[
|
127
|
+
Language::Nodes::Argument,
|
128
|
+
Language::Nodes::Directive,
|
129
|
+
Language::Nodes::DirectiveDefinition,
|
130
|
+
Language::Nodes::DirectiveLocation,
|
131
|
+
Language::Nodes::Document,
|
132
|
+
Language::Nodes::Enum,
|
133
|
+
Language::Nodes::EnumTypeDefinition,
|
134
|
+
Language::Nodes::EnumTypeExtension,
|
135
|
+
Language::Nodes::EnumValueDefinition,
|
136
|
+
Language::Nodes::Field,
|
137
|
+
Language::Nodes::FieldDefinition,
|
138
|
+
Language::Nodes::FragmentDefinition,
|
139
|
+
Language::Nodes::FragmentSpread,
|
140
|
+
Language::Nodes::InlineFragment,
|
141
|
+
Language::Nodes::InputObject,
|
142
|
+
Language::Nodes::InputObjectTypeDefinition,
|
143
|
+
Language::Nodes::InputObjectTypeExtension,
|
144
|
+
Language::Nodes::InputValueDefinition,
|
145
|
+
Language::Nodes::InterfaceTypeDefinition,
|
146
|
+
Language::Nodes::InterfaceTypeExtension,
|
147
|
+
Language::Nodes::ListType,
|
148
|
+
Language::Nodes::NonNullType,
|
149
|
+
Language::Nodes::NullValue,
|
150
|
+
Language::Nodes::ObjectTypeDefinition,
|
151
|
+
Language::Nodes::ObjectTypeExtension,
|
152
|
+
Language::Nodes::OperationDefinition,
|
153
|
+
Language::Nodes::ScalarTypeDefinition,
|
154
|
+
Language::Nodes::ScalarTypeExtension,
|
155
|
+
Language::Nodes::SchemaDefinition,
|
156
|
+
Language::Nodes::SchemaExtension,
|
157
|
+
Language::Nodes::TypeName,
|
158
|
+
Language::Nodes::UnionTypeDefinition,
|
159
|
+
Language::Nodes::UnionTypeExtension,
|
160
|
+
Language::Nodes::VariableDefinition,
|
161
|
+
Language::Nodes::VariableIdentifier,
|
162
|
+
].each do |ast_node_class|
|
163
|
+
make_visit_methods(ast_node_class)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -30,12 +30,9 @@ module GraphQL
|
|
30
30
|
# # Check the result
|
31
31
|
# visitor.count
|
32
32
|
# # => 3
|
33
|
+
#
|
34
|
+
# @see GraphQL::Language::StaticVisitor for a faster visitor that doesn't support modifying the document
|
33
35
|
class Visitor
|
34
|
-
# If any hook returns this value, the {Visitor} stops visiting this
|
35
|
-
# node right away
|
36
|
-
# @deprecated Use `super` to continue the visit; or don't call it to halt.
|
37
|
-
SKIP = :_skip
|
38
|
-
|
39
36
|
class DeleteNode; end
|
40
37
|
|
41
38
|
# When this is returned from a visitor method,
|
@@ -44,25 +41,13 @@ module GraphQL
|
|
44
41
|
|
45
42
|
def initialize(document)
|
46
43
|
@document = document
|
47
|
-
@visitors = {}
|
48
44
|
@result = nil
|
49
45
|
end
|
50
46
|
|
51
47
|
# @return [GraphQL::Language::Nodes::Document] The document with any modifications applied
|
52
48
|
attr_reader :result
|
53
49
|
|
54
|
-
#
|
55
|
-
# @param node_class [Class] The node class that you want to listen to
|
56
|
-
# @return [NodeVisitor]
|
57
|
-
#
|
58
|
-
# @example Run a hook whenever you enter a new Field
|
59
|
-
# visitor[GraphQL::Language::Nodes::Field] << ->(node, parent) { p "Here's a field" }
|
60
|
-
# @deprecated see `on_` methods, like {#on_field}
|
61
|
-
def [](node_class)
|
62
|
-
@visitors[node_class] ||= NodeVisitor.new
|
63
|
-
end
|
64
|
-
|
65
|
-
# Visit `document` and all children, applying hooks as you go
|
50
|
+
# Visit `document` and all children
|
66
51
|
# @return [void]
|
67
52
|
def visit
|
68
53
|
# `@document` may be any kind of node:
|
@@ -88,7 +73,6 @@ module GraphQL
|
|
88
73
|
# To customize this hook, override one of its make_visit_methods (or the base method?)
|
89
74
|
# in your subclasses.
|
90
75
|
#
|
91
|
-
# For compatibility, it calls hook procs, too.
|
92
76
|
# @param node [GraphQL::Language::Nodes::AbstractNode] the node being visited
|
93
77
|
# @param parent [GraphQL::Language::Nodes::AbstractNode, nil] the previously-visited node, or `nil` if this is the root node.
|
94
78
|
# @return [Array, nil] If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.
|
@@ -98,29 +82,24 @@ module GraphQL
|
|
98
82
|
# by a user hook, don't want to keep visiting in that case.
|
99
83
|
[node, parent]
|
100
84
|
else
|
101
|
-
# Run hooks if there are any
|
102
85
|
new_node = node
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
end
|
121
|
-
}
|
122
|
-
end
|
123
|
-
end_visit(new_node, parent) unless no_hooks
|
86
|
+
#{
|
87
|
+
if method_defined?(child_visit_method)
|
88
|
+
"new_node = #{child_visit_method}(new_node)"
|
89
|
+
elsif children_of_type
|
90
|
+
children_of_type.map do |child_accessor, child_class|
|
91
|
+
"node.#{child_accessor}.each do |child_node|
|
92
|
+
new_child_and_node = #{child_class.visit_method}_with_modifications(child_node, new_node)
|
93
|
+
# Reassign `node` in case the child hook makes a modification
|
94
|
+
if new_child_and_node.is_a?(Array)
|
95
|
+
new_node = new_child_and_node[1]
|
96
|
+
end
|
97
|
+
end"
|
98
|
+
end.join("\n")
|
99
|
+
else
|
100
|
+
""
|
101
|
+
end
|
102
|
+
}
|
124
103
|
|
125
104
|
if new_node.equal?(node)
|
126
105
|
[node, parent]
|
@@ -305,46 +284,6 @@ module GraphQL
|
|
305
284
|
new_node_and_new_parent
|
306
285
|
end
|
307
286
|
end
|
308
|
-
|
309
|
-
def begin_visit(node, parent)
|
310
|
-
node_visitor = self[node.class]
|
311
|
-
self.class.apply_hooks(node_visitor.enter, node, parent)
|
312
|
-
end
|
313
|
-
|
314
|
-
# Should global `leave` visitors come first or last?
|
315
|
-
def end_visit(node, parent)
|
316
|
-
node_visitor = self[node.class]
|
317
|
-
self.class.apply_hooks(node_visitor.leave, node, parent)
|
318
|
-
end
|
319
|
-
|
320
|
-
# If one of the visitors returns SKIP, stop visiting this node
|
321
|
-
def self.apply_hooks(hooks, node, parent)
|
322
|
-
hooks.each do |proc|
|
323
|
-
return false if proc.call(node, parent) == SKIP
|
324
|
-
end
|
325
|
-
true
|
326
|
-
end
|
327
|
-
|
328
|
-
# Collect `enter` and `leave` hooks for classes in {GraphQL::Language::Nodes}
|
329
|
-
#
|
330
|
-
# Access {NodeVisitor}s via {GraphQL::Language::Visitor#[]}
|
331
|
-
class NodeVisitor
|
332
|
-
# @return [Array<Proc>] Hooks to call when entering a node of this type
|
333
|
-
attr_reader :enter
|
334
|
-
# @return [Array<Proc>] Hooks to call when leaving a node of this type
|
335
|
-
attr_reader :leave
|
336
|
-
|
337
|
-
def initialize
|
338
|
-
@enter = []
|
339
|
-
@leave = []
|
340
|
-
end
|
341
|
-
|
342
|
-
# Shorthand to add a hook to the {#enter} array
|
343
|
-
# @param hook [Proc] A hook to add
|
344
|
-
def <<(hook)
|
345
|
-
enter << hook
|
346
|
-
end
|
347
|
-
end
|
348
287
|
end
|
349
288
|
end
|
350
289
|
end
|
data/lib/graphql/language.rb
CHANGED
@@ -8,6 +8,7 @@ require "graphql/language/lexer"
|
|
8
8
|
require "graphql/language/nodes"
|
9
9
|
require "graphql/language/cache"
|
10
10
|
require "graphql/language/parser"
|
11
|
+
require "graphql/language/static_visitor"
|
11
12
|
require "graphql/language/token"
|
12
13
|
require "graphql/language/visitor"
|
13
14
|
require "graphql/language/definition_slice"
|
@@ -19,7 +19,14 @@ module GraphQL
|
|
19
19
|
attr_reader :items
|
20
20
|
|
21
21
|
# @return [GraphQL::Query::Context]
|
22
|
-
|
22
|
+
attr_reader :context
|
23
|
+
|
24
|
+
def context=(new_ctx)
|
25
|
+
current_runtime_state = Thread.current[:__graphql_runtime_info]
|
26
|
+
query_runtime_state = current_runtime_state[new_ctx.query]
|
27
|
+
@was_authorized_by_scope_items = query_runtime_state.was_authorized_by_scope_items
|
28
|
+
@context = new_ctx
|
29
|
+
end
|
23
30
|
|
24
31
|
# @return [Object] the object this collection belongs to
|
25
32
|
attr_accessor :parent
|
@@ -83,6 +90,17 @@ module GraphQL
|
|
83
90
|
else
|
84
91
|
default_page_size
|
85
92
|
end
|
93
|
+
@was_authorized_by_scope_items = if @context
|
94
|
+
current_runtime_state = Thread.current[:__graphql_runtime_info]
|
95
|
+
query_runtime_state = current_runtime_state[@context.query]
|
96
|
+
query_runtime_state.was_authorized_by_scope_items
|
97
|
+
else
|
98
|
+
nil
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def was_authorized_by_scope_items?
|
103
|
+
@was_authorized_by_scope_items
|
86
104
|
end
|
87
105
|
|
88
106
|
def max_page_size=(new_value)
|
@@ -247,6 +265,10 @@ module GraphQL
|
|
247
265
|
def cursor
|
248
266
|
@cursor ||= @connection.cursor_for(@node)
|
249
267
|
end
|
268
|
+
|
269
|
+
def was_authorized_by_scope_items?
|
270
|
+
@connection.was_authorized_by_scope_items?
|
271
|
+
end
|
250
272
|
end
|
251
273
|
end
|
252
274
|
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
class Query
|
4
|
+
class Context
|
5
|
+
class ScopedContext
|
6
|
+
def initialize(query_context)
|
7
|
+
@query_context = query_context
|
8
|
+
@scoped_contexts = nil
|
9
|
+
@all_keys = nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def merged_context
|
13
|
+
if @scoped_contexts.nil?
|
14
|
+
GraphQL::EmptyObjects::EMPTY_HASH
|
15
|
+
else
|
16
|
+
merged_ctx = {}
|
17
|
+
each_present_path_ctx do |path_ctx|
|
18
|
+
merged_ctx = path_ctx.merge(merged_ctx)
|
19
|
+
end
|
20
|
+
merged_ctx
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def merge!(hash, at: current_path)
|
25
|
+
@all_keys ||= Set.new
|
26
|
+
@all_keys.merge(hash.keys)
|
27
|
+
ctx = @scoped_contexts ||= {}
|
28
|
+
at.each do |path_part|
|
29
|
+
ctx = ctx[path_part] ||= { parent: ctx }
|
30
|
+
end
|
31
|
+
this_scoped_ctx = ctx[:scoped_context] ||= {}
|
32
|
+
this_scoped_ctx.merge!(hash)
|
33
|
+
end
|
34
|
+
|
35
|
+
def key?(key)
|
36
|
+
if @all_keys && @all_keys.include?(key)
|
37
|
+
each_present_path_ctx do |path_ctx|
|
38
|
+
if path_ctx.key?(key)
|
39
|
+
return true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
def [](key)
|
47
|
+
each_present_path_ctx do |path_ctx|
|
48
|
+
if path_ctx.key?(key)
|
49
|
+
return path_ctx[key]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def current_path
|
56
|
+
@query_context.current_path || GraphQL::EmptyObjects::EMPTY_ARRAY
|
57
|
+
end
|
58
|
+
|
59
|
+
def dig(key, *other_keys)
|
60
|
+
each_present_path_ctx do |path_ctx|
|
61
|
+
if path_ctx.key?(key)
|
62
|
+
found_value = path_ctx[key]
|
63
|
+
if other_keys.any?
|
64
|
+
return found_value.dig(*other_keys)
|
65
|
+
else
|
66
|
+
return found_value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
# Start at the current location,
|
76
|
+
# but look up the tree for previously-assigned scoped values
|
77
|
+
def each_present_path_ctx
|
78
|
+
ctx = @scoped_contexts
|
79
|
+
if ctx.nil?
|
80
|
+
# no-op
|
81
|
+
else
|
82
|
+
current_path.each do |path_part|
|
83
|
+
if ctx.key?(path_part)
|
84
|
+
ctx = ctx[path_part]
|
85
|
+
else
|
86
|
+
break
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
while ctx
|
91
|
+
if (scoped_ctx = ctx[:scoped_context])
|
92
|
+
yield(scoped_ctx)
|
93
|
+
end
|
94
|
+
ctx = ctx[:parent]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|