graphql 1.8.3 → 1.8.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql.rb +4 -1
- data/lib/graphql/argument.rb +1 -0
- data/lib/graphql/authorization.rb +81 -0
- data/lib/graphql/boolean_type.rb +0 -1
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +2 -1
- data/lib/graphql/execution/execute.rb +34 -10
- data/lib/graphql/execution/lazy.rb +5 -1
- data/lib/graphql/field.rb +7 -1
- data/lib/graphql/float_type.rb +0 -1
- data/lib/graphql/id_type.rb +0 -1
- data/lib/graphql/int_type.rb +0 -1
- data/lib/graphql/introspection/entry_points.rb +2 -2
- data/lib/graphql/object_type.rb +3 -3
- data/lib/graphql/query.rb +6 -0
- data/lib/graphql/query/arguments.rb +2 -0
- data/lib/graphql/query/context.rb +6 -0
- data/lib/graphql/query/variables.rb +7 -1
- data/lib/graphql/relay/connection_instrumentation.rb +2 -2
- data/lib/graphql/relay/connection_resolve.rb +7 -27
- data/lib/graphql/relay/connection_type.rb +1 -0
- data/lib/graphql/relay/edge_type.rb +1 -0
- data/lib/graphql/relay/edges_instrumentation.rb +9 -25
- data/lib/graphql/relay/mutation/instrumentation.rb +1 -2
- data/lib/graphql/relay/mutation/resolve.rb +2 -4
- data/lib/graphql/relay/node.rb +1 -6
- data/lib/graphql/relay/page_info.rb +1 -9
- data/lib/graphql/schema.rb +84 -11
- data/lib/graphql/schema/argument.rb +13 -0
- data/lib/graphql/schema/enum.rb +1 -1
- data/lib/graphql/schema/enum_value.rb +4 -0
- data/lib/graphql/schema/field.rb +44 -11
- data/lib/graphql/schema/interface.rb +20 -0
- data/lib/graphql/schema/introspection_system.rb +1 -1
- data/lib/graphql/schema/member/base_dsl_methods.rb +25 -3
- data/lib/graphql/schema/member/instrumentation.rb +15 -17
- data/lib/graphql/schema/mutation.rb +4 -0
- data/lib/graphql/schema/object.rb +33 -0
- data/lib/graphql/schema/possible_types.rb +2 -0
- data/lib/graphql/schema/resolver.rb +10 -0
- data/lib/graphql/schema/traversal.rb +9 -2
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +11 -2
- data/lib/graphql/string_type.rb +0 -1
- data/lib/graphql/types.rb +7 -0
- data/lib/graphql/types/relay.rb +31 -0
- data/lib/graphql/types/relay/base_connection.rb +87 -0
- data/lib/graphql/types/relay/base_edge.rb +51 -0
- data/lib/graphql/types/relay/base_field.rb +22 -0
- data/lib/graphql/types/relay/base_interface.rb +29 -0
- data/lib/graphql/types/relay/base_object.rb +26 -0
- data/lib/graphql/types/relay/node.rb +18 -0
- data/lib/graphql/types/relay/page_info.rb +23 -0
- data/lib/graphql/unauthorized_error.rb +20 -0
- data/lib/graphql/version.rb +1 -1
- data/spec/graphql/authorization_spec.rb +684 -0
- data/spec/graphql/query/variables_spec.rb +20 -0
- data/spec/graphql/relay/connection_instrumentation_spec.rb +1 -1
- data/spec/graphql/schema/resolver_spec.rb +31 -0
- data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +52 -0
- data/spec/support/dummy/schema.rb +16 -0
- data/spec/support/star_wars/schema.rb +28 -17
- metadata +15 -2
@@ -110,6 +110,26 @@ describe GraphQL::Query::Variables do
|
|
110
110
|
assert_equal expected, variables.errors.first.message
|
111
111
|
end
|
112
112
|
end
|
113
|
+
|
114
|
+
describe "when provided input cannot be coerced" do
|
115
|
+
let(:query_string) {%|
|
116
|
+
query searchMyDairy (
|
117
|
+
$time: Time
|
118
|
+
) {
|
119
|
+
searchDairy(expiresAfter: $time) {
|
120
|
+
... on Cheese {
|
121
|
+
flavor
|
122
|
+
}
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|}
|
126
|
+
let(:provided_variables) { { "time" => "a" } }
|
127
|
+
|
128
|
+
it "validates invalid input objects" do
|
129
|
+
expected = "Variable time of type Time was provided invalid value"
|
130
|
+
assert_equal expected, variables.errors.first.message
|
131
|
+
end
|
132
|
+
end
|
113
133
|
end
|
114
134
|
|
115
135
|
describe "nullable variables" do
|
@@ -77,7 +77,7 @@ describe GraphQL::Relay::ConnectionInstrumentation do
|
|
77
77
|
# Before the object is wrapped in a connection, the instrumentation sees `Array`
|
78
78
|
assert_equal ["StarWars::FactionRecord", "Array", "GraphQL::Relay::ArrayConnection"], ctx[:before_built_ins]
|
79
79
|
# After the object is wrapped in a connection, it sees the connection object
|
80
|
-
assert_equal ["StarWars::Faction", "GraphQL::Relay::ArrayConnection", "GraphQL::Relay::
|
80
|
+
assert_equal ["StarWars::Faction", "GraphQL::Relay::ArrayConnection", "GraphQL::Types::Relay::PageInfo"], ctx[:after_built_ins]
|
81
81
|
end
|
82
82
|
end
|
83
83
|
end
|
@@ -49,6 +49,21 @@ describe GraphQL::Schema::Resolver do
|
|
49
49
|
class Resolver5 < Resolver4
|
50
50
|
end
|
51
51
|
|
52
|
+
class Resolver6 < Resolver1
|
53
|
+
type Integer, null: false
|
54
|
+
|
55
|
+
def resolve
|
56
|
+
self.class.complexity
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class Resolver7 < Resolver6
|
61
|
+
complexity 2
|
62
|
+
end
|
63
|
+
|
64
|
+
class Resolver8 < Resolver7
|
65
|
+
end
|
66
|
+
|
52
67
|
class Query < GraphQL::Schema::Object
|
53
68
|
class CustomField < GraphQL::Schema::Field
|
54
69
|
def resolve_field(*args)
|
@@ -68,6 +83,9 @@ describe GraphQL::Schema::Resolver do
|
|
68
83
|
field :resolver_3_again, resolver: Resolver3, description: "field desc"
|
69
84
|
field :resolver_4, "Positional description", resolver: Resolver4
|
70
85
|
field :resolver_5, resolver: Resolver5
|
86
|
+
field :resolver_6, resolver: Resolver6
|
87
|
+
field :resolver_7, resolver: Resolver7
|
88
|
+
field :resolver_8, resolver: Resolver8
|
71
89
|
end
|
72
90
|
|
73
91
|
class Schema < GraphQL::Schema
|
@@ -114,6 +132,19 @@ describe GraphQL::Schema::Resolver do
|
|
114
132
|
end
|
115
133
|
end
|
116
134
|
|
135
|
+
describe "complexity" do
|
136
|
+
it "has default values" do
|
137
|
+
res = ResolverTest::Schema.execute " { resolver6 } ", root_value: OpenStruct.new(value: 0)
|
138
|
+
assert_equal 1, res["data"]["resolver6"]
|
139
|
+
end
|
140
|
+
|
141
|
+
it "is inherited" do
|
142
|
+
res = ResolverTest::Schema.execute " { resolver7 resolver8 } ", root_value: OpenStruct.new(value: 0)
|
143
|
+
assert_equal 2, res["data"]["resolver7"]
|
144
|
+
assert_equal 2, res["data"]["resolver8"]
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
117
148
|
describe "when applied to a field" do
|
118
149
|
it "gets the field's description" do
|
119
150
|
assert_nil ResolverTest::Schema.find("Query.resolver3").description
|
data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb
CHANGED
@@ -134,4 +134,56 @@ describe GraphQL::StaticValidation::VariableDefaultValuesAreCorrectlyTyped do
|
|
134
134
|
end
|
135
135
|
end
|
136
136
|
end
|
137
|
+
|
138
|
+
describe "custom error messages" do
|
139
|
+
let(:schema) {
|
140
|
+
TimeType = GraphQL::ScalarType.define do
|
141
|
+
name "Time"
|
142
|
+
description "Time since epoch in seconds"
|
143
|
+
|
144
|
+
coerce_input ->(value, ctx) do
|
145
|
+
begin
|
146
|
+
Time.at(Float(value))
|
147
|
+
rescue ArgumentError
|
148
|
+
raise GraphQL::CoercionError, 'cannot coerce to Float'
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
coerce_result ->(value, ctx) { value.to_f }
|
153
|
+
end
|
154
|
+
|
155
|
+
QueryType = GraphQL::ObjectType.define do
|
156
|
+
name "Query"
|
157
|
+
description "The query root of this schema"
|
158
|
+
|
159
|
+
field :time do
|
160
|
+
type TimeType
|
161
|
+
argument :value, !TimeType
|
162
|
+
resolve ->(obj, args, ctx) { args[:value] }
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
GraphQL::Schema.define do
|
167
|
+
query QueryType
|
168
|
+
end
|
169
|
+
}
|
170
|
+
|
171
|
+
let(:query_string) {%|
|
172
|
+
query(
|
173
|
+
$value: Time = "a"
|
174
|
+
) {
|
175
|
+
time(value: $value)
|
176
|
+
}
|
177
|
+
|}
|
178
|
+
|
179
|
+
it "sets error message from a CoercionError if raised" do
|
180
|
+
assert_equal 1, errors.length
|
181
|
+
|
182
|
+
assert_includes errors, {
|
183
|
+
"message"=> "cannot coerce to Float",
|
184
|
+
"locations"=>[{"line"=>3, "column"=>9}],
|
185
|
+
"fields"=>["query"]
|
186
|
+
}
|
187
|
+
end
|
188
|
+
end
|
137
189
|
end
|
@@ -248,6 +248,21 @@ module Dummy
|
|
248
248
|
end
|
249
249
|
end
|
250
250
|
|
251
|
+
TimeType = GraphQL::ScalarType.define do
|
252
|
+
name "Time"
|
253
|
+
description "Time since epoch in seconds"
|
254
|
+
|
255
|
+
coerce_input ->(value, ctx) do
|
256
|
+
begin
|
257
|
+
Time.at(Float(value))
|
258
|
+
rescue ArgumentError
|
259
|
+
raise GraphQL::CoercionError, 'cannot coerce to Float'
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
coerce_result ->(value, ctx) { value.to_f }
|
264
|
+
end
|
265
|
+
|
251
266
|
class FetchItem < GraphQL::Function
|
252
267
|
attr_reader :type, :description, :arguments
|
253
268
|
|
@@ -312,6 +327,7 @@ module Dummy
|
|
312
327
|
type !DairyProductUnion
|
313
328
|
# This is a list just for testing 😬
|
314
329
|
argument :product, types[DairyProductInputType], default_value: [{"source" => "SHEEP"}]
|
330
|
+
argument :expiresAfter, TimeType
|
315
331
|
resolve ->(t, args, c) {
|
316
332
|
source = args["product"][0][:source] # String or Sym is ok
|
317
333
|
products = CHEESES.values + MILKS.values
|
@@ -27,12 +27,23 @@ module StarWars
|
|
27
27
|
field :planet, String, null: true
|
28
28
|
end
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
30
|
+
|
31
|
+
class BaseEdge < GraphQL::Types::Relay::BaseEdge
|
32
|
+
node_type(BaseType)
|
33
|
+
end
|
34
|
+
|
35
|
+
class BaseConnection < GraphQL::Types::Relay::BaseConnection
|
36
|
+
edge_type(BaseEdge)
|
37
|
+
end
|
38
|
+
|
39
|
+
class BasesConnectionWithTotalCountType < GraphQL::Types::Relay::BaseConnection
|
40
|
+
edge_type(BaseEdge)
|
41
|
+
nodes_field
|
42
|
+
|
43
|
+
field :total_count, Integer, null: true
|
44
|
+
|
45
|
+
def total_count
|
46
|
+
object.nodes.count
|
36
47
|
end
|
37
48
|
end
|
38
49
|
|
@@ -121,7 +132,7 @@ module StarWars
|
|
121
132
|
|
122
133
|
field :shipsWithMaxPageSize, "Ships with max page size", max_page_size: 2, function: ShipsWithMaxPageSize.new
|
123
134
|
|
124
|
-
field :bases,
|
135
|
+
field :bases, BasesConnectionWithTotalCountType, null: true, connection: true, resolve: ->(obj, args, ctx) {
|
125
136
|
all_bases = Base.where(id: obj.bases)
|
126
137
|
if args[:nameIncludes]
|
127
138
|
all_bases = all_bases.where("name LIKE ?", "%#{args[:nameIncludes]}%")
|
@@ -131,8 +142,8 @@ module StarWars
|
|
131
142
|
argument :nameIncludes, String, required: false
|
132
143
|
end
|
133
144
|
|
134
|
-
field :basesClone,
|
135
|
-
field :basesByName,
|
145
|
+
field :basesClone, BaseConnection, null: true
|
146
|
+
field :basesByName, BaseConnection, null: true do
|
136
147
|
argument :order, String, default_value: "name", required: false
|
137
148
|
end
|
138
149
|
def bases_by_name(order: nil)
|
@@ -143,13 +154,13 @@ module StarWars
|
|
143
154
|
end
|
144
155
|
end
|
145
156
|
|
146
|
-
field :basesWithMaxLimitRelation,
|
147
|
-
field :basesWithMaxLimitArray,
|
148
|
-
field :basesWithDefaultMaxLimitRelation,
|
149
|
-
field :basesWithDefaultMaxLimitArray,
|
150
|
-
field :basesWithLargeMaxLimitRelation,
|
157
|
+
field :basesWithMaxLimitRelation, BaseConnection, null: true, max_page_size: 2, resolve: Proc.new { Base.all}
|
158
|
+
field :basesWithMaxLimitArray, BaseConnection, null: true, max_page_size: 2, resolve: Proc.new { Base.all.to_a }
|
159
|
+
field :basesWithDefaultMaxLimitRelation, BaseConnection, null: true, resolve: Proc.new { Base.all }
|
160
|
+
field :basesWithDefaultMaxLimitArray, BaseConnection, null: true, resolve: Proc.new { Base.all.to_a }
|
161
|
+
field :basesWithLargeMaxLimitRelation, BaseConnection, null: true, max_page_size: 1000, resolve: Proc.new { Base.all }
|
151
162
|
|
152
|
-
field :basesAsSequelDataset,
|
163
|
+
field :basesAsSequelDataset, BasesConnectionWithTotalCountType, null: true, connection: true, max_page_size: 1000 do
|
153
164
|
argument :nameIncludes, String, required: false
|
154
165
|
end
|
155
166
|
|
@@ -297,14 +308,14 @@ module StarWars
|
|
297
308
|
|
298
309
|
field :largestBase, BaseType, null: true, resolve: ->(obj, args, ctx) { Base.find(3) }
|
299
310
|
|
300
|
-
field :newestBasesGroupedByFaction,
|
311
|
+
field :newestBasesGroupedByFaction, BaseConnection, null: true, resolve: ->(obj, args, ctx) {
|
301
312
|
Base
|
302
313
|
.having('id in (select max(id) from bases group by faction_id)')
|
303
314
|
.group(:id)
|
304
315
|
.order('faction_id desc')
|
305
316
|
}
|
306
317
|
|
307
|
-
field :basesWithNullName,
|
318
|
+
field :basesWithNullName, BaseConnection, null: false, resolve: ->(obj, args, ctx) {
|
308
319
|
[OpenStruct.new(id: nil)]
|
309
320
|
}
|
310
321
|
|
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.8.
|
4
|
+
version: 1.8.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Mosolgo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-06-
|
11
|
+
date: 2018-06-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: benchmark-ips
|
@@ -348,6 +348,7 @@ files:
|
|
348
348
|
- lib/graphql/analysis/reducer_state.rb
|
349
349
|
- lib/graphql/analysis_error.rb
|
350
350
|
- lib/graphql/argument.rb
|
351
|
+
- lib/graphql/authorization.rb
|
351
352
|
- lib/graphql/backtrace.rb
|
352
353
|
- lib/graphql/backtrace/inspect_result.rb
|
353
354
|
- lib/graphql/backtrace/table.rb
|
@@ -588,12 +589,22 @@ files:
|
|
588
589
|
- lib/graphql/tracing/scout_tracing.rb
|
589
590
|
- lib/graphql/tracing/skylight_tracing.rb
|
590
591
|
- lib/graphql/type_kinds.rb
|
592
|
+
- lib/graphql/types.rb
|
591
593
|
- lib/graphql/types/boolean.rb
|
592
594
|
- lib/graphql/types/float.rb
|
593
595
|
- lib/graphql/types/id.rb
|
594
596
|
- lib/graphql/types/int.rb
|
595
597
|
- lib/graphql/types/iso_8601_date_time.rb
|
598
|
+
- lib/graphql/types/relay.rb
|
599
|
+
- lib/graphql/types/relay/base_connection.rb
|
600
|
+
- lib/graphql/types/relay/base_edge.rb
|
601
|
+
- lib/graphql/types/relay/base_field.rb
|
602
|
+
- lib/graphql/types/relay/base_interface.rb
|
603
|
+
- lib/graphql/types/relay/base_object.rb
|
604
|
+
- lib/graphql/types/relay/node.rb
|
605
|
+
- lib/graphql/types/relay/page_info.rb
|
596
606
|
- lib/graphql/types/string.rb
|
607
|
+
- lib/graphql/unauthorized_error.rb
|
597
608
|
- lib/graphql/union_type.rb
|
598
609
|
- lib/graphql/unresolved_type_error.rb
|
599
610
|
- lib/graphql/upgrader/member.rb
|
@@ -966,6 +977,7 @@ files:
|
|
966
977
|
- spec/graphql/analysis/query_complexity_spec.rb
|
967
978
|
- spec/graphql/analysis/query_depth_spec.rb
|
968
979
|
- spec/graphql/argument_spec.rb
|
980
|
+
- spec/graphql/authorization_spec.rb
|
969
981
|
- spec/graphql/backtrace_spec.rb
|
970
982
|
- spec/graphql/base_type_spec.rb
|
971
983
|
- spec/graphql/boolean_type_spec.rb
|
@@ -1514,6 +1526,7 @@ test_files:
|
|
1514
1526
|
- spec/graphql/analysis/query_complexity_spec.rb
|
1515
1527
|
- spec/graphql/analysis/query_depth_spec.rb
|
1516
1528
|
- spec/graphql/argument_spec.rb
|
1529
|
+
- spec/graphql/authorization_spec.rb
|
1517
1530
|
- spec/graphql/backtrace_spec.rb
|
1518
1531
|
- spec/graphql/base_type_spec.rb
|
1519
1532
|
- spec/graphql/boolean_type_spec.rb
|