graphql 1.7.2 → 1.7.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.
- 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
|