graphql 1.5.15 → 1.6.0
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 -19
- data/lib/graphql/analysis/analyze_query.rb +27 -2
- data/lib/graphql/analysis/query_complexity.rb +10 -11
- data/lib/graphql/argument.rb +7 -6
- data/lib/graphql/backwards_compatibility.rb +47 -0
- data/lib/graphql/compatibility/execution_specification.rb +14 -0
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +6 -1
- data/lib/graphql/compatibility/lazy_execution_specification.rb +19 -0
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +15 -6
- data/lib/graphql/directive.rb +1 -6
- data/lib/graphql/execution.rb +1 -0
- data/lib/graphql/execution/execute.rb +174 -160
- data/lib/graphql/execution/field_result.rb +5 -1
- data/lib/graphql/execution/lazy.rb +2 -2
- data/lib/graphql/execution/lazy/resolve.rb +8 -11
- data/lib/graphql/execution/multiplex.rb +134 -0
- data/lib/graphql/execution/selection_result.rb +5 -0
- data/lib/graphql/field.rb +1 -8
- data/lib/graphql/filter.rb +53 -0
- data/lib/graphql/internal_representation/node.rb +11 -6
- data/lib/graphql/internal_representation/rewrite.rb +3 -3
- data/lib/graphql/query.rb +160 -78
- data/lib/graphql/query/arguments.rb +14 -25
- data/lib/graphql/query/arguments_cache.rb +6 -13
- data/lib/graphql/query/context.rb +28 -10
- data/lib/graphql/query/executor.rb +1 -0
- data/lib/graphql/query/literal_input.rb +10 -4
- data/lib/graphql/query/null_context.rb +1 -1
- data/lib/graphql/query/serial_execution/field_resolution.rb +5 -1
- data/lib/graphql/query/validation_pipeline.rb +12 -7
- data/lib/graphql/query/variables.rb +1 -1
- data/lib/graphql/rake_task.rb +140 -0
- data/lib/graphql/relay/array_connection.rb +29 -48
- data/lib/graphql/relay/base_connection.rb +9 -7
- data/lib/graphql/relay/mutation.rb +0 -11
- data/lib/graphql/relay/mutation/instrumentation.rb +2 -2
- data/lib/graphql/relay/mutation/resolve.rb +7 -10
- data/lib/graphql/relay/relation_connection.rb +98 -61
- data/lib/graphql/scalar_type.rb +1 -15
- data/lib/graphql/schema.rb +90 -25
- data/lib/graphql/schema/build_from_definition.rb +22 -23
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +70 -0
- data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +47 -0
- data/lib/graphql/schema/middleware_chain.rb +1 -1
- data/lib/graphql/schema/printer.rb +2 -1
- data/lib/graphql/schema/timeout_middleware.rb +6 -6
- data/lib/graphql/schema/type_map.rb +1 -1
- data/lib/graphql/schema/warden.rb +5 -9
- data/lib/graphql/static_validation/definition_dependencies.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/spec/graphql/analysis/analyze_query_spec.rb +2 -2
- data/spec/graphql/analysis/max_query_complexity_spec.rb +28 -0
- data/spec/graphql/argument_spec.rb +3 -3
- data/spec/graphql/execution/lazy_spec.rb +8 -114
- data/spec/graphql/execution/multiplex_spec.rb +131 -0
- data/spec/graphql/internal_representation/rewrite_spec.rb +10 -0
- data/spec/graphql/query/arguments_spec.rb +14 -16
- data/spec/graphql/query/context_spec.rb +14 -1
- data/spec/graphql/query/literal_input_spec.rb +19 -13
- data/spec/graphql/query/variables_spec.rb +1 -1
- data/spec/graphql/query_spec.rb +12 -1
- data/spec/graphql/rake_task_spec.rb +57 -0
- data/spec/graphql/relay/array_connection_spec.rb +24 -3
- data/spec/graphql/relay/connection_instrumentation_spec.rb +23 -0
- data/spec/graphql/relay/mutation_spec.rb +2 -10
- data/spec/graphql/relay/page_info_spec.rb +2 -2
- data/spec/graphql/relay/relation_connection_spec.rb +167 -3
- data/spec/graphql/schema/build_from_definition_spec.rb +93 -19
- data/spec/graphql/schema/warden_spec.rb +80 -0
- data/spec/graphql/schema_spec.rb +26 -2
- data/spec/spec_helper.rb +4 -2
- data/spec/support/lazy_helpers.rb +152 -0
- data/spec/support/star_wars/schema.rb +23 -0
- metadata +28 -3
- data/lib/graphql/schema/mask.rb +0 -55
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
describe GraphQL::Execution::Multiplex do
|
5
|
+
def multiplex(*a)
|
6
|
+
LazyHelpers::LazySchema.multiplex(*a)
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:q1) { <<-GRAPHQL
|
10
|
+
query Q1 {
|
11
|
+
nestedSum(value: 3) {
|
12
|
+
value
|
13
|
+
nestedSum(value: 7) {
|
14
|
+
value
|
15
|
+
}
|
16
|
+
}
|
17
|
+
}
|
18
|
+
GRAPHQL
|
19
|
+
}
|
20
|
+
let(:q2) { <<-GRAPHQL
|
21
|
+
query Q2 {
|
22
|
+
nestedSum(value: 2) {
|
23
|
+
value
|
24
|
+
nestedSum(value: 11) {
|
25
|
+
value
|
26
|
+
}
|
27
|
+
}
|
28
|
+
}
|
29
|
+
GRAPHQL
|
30
|
+
}
|
31
|
+
let(:q3) { <<-GRAPHQL
|
32
|
+
query Q3 {
|
33
|
+
listSum(values: [1,2]) {
|
34
|
+
nestedSum(value: 3) {
|
35
|
+
value
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
GRAPHQL
|
40
|
+
}
|
41
|
+
|
42
|
+
let(:queries) { [{query: q1}, {query: q2}, {query: q3}] }
|
43
|
+
|
44
|
+
describe "multiple queries in the same lazy context" do
|
45
|
+
it "runs multiple queries in the same lazy context" do
|
46
|
+
expected_data = [
|
47
|
+
{"data"=>{"nestedSum"=>{"value"=>14, "nestedSum"=>{"value"=>46}}}},
|
48
|
+
{"data"=>{"nestedSum"=>{"value"=>14, "nestedSum"=>{"value"=>46}}}},
|
49
|
+
{"data"=>{"listSum"=>[{"nestedSum"=>{"value"=>14}}, {"nestedSum"=>{"value"=>14}}]}},
|
50
|
+
]
|
51
|
+
|
52
|
+
res = multiplex(queries)
|
53
|
+
assert_equal expected_data, res
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "when some have validation errors or runtime errors" do
|
58
|
+
let(:q1) { " { success: nullableNestedSum(value: 1) { value } }" }
|
59
|
+
let(:q2) { " { runtimeError: nullableNestedSum(value: 13) { value } }" }
|
60
|
+
let(:q3) { "{
|
61
|
+
invalidNestedNull: nullableNestedSum(value: 1) {
|
62
|
+
value
|
63
|
+
nullableNestedSum(value: 2) {
|
64
|
+
nestedSum(value: 13) {
|
65
|
+
value
|
66
|
+
}
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}" }
|
70
|
+
let(:q4) { " { validationError: nullableNestedSum(value: true) }"}
|
71
|
+
|
72
|
+
it "returns a mix of errors and values" do
|
73
|
+
expected_res = [
|
74
|
+
{
|
75
|
+
"data"=>{"success"=>{"value"=>2}}
|
76
|
+
},
|
77
|
+
{
|
78
|
+
"data"=>{"runtimeError"=>nil},
|
79
|
+
"errors"=>[{
|
80
|
+
"message"=>"13 is unlucky",
|
81
|
+
"locations"=>[{"line"=>1, "column"=>4}],
|
82
|
+
"path"=>["runtimeError"]
|
83
|
+
}]
|
84
|
+
},
|
85
|
+
{
|
86
|
+
"data"=>{"invalidNestedNull"=>{"value" => 2,"nullableNestedSum" => nil}},
|
87
|
+
"errors"=>[{"message"=>"Cannot return null for non-nullable field LazySum.nestedSum"}],
|
88
|
+
},
|
89
|
+
{
|
90
|
+
"errors" => [{
|
91
|
+
"message"=>"Objects must have selections (field 'nullableNestedSum' returns LazySum but has no selections)",
|
92
|
+
"locations"=>[{"line"=>1, "column"=>4}],
|
93
|
+
"fields"=>["query", "validationError"]
|
94
|
+
}]
|
95
|
+
},
|
96
|
+
]
|
97
|
+
|
98
|
+
res = multiplex([
|
99
|
+
{query: q1},
|
100
|
+
{query: q2},
|
101
|
+
{query: q3},
|
102
|
+
{query: q4},
|
103
|
+
])
|
104
|
+
assert_equal expected_res, res
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "context shared by a multiplex run" do
|
109
|
+
it "is provided as context:" do
|
110
|
+
checks = []
|
111
|
+
multiplex(queries, context: { instrumentation_checks: checks })
|
112
|
+
assert_equal ["before multiplex 1", "before multiplex 2", "after multiplex 2", "after multiplex 1"], checks
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "instrumenting a multiplex run" do
|
117
|
+
it "runs query instrumentation for each query and multiplex-level instrumentation" do
|
118
|
+
checks = []
|
119
|
+
queries_with_context = queries.map { |q| q.merge(context: { instrumentation_checks: checks }) }
|
120
|
+
multiplex(queries_with_context, context: { instrumentation_checks: checks })
|
121
|
+
assert_equal [
|
122
|
+
"before multiplex 1",
|
123
|
+
"before multiplex 2",
|
124
|
+
"before Q1", "before Q2", "before Q3",
|
125
|
+
"after Q1", "after Q2", "after Q3",
|
126
|
+
"after multiplex 2",
|
127
|
+
"after multiplex 1",
|
128
|
+
], checks
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -148,6 +148,16 @@ describe GraphQL::InternalRepresentation::Rewrite do
|
|
148
148
|
assert_equal habitats_selection, seasons_selection.parent
|
149
149
|
assert_equal habitats_selection, average_weight_selection.parent
|
150
150
|
end
|
151
|
+
|
152
|
+
it "tracks field return type" do
|
153
|
+
doc = rewrite_result.operation_definitions["getPlant"]
|
154
|
+
|
155
|
+
assert plant_selection = doc.typed_children[schema.types["Query"]]["plant"]
|
156
|
+
assert_equal "Plant", plant_selection.return_type.to_s
|
157
|
+
|
158
|
+
assert tree_selection = plant_selection.typed_children[schema.types["Fruit"]]
|
159
|
+
assert_equal "[Int!]!", tree_selection["color"].return_type.to_s
|
160
|
+
end
|
151
161
|
end
|
152
162
|
|
153
163
|
describe "tracking directives on fragment spreads" do
|
@@ -26,8 +26,8 @@ describe GraphQL::Query::Arguments do
|
|
26
26
|
}, argument_definitions: test_input_2.arguments)
|
27
27
|
}
|
28
28
|
|
29
|
-
it "returns keys as strings" do
|
30
|
-
assert_equal(["a", "b", "
|
29
|
+
it "returns keys as strings, with aliases" do
|
30
|
+
assert_equal(["a", "b", "inputObject"], arguments.keys)
|
31
31
|
end
|
32
32
|
|
33
33
|
it "delegates values to values hash" do
|
@@ -39,11 +39,11 @@ describe GraphQL::Query::Arguments do
|
|
39
39
|
arguments.each do |key, value|
|
40
40
|
pairs << [key, value]
|
41
41
|
end
|
42
|
-
assert_equal([["a", 1], ["b", 2], ["
|
42
|
+
assert_equal([["a", 1], ["b", 2], ["inputObject", {"d" => 3, "e" => 4}]], pairs)
|
43
43
|
end
|
44
44
|
|
45
|
-
it "returns
|
46
|
-
assert_equal({ a
|
45
|
+
it "returns a stringified, aliased hash with to_h" do
|
46
|
+
assert_equal({ "a"=> 1, "b" => 2, "inputObject" => { "d" => 3, "e" => 4 } }, arguments.to_h)
|
47
47
|
end
|
48
48
|
|
49
49
|
it "yields key, value, and arg_defnition" do
|
@@ -52,10 +52,11 @@ describe GraphQL::Query::Arguments do
|
|
52
52
|
value = arg_value.value.is_a?(GraphQL::Query::Arguments) ? arg_value.value.to_h : arg_value.value
|
53
53
|
type_info << [arg_value.key, value, arg_value.definition.type.unwrap.name]
|
54
54
|
end
|
55
|
+
|
55
56
|
expected_type_info =[
|
56
57
|
["a", 1, "Int"],
|
57
58
|
["b", 2, "Int"],
|
58
|
-
["inputObject", { d
|
59
|
+
["inputObject", { "d" => 3, "e" => 4 }, "TestInput1"],
|
59
60
|
]
|
60
61
|
assert_equal expected_type_info, type_info
|
61
62
|
end
|
@@ -65,14 +66,18 @@ describe GraphQL::Query::Arguments do
|
|
65
66
|
types = {}
|
66
67
|
arguments.each_value do |arg_value|
|
67
68
|
transformed_args[arg_value.key.upcase] = arg_value.value
|
68
|
-
|
69
|
+
defn = arg_value.definition
|
70
|
+
types[arg_value.key.upcase] = defn.redefine(
|
71
|
+
name: defn.name.upcase,
|
72
|
+
as: defn.as ? defn.as.to_s.upcase : nil,
|
73
|
+
)
|
69
74
|
end
|
70
75
|
|
71
76
|
new_arguments = GraphQL::Query::Arguments.new(transformed_args, argument_definitions: types)
|
72
77
|
expected_hash = {
|
73
78
|
"A" => 1,
|
74
79
|
"B" => 2,
|
75
|
-
"INPUTOBJECT" => { d
|
80
|
+
"INPUTOBJECT" => { "d" => 3 , "e" => 4 },
|
76
81
|
}
|
77
82
|
assert_equal expected_hash, new_arguments.to_h
|
78
83
|
end
|
@@ -176,6 +181,7 @@ describe GraphQL::Query::Arguments do
|
|
176
181
|
last_args = arg_values.last
|
177
182
|
|
178
183
|
assert_equal true, last_args.key?(:specialKeyName)
|
184
|
+
assert_equal true, last_args.key?("specialKeyName")
|
179
185
|
end
|
180
186
|
|
181
187
|
it "works from query literals" do
|
@@ -190,14 +196,6 @@ describe GraphQL::Query::Arguments do
|
|
190
196
|
assert_equal({"a" => 1, "b" => 2}, last_args.to_h)
|
191
197
|
end
|
192
198
|
|
193
|
-
it "uses Field#default_arguments when no args are provided" do
|
194
|
-
schema.execute("{ argTest noArgTest noDefaultsTest }")
|
195
|
-
|
196
|
-
assert schema.query.get_field("argTest").default_arguments.eql?(arg_values[0])
|
197
|
-
assert GraphQL::Query::Arguments::NO_ARGS.eql?(arg_values[1])
|
198
|
-
assert GraphQL::Query::Arguments::NO_ARGS.eql?(arg_values[2])
|
199
|
-
end
|
200
|
-
|
201
199
|
it "works from variables" do
|
202
200
|
variables = { "arg" => { "a" => 1, "d" => nil } }
|
203
201
|
schema.execute("query ArgTest($arg: TestInput){ argTest(d: $arg) }", variables: variables)
|
@@ -75,8 +75,10 @@ describe GraphQL::Query::Context do
|
|
75
75
|
describe "empty values" do
|
76
76
|
let(:context) { GraphQL::Query::Context.new(query: OpenStruct.new(schema: schema), values: nil) }
|
77
77
|
|
78
|
-
it "returns nil
|
78
|
+
it "returns returns nil and reports key? => false" do
|
79
79
|
assert_equal(nil, context[:some_key])
|
80
|
+
assert_equal(false, context.key?(:some_key))
|
81
|
+
assert_raises(KeyError) { context.fetch(:some_key) }
|
80
82
|
end
|
81
83
|
end
|
82
84
|
|
@@ -88,6 +90,17 @@ describe GraphQL::Query::Context do
|
|
88
90
|
context[:some_key] = "wow!"
|
89
91
|
assert_equal("wow!", context[:some_key])
|
90
92
|
end
|
93
|
+
|
94
|
+
describe "namespaces" do
|
95
|
+
let(:context) { GraphQL::Query::Context.new(query: OpenStruct.new(schema: schema), values: {a: 1}) }
|
96
|
+
|
97
|
+
it "doesn't conflict with base values" do
|
98
|
+
ns = context.namespace(:stuff)
|
99
|
+
ns[:b] = 2
|
100
|
+
assert_equal({a: 1}, context.to_h)
|
101
|
+
assert_equal({b: 2}, context.namespace(:stuff))
|
102
|
+
end
|
103
|
+
end
|
91
104
|
end
|
92
105
|
|
93
106
|
describe "accessing context after the fact" do
|
@@ -8,13 +8,14 @@ describe GraphQL::Query::LiteralInput do
|
|
8
8
|
query = GraphQL::ObjectType.define do
|
9
9
|
name "Query"
|
10
10
|
|
11
|
-
field :
|
11
|
+
field :addToArgumentValue do
|
12
12
|
type !types.Int
|
13
13
|
argument :value do
|
14
|
-
type
|
15
|
-
|
14
|
+
type types.Int
|
15
|
+
default_value 3
|
16
|
+
prepare ->(arg, ctx) do
|
16
17
|
return GraphQL::ExecutionError.new("Can't return more than 3 digits") if arg > 998
|
17
|
-
arg +
|
18
|
+
arg + ctx[:val]
|
18
19
|
end
|
19
20
|
end
|
20
21
|
resolve ->(t, a, c) { a[:value] }
|
@@ -25,26 +26,31 @@ describe GraphQL::Query::LiteralInput do
|
|
25
26
|
}
|
26
27
|
|
27
28
|
it "prepares values from query literals" do
|
28
|
-
result = schema.execute("{
|
29
|
-
assert_equal(result["data"]["
|
29
|
+
result = schema.execute("{ addToArgumentValue(value: 1) }", context: { val: 1 })
|
30
|
+
assert_equal(result["data"]["addToArgumentValue"], 2)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "prepares default values" do
|
34
|
+
result = schema.execute("{ addToArgumentValue }", context: { val: 4 })
|
35
|
+
assert_equal(7, result["data"]["addToArgumentValue"])
|
30
36
|
end
|
31
37
|
|
32
38
|
it "prepares values from variables" do
|
33
|
-
result = schema.execute("query ($value: Int!) {
|
34
|
-
assert_equal(result["data"]["
|
39
|
+
result = schema.execute("query ($value: Int!) { addToArgumentValue(value: $value) }", variables: { "value" => 1}, context: { val: 2 } )
|
40
|
+
assert_equal(result["data"]["addToArgumentValue"], 3)
|
35
41
|
end
|
36
42
|
|
37
43
|
it "prepares values correctly if called multiple times with different arguments" do
|
38
|
-
result = schema.execute("{ first:
|
39
|
-
assert_equal(result["data"]["first"],
|
40
|
-
assert_equal(result["data"]["second"],
|
44
|
+
result = schema.execute("{ first: addToArgumentValue(value: 1) second: addToArgumentValue(value: 2) }", context: { val: 3 })
|
45
|
+
assert_equal(result["data"]["first"], 4)
|
46
|
+
assert_equal(result["data"]["second"], 5)
|
41
47
|
end
|
42
48
|
|
43
49
|
it "adds message to errors key if an ExecutionError is returned from the prepare function" do
|
44
|
-
result = schema.execute("{
|
50
|
+
result = schema.execute("{ addToArgumentValue(value: 999) }")
|
45
51
|
assert_equal(result["errors"][0]["message"], "Can't return more than 3 digits")
|
46
52
|
assert_equal(result["errors"][0]["locations"][0]["line"], 1)
|
47
|
-
assert_equal(result["errors"][0]["locations"][0]["column"],
|
53
|
+
assert_equal(result["errors"][0]["locations"][0]["column"], 22)
|
48
54
|
end
|
49
55
|
end
|
50
56
|
end
|
@@ -19,7 +19,7 @@ describe GraphQL::Query::Variables do
|
|
19
19
|
let(:variables) { GraphQL::Query::Variables.new(
|
20
20
|
OpenStruct.new({
|
21
21
|
schema: schema,
|
22
|
-
warden: GraphQL::Schema::Warden.new(schema.
|
22
|
+
warden: GraphQL::Schema::Warden.new(schema.default_filter, schema: schema, context: nil),
|
23
23
|
}),
|
24
24
|
ast_variables,
|
25
25
|
provided_variables)
|
data/spec/graphql/query_spec.rb
CHANGED
@@ -52,9 +52,20 @@ describe GraphQL::Query do
|
|
52
52
|
variables: query_variables,
|
53
53
|
operation_name: operation_name,
|
54
54
|
max_depth: max_depth,
|
55
|
-
)
|
55
|
+
).result
|
56
56
|
}
|
57
57
|
end
|
58
|
+
|
59
|
+
it 'can be assigned later' do
|
60
|
+
query = GraphQL::Query.new(
|
61
|
+
schema,
|
62
|
+
variables: query_variables,
|
63
|
+
operation_name: operation_name,
|
64
|
+
max_depth: max_depth,
|
65
|
+
)
|
66
|
+
query.query_string = '{ __type(name: "Cheese") { name } }'
|
67
|
+
assert_equal "Cheese", query.result["data"] ["__type"]["name"]
|
68
|
+
end
|
58
69
|
end
|
59
70
|
|
60
71
|
describe "operation_name" do
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
rake_task_schema_defn = <<-GRAPHQL
|
5
|
+
type Query {
|
6
|
+
allowed(allowed: ID!, excluded: ID!): Int
|
7
|
+
excluded(excluded: ID!): Boolean
|
8
|
+
ignored: Float
|
9
|
+
}
|
10
|
+
GRAPHQL
|
11
|
+
|
12
|
+
RakeTaskSchema = GraphQL::Schema.from_definition(rake_task_schema_defn)
|
13
|
+
|
14
|
+
# Default task
|
15
|
+
GraphQL::RakeTask.new(schema_name: "RakeTaskSchema")
|
16
|
+
# Configured task
|
17
|
+
GraphQL::RakeTask.new(idl_outfile: "tmp/configured_schema.graphql") do |t|
|
18
|
+
t.namespace = "graphql_custom"
|
19
|
+
t.load_context = ->(task) { {filtered: true} }
|
20
|
+
t.only = ->(member, ctx) { member.is_a?(GraphQL::ScalarType) || (ctx[:filtered] && ["Query", "allowed"].include?(member.name)) }
|
21
|
+
t.load_schema = ->(task) { RakeTaskSchema }
|
22
|
+
end
|
23
|
+
|
24
|
+
describe GraphQL::RakeTask do
|
25
|
+
describe "default settings" do
|
26
|
+
after do
|
27
|
+
FileUtils.rm_rf("./schema.json")
|
28
|
+
FileUtils.rm_rf("./schema.graphql")
|
29
|
+
end
|
30
|
+
|
31
|
+
it "writes JSON" do
|
32
|
+
capture_io do
|
33
|
+
Rake::Task["graphql:schema:dump"].invoke
|
34
|
+
end
|
35
|
+
dumped_json = File.read("./schema.json")
|
36
|
+
expected_json = JSON.pretty_generate(RakeTaskSchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY))
|
37
|
+
assert_equal(expected_json, dumped_json)
|
38
|
+
|
39
|
+
dumped_idl = File.read("./schema.graphql")
|
40
|
+
expected_idl = rake_task_schema_defn.chomp
|
41
|
+
assert_equal(expected_idl, dumped_idl)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "customized settings" do
|
46
|
+
it "writes GraphQL" do
|
47
|
+
capture_io do
|
48
|
+
Rake::Task["graphql_custom:schema:idl"].invoke
|
49
|
+
end
|
50
|
+
dumped_idl = File.read("./tmp/configured_schema.graphql")
|
51
|
+
expected_idl = "type Query {
|
52
|
+
allowed(allowed: ID!): Int
|
53
|
+
}"
|
54
|
+
assert_equal expected_idl, dumped_idl
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -89,6 +89,27 @@ describe GraphQL::Relay::ArrayConnection do
|
|
89
89
|
assert_equal(false, result["data"]["rebels"]["ships"]["pageInfo"]["hasPreviousPage"])
|
90
90
|
end
|
91
91
|
|
92
|
+
it 'works with before and after specified together' do
|
93
|
+
result = star_wars_query(query_string, "first" => 1)
|
94
|
+
assert_equal(["X-Wing"], get_names(result))
|
95
|
+
|
96
|
+
first_cursor = get_last_cursor(result)
|
97
|
+
|
98
|
+
# There is no records between before and after if they point to the same cursor
|
99
|
+
result = star_wars_query(query_string, "before" => first_cursor, "after" => first_cursor, "last" => 2)
|
100
|
+
assert_equal([], get_names(result))
|
101
|
+
|
102
|
+
result = star_wars_query(query_string, "after" => first_cursor, "first" => 2)
|
103
|
+
assert_equal(["Y-Wing", "A-Wing"], get_names(result))
|
104
|
+
|
105
|
+
# After the last result, find the next 2:
|
106
|
+
second_cursor = get_last_cursor(result)
|
107
|
+
|
108
|
+
# There is only 2 results between the cursors
|
109
|
+
result = star_wars_query(query_string, "after" => first_cursor, "before" => second_cursor, "first" => 5)
|
110
|
+
assert_equal(["Y-Wing", "A-Wing"], get_names(result))
|
111
|
+
end
|
112
|
+
|
92
113
|
it 'handles cursors beyond the bounds of the array' do
|
93
114
|
overreaching_cursor = Base64.strict_encode64("100")
|
94
115
|
result = star_wars_query(query_string, "after" => overreaching_cursor, "first" => 2)
|
@@ -157,13 +178,13 @@ describe GraphQL::Relay::ArrayConnection do
|
|
157
178
|
|
158
179
|
it "applies to queries by `last`" do
|
159
180
|
last_cursor = "Ng=="
|
160
|
-
|
181
|
+
|
161
182
|
result = star_wars_query(query_string, "last" => 100, "before" => last_cursor)
|
162
|
-
assert_equal(
|
183
|
+
assert_equal(["Death Star", "Shield Generator"], get_names(result))
|
163
184
|
assert_equal(true, get_page_info(result)["hasPreviousPage"])
|
164
185
|
|
165
186
|
result = star_wars_query(query_string, "before" => last_cursor)
|
166
|
-
assert_equal(
|
187
|
+
assert_equal(["Yavin", "Echo Base"], get_names(result))
|
167
188
|
assert_equal(false, get_page_info(result)["hasPreviousPage"], "hasPreviousPage is false when last is not specified")
|
168
189
|
|
169
190
|
third_cursor = "Mw=="
|