graphql 1.5.15 → 1.6.0
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.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=="
|