graphql 1.7.2 → 1.7.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql/backtrace/inspect_result.rb +1 -1
- data/lib/graphql/backtrace/table.rb +2 -2
- data/lib/graphql/input_object_type.rb +1 -1
- data/lib/graphql/query/arguments.rb +31 -45
- data/lib/graphql/query/literal_input.rb +1 -1
- data/lib/graphql/relay/base_connection.rb +4 -0
- data/lib/graphql/relay/edge.rb +5 -1
- data/lib/graphql/schema/traversal.rb +7 -4
- data/lib/graphql/version.rb +1 -1
- data/spec/graphql/backtrace_spec.rb +37 -1
- data/spec/graphql/introspection/type_by_name_field_spec.rb +38 -0
- data/spec/graphql/query/arguments_spec.rb +4 -2
- data/spec/graphql/relay/base_connection_spec.rb +11 -0
- data/spec/graphql/relay/edge_spec.rb +10 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '08e688c4046aa3130fe9f427f810356abc25abfc'
|
4
|
+
data.tar.gz: d2896b9042f2bab1dffd256551082168aa52288d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 624eb16565591d5df45dc69df9dc5cc7fa6b97ca9ff4d3745427df47e979a15e889458689f1e52d9f8a553b0974f738cb2cff703d1fc98dcc25cfbffee36f408
|
7
|
+
data.tar.gz: 0421334ac91f05b8a0adf48199b811eb81efbcfd4a0c543bf3ff58248e9db3c4c1ba036d5cbeffca69fcb12e10d07e88fa0cf9896cbfd081b884da5d62f5aa8c
|
@@ -87,7 +87,7 @@ module GraphQL
|
|
87
87
|
rows << [
|
88
88
|
"#{position}",
|
89
89
|
"#{field_name}#{field_alias ? " as #{field_alias}" : ""}",
|
90
|
-
ctx.object.inspect,
|
90
|
+
"#{ctx.object.inspect}",
|
91
91
|
ctx.irep_node.arguments.to_h.inspect,
|
92
92
|
Backtrace::InspectResult.inspect(top && @override_value ? @override_value : ctx.value),
|
93
93
|
]
|
@@ -107,7 +107,7 @@ module GraphQL
|
|
107
107
|
rows << [
|
108
108
|
"#{position}",
|
109
109
|
"#{op_type}#{op_name ? " #{op_name}" : ""}",
|
110
|
-
query.root_value.inspect,
|
110
|
+
"#{query.root_value.inspect}",
|
111
111
|
query.variables.to_h.inspect,
|
112
112
|
Backtrace::InspectResult.inspect(query.context.value),
|
113
113
|
]
|
@@ -1,48 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module GraphQL
|
3
3
|
class Query
|
4
|
-
class StaticArguments
|
5
|
-
attr_reader :argument_definitions
|
6
|
-
|
7
|
-
def initialize(argument_definitions:)
|
8
|
-
@argument_definitions = argument_definitions
|
9
|
-
end
|
10
|
-
|
11
|
-
def instantiate_arguments(values)
|
12
|
-
arg_class.new(values, argument_definitions: argument_definitions)
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def arg_class
|
18
|
-
@arg_class ||= begin
|
19
|
-
klass = Class.new(GraphQL::Query::Arguments).instance_exec(self) do |static_arguments|
|
20
|
-
static_arguments.argument_definitions.each do |_arg_name, arg_definition|
|
21
|
-
expose_as = arg_definition.expose_as.to_s
|
22
|
-
|
23
|
-
# Don't define a helper method if it would override something.
|
24
|
-
if instance_methods.include?(expose_as)
|
25
|
-
warn(
|
26
|
-
"Unable to define a helper for argument with name '#{expose_as}' "\
|
27
|
-
"as this is a reserved name. If you're using an argument such as "\
|
28
|
-
"`argument #{expose_as}`, consider renaming this argument.`"
|
29
|
-
)
|
30
|
-
next
|
31
|
-
end
|
32
|
-
|
33
|
-
define_method(expose_as) do
|
34
|
-
self[expose_as]
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
self
|
39
|
-
end
|
40
|
-
|
41
|
-
klass
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
4
|
# Read-only access to values, normalizing all keys to strings
|
47
5
|
#
|
48
6
|
# {Arguments} recursively wraps the input in {Arguments} instances.
|
@@ -50,8 +8,32 @@ module GraphQL
|
|
50
8
|
extend GraphQL::Delegate
|
51
9
|
|
52
10
|
def self.construct_arguments_class(argument_owner)
|
53
|
-
|
54
|
-
argument_owner.arguments_class =
|
11
|
+
argument_definitions = argument_owner.arguments
|
12
|
+
argument_owner.arguments_class = Class.new(self) do
|
13
|
+
self.argument_definitions = argument_definitions
|
14
|
+
|
15
|
+
def initialize(values)
|
16
|
+
super(values, argument_definitions: self.class.argument_definitions)
|
17
|
+
end
|
18
|
+
|
19
|
+
argument_definitions.each do |_arg_name, arg_definition|
|
20
|
+
expose_as = arg_definition.expose_as.to_s
|
21
|
+
|
22
|
+
# Don't define a helper method if it would override something.
|
23
|
+
if instance_methods.include?(expose_as)
|
24
|
+
warn(
|
25
|
+
"Unable to define a helper for argument with name '#{expose_as}' "\
|
26
|
+
"as this is a reserved name. If you're using an argument such as "\
|
27
|
+
"`argument #{expose_as}`, consider renaming this argument.`"
|
28
|
+
)
|
29
|
+
next
|
30
|
+
end
|
31
|
+
|
32
|
+
define_method(expose_as) do
|
33
|
+
self[expose_as]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
55
37
|
end
|
56
38
|
|
57
39
|
def initialize(values, argument_definitions:)
|
@@ -105,6 +87,10 @@ module GraphQL
|
|
105
87
|
|
106
88
|
NO_ARGS = self.new({}, argument_definitions: [])
|
107
89
|
|
90
|
+
class << self
|
91
|
+
attr_accessor :argument_definitions
|
92
|
+
end
|
93
|
+
|
108
94
|
private
|
109
95
|
|
110
96
|
class ArgumentValue
|
@@ -129,7 +115,7 @@ module GraphQL
|
|
129
115
|
wrap_value(value, arg_defn_type.of_type)
|
130
116
|
when GraphQL::InputObjectType
|
131
117
|
if value.is_a?(Hash)
|
132
|
-
|
118
|
+
arg_defn_type.arguments_class.new(value)
|
133
119
|
else
|
134
120
|
value
|
135
121
|
end
|
@@ -140,6 +140,10 @@ module GraphQL
|
|
140
140
|
raise NotImplementedError, "must return a cursor for this object/connection pair"
|
141
141
|
end
|
142
142
|
|
143
|
+
def inspect
|
144
|
+
"#<GraphQL::Relay::Connection @parent=#{@parent.inspect} @arguments=#{@arguments.to_h.inspect}>"
|
145
|
+
end
|
146
|
+
|
143
147
|
private
|
144
148
|
|
145
149
|
# Return a sanitized `arguments[arg_name]` (don't allow negatives)
|
data/lib/graphql/relay/edge.rb
CHANGED
@@ -4,7 +4,7 @@ module GraphQL
|
|
4
4
|
# Mostly an internal concern.
|
5
5
|
#
|
6
6
|
# Wraps an object as a `node`, and exposes a connection-specific `cursor`.
|
7
|
-
class Edge
|
7
|
+
class Edge
|
8
8
|
attr_reader :node, :connection
|
9
9
|
def initialize(node, connection)
|
10
10
|
@node = node
|
@@ -18,6 +18,10 @@ module GraphQL
|
|
18
18
|
def parent
|
19
19
|
@parent ||= connection.parent
|
20
20
|
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
"#<GraphQL::Relay::Edge (#{parent.inspect} => #{node.inspect})>"
|
24
|
+
end
|
21
25
|
end
|
22
26
|
end
|
23
27
|
end
|
@@ -104,10 +104,13 @@ module GraphQL
|
|
104
104
|
end
|
105
105
|
|
106
106
|
def visit_field_on_type(type_defn, field_defn, dynamic_field: false)
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
107
|
+
if dynamic_field
|
108
|
+
# Don't apply instrumentation to dynamic fields since they're shared constants
|
109
|
+
instrumented_field_defn = field_defn
|
110
|
+
else
|
111
|
+
instrumented_field_defn = @field_instrumenters.reduce(field_defn) do |defn, inst|
|
112
|
+
inst.instrument(type_defn, defn)
|
113
|
+
end
|
111
114
|
@instrumented_field_map[type_defn.name][instrumented_field_defn.name] = instrumented_field_defn
|
112
115
|
end
|
113
116
|
@type_reference_map[instrumented_field_defn.type.unwrap.name] << instrumented_field_defn
|
data/lib/graphql/version.rb
CHANGED
@@ -16,11 +16,25 @@ describe GraphQL::Backtrace do
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
+
class ErrorAnalyzer
|
20
|
+
def call(_memo, visit_type, irep_node)
|
21
|
+
if irep_node.name == "raiseError"
|
22
|
+
raise GraphQL::AnalysisError, "this should not be wrapped by a backtrace, but instead, returned to the client"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class NilInspectObject
|
28
|
+
# Oops, this is evil, but it happens and we should handle it.
|
29
|
+
def inspect; nil; end
|
30
|
+
end
|
31
|
+
|
19
32
|
let(:resolvers) {
|
20
33
|
{
|
21
34
|
"Query" => {
|
22
35
|
"field1" => Proc.new { :something },
|
23
36
|
"field2" => Proc.new { :something },
|
37
|
+
"nilInspect" => Proc.new { NilInspectObject.new },
|
24
38
|
},
|
25
39
|
"Thing" => {
|
26
40
|
"listField" => Proc.new { :not_a_list },
|
@@ -36,6 +50,7 @@ describe GraphQL::Backtrace do
|
|
36
50
|
type Query {
|
37
51
|
field1: Thing
|
38
52
|
field2: OtherThing
|
53
|
+
nilInspect: Thing
|
39
54
|
}
|
40
55
|
|
41
56
|
type Thing {
|
@@ -49,6 +64,7 @@ describe GraphQL::Backtrace do
|
|
49
64
|
GRAPHQL
|
50
65
|
GraphQL::Schema.from_definition(defn, default_resolve: resolvers).redefine {
|
51
66
|
lazy_resolve(LazyError, :raise_err)
|
67
|
+
query_analyzer(ErrorAnalyzer.new)
|
52
68
|
}
|
53
69
|
}
|
54
70
|
|
@@ -103,7 +119,7 @@ describe GraphQL::Backtrace do
|
|
103
119
|
assert_includes err.message, rendered_table
|
104
120
|
# The message includes the original error message
|
105
121
|
assert_includes err.message, "This is broken: Boom"
|
106
|
-
assert_includes err.message, "spec/graphql/backtrace_spec.rb:
|
122
|
+
assert_includes err.message, "spec/graphql/backtrace_spec.rb:41", "It includes the original backtrace"
|
107
123
|
assert_includes err.message, "more lines"
|
108
124
|
end
|
109
125
|
|
@@ -133,6 +149,26 @@ describe GraphQL::Backtrace do
|
|
133
149
|
].join("\n")
|
134
150
|
assert_includes err.message, rendered_table
|
135
151
|
end
|
152
|
+
|
153
|
+
it "returns analysis errors to the client" do
|
154
|
+
res = schema.execute("query raiseError { __typename }")
|
155
|
+
assert_equal "this should not be wrapped by a backtrace, but instead, returned to the client", res["errors"].first["message"]
|
156
|
+
end
|
157
|
+
|
158
|
+
it "always stringifies the #inspect response" do
|
159
|
+
err = assert_raises(GraphQL::Backtrace::TracedError) {
|
160
|
+
schema.execute("query { nilInspect { raiseField(message: \"pop!\") } }")
|
161
|
+
}
|
162
|
+
|
163
|
+
rendered_table = [
|
164
|
+
'Loc | Field | Object | Arguments | Result',
|
165
|
+
'1:22 | Thing.raiseField | | {"message"=>"pop!"} | #<RuntimeError: This is broken: pop!>',
|
166
|
+
'1:9 | Query.nilInspect | nil | {} | {}',
|
167
|
+
'1:1 | query | nil | {} | {}',
|
168
|
+
].join("\n")
|
169
|
+
|
170
|
+
assert_includes(err.message, rendered_table)
|
171
|
+
end
|
136
172
|
end
|
137
173
|
|
138
174
|
# This will get brittle when execution code moves between files
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe GraphQL::Introspection::TypeByNameField do
|
5
|
+
describe "after instrumentation" do
|
6
|
+
# Just make sure it returns a new object, not the original field
|
7
|
+
class DupInstrumenter
|
8
|
+
def self.instrument(t, f)
|
9
|
+
f.redefine {
|
10
|
+
resolve ->(o, a, c) { :no_op }
|
11
|
+
}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class ArgAnalyzer
|
16
|
+
def call(_, _, node)
|
17
|
+
if node.ast_node.is_a?(GraphQL::Language::Nodes::Field)
|
18
|
+
node.arguments
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:instrumented_schema) {
|
24
|
+
# This was probably assigned earlier in the test suite, but to simulate an application, clear it.
|
25
|
+
GraphQL::Introspection::TypeByNameField.arguments_class = nil
|
26
|
+
|
27
|
+
Dummy::Schema.redefine {
|
28
|
+
instrument(:field, DupInstrumenter)
|
29
|
+
query_analyzer(ArgAnalyzer.new)
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
it "still works with __type" do
|
34
|
+
res = instrumented_schema.execute("{ __type(name: \"X\") { name } }")
|
35
|
+
assert_equal({"data"=>{"__type"=>nil}}, res)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -90,13 +90,15 @@ describe GraphQL::Query::Arguments do
|
|
90
90
|
argument :b, test_input_type
|
91
91
|
argument :c, types.Int # will be a hash
|
92
92
|
end
|
93
|
+
GraphQL::Query::Arguments.construct_arguments_class(test_input_type)
|
94
|
+
test_input_type
|
93
95
|
}
|
94
96
|
it "wraps input objects, but not other hashes" do
|
95
97
|
args = GraphQL::Query::Arguments.new(
|
96
98
|
{a: 1, b: {a: 2}, c: {a: 3}},
|
97
99
|
argument_definitions: input_type.arguments
|
98
100
|
)
|
99
|
-
|
101
|
+
assert_kind_of GraphQL::Query::Arguments, args["b"]
|
100
102
|
assert_instance_of Hash, args["c"]
|
101
103
|
end
|
102
104
|
end
|
@@ -304,7 +306,7 @@ describe GraphQL::Query::Arguments do
|
|
304
306
|
assert_equal nil, input_object.arguments_class
|
305
307
|
|
306
308
|
GraphQL::Query::Arguments.construct_arguments_class(input_object)
|
307
|
-
args = input_object.arguments_class.
|
309
|
+
args = input_object.arguments_class.new({foo: 3, bar: -90})
|
308
310
|
|
309
311
|
assert_equal 3, args.foo
|
310
312
|
assert_equal -90, args.bar
|
@@ -49,6 +49,17 @@ describe GraphQL::Relay::BaseConnection do
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
+
describe "#inspect" do
|
53
|
+
it "inspects nicely" do
|
54
|
+
args = {
|
55
|
+
first: 1,
|
56
|
+
last: -1,
|
57
|
+
}
|
58
|
+
conn = GraphQL::Relay::BaseConnection.new([], args, context: context)
|
59
|
+
assert_equal "#<GraphQL::Relay::Connection @parent=nil @arguments={:first=>1, :last=>-1}>", conn.inspect
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
52
63
|
describe "#encode / #decode" do
|
53
64
|
module ReverseEncoder
|
54
65
|
module_function
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe GraphQL::Relay::Edge do
|
5
|
+
it "inspects nicely" do
|
6
|
+
connection = OpenStruct.new(parent: "Parent")
|
7
|
+
edge = GraphQL::Relay::Edge.new("Node", connection)
|
8
|
+
assert_equal '#<GraphQL::Relay::Edge ("Parent" => "Node")>', edge.inspect
|
9
|
+
end
|
10
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.7.
|
4
|
+
version: 1.7.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-09-
|
11
|
+
date: 2017-09-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|
@@ -568,6 +568,7 @@ files:
|
|
568
568
|
- spec/graphql/introspection/input_value_type_spec.rb
|
569
569
|
- spec/graphql/introspection/introspection_query_spec.rb
|
570
570
|
- spec/graphql/introspection/schema_type_spec.rb
|
571
|
+
- spec/graphql/introspection/type_by_name_field_spec.rb
|
571
572
|
- spec/graphql/introspection/type_type_spec.rb
|
572
573
|
- spec/graphql/language/definition_slice_spec.rb
|
573
574
|
- spec/graphql/language/equality_spec.rb
|
@@ -593,6 +594,7 @@ files:
|
|
593
594
|
- spec/graphql/relay/connection_instrumentation_spec.rb
|
594
595
|
- spec/graphql/relay/connection_resolve_spec.rb
|
595
596
|
- spec/graphql/relay/connection_type_spec.rb
|
597
|
+
- spec/graphql/relay/edge_spec.rb
|
596
598
|
- spec/graphql/relay/mutation_spec.rb
|
597
599
|
- spec/graphql/relay/node_spec.rb
|
598
600
|
- spec/graphql/relay/page_info_spec.rb
|
@@ -728,6 +730,7 @@ test_files:
|
|
728
730
|
- spec/graphql/introspection/input_value_type_spec.rb
|
729
731
|
- spec/graphql/introspection/introspection_query_spec.rb
|
730
732
|
- spec/graphql/introspection/schema_type_spec.rb
|
733
|
+
- spec/graphql/introspection/type_by_name_field_spec.rb
|
731
734
|
- spec/graphql/introspection/type_type_spec.rb
|
732
735
|
- spec/graphql/language/definition_slice_spec.rb
|
733
736
|
- spec/graphql/language/equality_spec.rb
|
@@ -753,6 +756,7 @@ test_files:
|
|
753
756
|
- spec/graphql/relay/connection_instrumentation_spec.rb
|
754
757
|
- spec/graphql/relay/connection_resolve_spec.rb
|
755
758
|
- spec/graphql/relay/connection_type_spec.rb
|
759
|
+
- spec/graphql/relay/edge_spec.rb
|
756
760
|
- spec/graphql/relay/mutation_spec.rb
|
757
761
|
- spec/graphql/relay/node_spec.rb
|
758
762
|
- spec/graphql/relay/page_info_spec.rb
|