graphql 0.0.1 → 0.0.2
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 +78 -9
- data/lib/graphql/call.rb +7 -0
- data/lib/graphql/connection.rb +44 -0
- data/lib/graphql/field.rb +117 -0
- data/lib/graphql/field_definer.rb +29 -0
- data/lib/graphql/introspection/call_node.rb +13 -0
- data/lib/graphql/introspection/connection.rb +9 -0
- data/lib/graphql/introspection/field_node.rb +19 -0
- data/lib/graphql/introspection/root_call_argument_node.rb +5 -0
- data/lib/graphql/introspection/root_call_node.rb +16 -0
- data/lib/graphql/introspection/schema_call.rb +8 -0
- data/lib/graphql/introspection/schema_node.rb +17 -0
- data/lib/graphql/introspection/type_call.rb +8 -0
- data/lib/graphql/introspection/type_node.rb +16 -0
- data/lib/graphql/node.rb +141 -34
- data/lib/graphql/parser.rb +19 -8
- data/lib/graphql/query.rb +64 -21
- data/lib/graphql/root_call.rb +176 -0
- data/lib/graphql/root_call_argument.rb +8 -0
- data/lib/graphql/root_call_argument_definer.rb +20 -0
- data/lib/graphql/schema.rb +99 -0
- data/lib/graphql/syntax/call.rb +3 -12
- data/lib/graphql/syntax/field.rb +4 -2
- data/lib/graphql/syntax/node.rb +3 -10
- data/lib/graphql/syntax/query.rb +7 -0
- data/lib/graphql/syntax/variable.rb +7 -0
- data/lib/graphql/transform.rb +14 -5
- data/lib/graphql/types/boolean_field.rb +3 -0
- data/lib/graphql/types/connection_field.rb +30 -0
- data/lib/graphql/types/cursor_field.rb +9 -0
- data/lib/graphql/types/number_field.rb +3 -0
- data/lib/graphql/types/object_field.rb +8 -0
- data/lib/graphql/types/string_field.rb +3 -0
- data/lib/graphql/types/type_field.rb +6 -0
- data/lib/graphql/version.rb +3 -0
- data/readme.md +142 -10
- data/spec/graphql/field_spec.rb +66 -0
- data/spec/graphql/node_spec.rb +68 -0
- data/spec/graphql/parser_spec.rb +75 -25
- data/spec/graphql/query_spec.rb +185 -83
- data/spec/graphql/root_call_spec.rb +55 -0
- data/spec/graphql/schema_spec.rb +128 -0
- data/spec/graphql/transform_spec.rb +124 -39
- data/spec/spec_helper.rb +2 -1
- data/spec/support/dummy_app.rb +43 -23
- data/spec/support/nodes.rb +145 -32
- metadata +78 -16
- data/lib/graphql/collection_edge.rb +0 -62
- data/lib/graphql/syntax/edge.rb +0 -12
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
describe GraphQL::Field do
|
5
|
+
let(:owner) { OpenStruct.new(name: "TestOwner")}
|
6
|
+
let(:field) { GraphQL::Field.create_class(name: "high_fives", type: :number, owner_class: owner).new(query: {}) }
|
7
|
+
|
8
|
+
describe '#name' do
|
9
|
+
it 'is present' do
|
10
|
+
assert_equal field.name, "high_fives"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#method' do
|
15
|
+
it 'defaults to name' do
|
16
|
+
assert_equal "high_fives", field.method
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '.call' do
|
21
|
+
let(:content_field) { Nodes::PostNode.all_fields["content"] }
|
22
|
+
it 'doesnt register a call twice' do
|
23
|
+
assert_equal 3, content_field.calls.size
|
24
|
+
call = content_field.calls.first[1]
|
25
|
+
content_field.call(call.name, call.lambda)
|
26
|
+
content_field.call(call.name, call.lambda)
|
27
|
+
assert_equal 3, content_field.calls.size
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '.to_s' do
|
32
|
+
it 'includes name' do
|
33
|
+
assert_match(/high_fives/, field.class.to_s)
|
34
|
+
end
|
35
|
+
it 'includes owner name' do
|
36
|
+
assert_match(/TestOwner/, field.class.to_s)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '__type__' do
|
41
|
+
let(:query_string) { "type(post) { fields { edges { node { name, type, calls { edges { node { name } }} } } } } "}
|
42
|
+
let(:query) { GraphQL::Query.new(query_string, context: {}) }
|
43
|
+
let(:result) { query.as_result }
|
44
|
+
let(:id_field) { result["post"]["fields"]["edges"][1]["node"] }
|
45
|
+
let(:title_field) { result["post"]["fields"]["edges"][2]["node"] }
|
46
|
+
let(:comments_field) { result["post"]["fields"]["edges"][5]["node"] }
|
47
|
+
let(:content_field) { result["post"]["fields"]["edges"][3]["node"] }
|
48
|
+
|
49
|
+
it 'has name' do
|
50
|
+
assert_equal "id", id_field["name"]
|
51
|
+
assert_equal "title", title_field["name"]
|
52
|
+
assert_equal "comments", comments_field["name"]
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'has type' do
|
56
|
+
assert_equal "number", id_field["type"]
|
57
|
+
assert_equal "string", title_field["type"]
|
58
|
+
assert_equal "connection", comments_field["type"]
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'has calls' do
|
62
|
+
assert_equal 3, content_field["calls"]["edges"].length
|
63
|
+
assert_equal ["from", "for", "select"], content_field["calls"]["edges"].map {|c| c["node"]["name"] }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GraphQL::Node do
|
4
|
+
let(:query_string) { "type(post) { name, description, fields { count, edges { node { name, description }}} }"}
|
5
|
+
let(:result) { GraphQL::Query.new(query_string).as_result}
|
6
|
+
|
7
|
+
describe '__type__' do
|
8
|
+
let(:title_field) { result["post"]["fields"]["edges"].find {|e| e["node"]["name"] == "title"}["node"] }
|
9
|
+
it 'has name' do
|
10
|
+
assert_equal "post", result["post"]["name"]
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'has description' do
|
14
|
+
assert_equal "A blog post entry", result["post"]["description"]
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'has fields' do
|
18
|
+
assert_equal 8, result["post"]["fields"]["count"]
|
19
|
+
assert_equal({ "name" => "title", "description" => nil}, title_field)
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'getting the __type__ field' do
|
23
|
+
before do
|
24
|
+
@post = Post.create(id: 155, content: "Hello world")
|
25
|
+
end
|
26
|
+
|
27
|
+
after do
|
28
|
+
@post.destroy
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:query_string) { "post(155) { __type__ { name, fields { count } } }"}
|
32
|
+
|
33
|
+
it 'exposes the type' do
|
34
|
+
assert_equal "post", result["155"]["__type__"]["name"]
|
35
|
+
assert_equal 8, result["155"]["__type__"]["fields"]["count"]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '.node_name' do
|
41
|
+
let(:query_string) { "type(upvote) { name }"}
|
42
|
+
|
43
|
+
it 'overrides __type__.name' do
|
44
|
+
assert_equal "upvote", result["upvote"]["name"]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '.field' do
|
49
|
+
it 'doesnt add the field twice if you call it twice' do
|
50
|
+
assert_equal 5, Nodes::CommentNode.all_fields.size
|
51
|
+
Nodes::CommentNode.field.number(:id)
|
52
|
+
Nodes::CommentNode.field.number(:id)
|
53
|
+
assert_equal 5, Nodes::CommentNode.all_fields.size
|
54
|
+
Nodes::CommentNode.remove_field(:id)
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'type:' do
|
58
|
+
it 'uses symbols to find built-ins' do
|
59
|
+
id_field = Nodes::CommentNode.all_fields["id"]
|
60
|
+
assert id_field.superclass == GraphQL::Types::NumberField
|
61
|
+
end
|
62
|
+
it 'uses the provided class as a superclass' do
|
63
|
+
letters_field = Nodes::CommentNode.all_fields["letters"]
|
64
|
+
assert letters_field.superclass == Nodes::LetterSelectionField
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/spec/graphql/parser_spec.rb
CHANGED
@@ -1,33 +1,59 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe GraphQL::Parser do
|
4
|
-
let(:node_name) { "" }
|
5
|
-
let(:fields) { "id, name"}
|
6
|
-
let(:query) { "#{node_name} { #{fields} }"}
|
7
4
|
let(:parser) { GraphQL::PARSER }
|
8
5
|
|
6
|
+
describe 'query' do
|
7
|
+
let(:query) { parser.query }
|
8
|
+
it 'parses node-only' do
|
9
|
+
assert query.parse_with_debug("node(4) { id, name } ")
|
10
|
+
end
|
11
|
+
it 'parses node and variables' do
|
12
|
+
assert query.parse_with_debug(%{
|
13
|
+
like_page(<page>) {
|
14
|
+
page { id }
|
15
|
+
}
|
16
|
+
<page>: {
|
17
|
+
"page": {"id": 1},
|
18
|
+
"person" : { "id", 4}
|
19
|
+
}
|
20
|
+
<other>: {
|
21
|
+
"page": {"id": 1},
|
22
|
+
"person" : { "id", 4}
|
23
|
+
}
|
24
|
+
})
|
25
|
+
end
|
26
|
+
end
|
9
27
|
describe 'field' do
|
10
28
|
let(:field) { parser.field }
|
11
29
|
it 'finds words' do
|
12
|
-
assert field.parse_with_debug("name")
|
13
30
|
assert field.parse_with_debug("date_of_birth")
|
14
31
|
end
|
15
|
-
end
|
16
32
|
|
17
|
-
|
18
|
-
|
33
|
+
it 'finds aliases' do
|
34
|
+
assert field.parse_with_debug("name as moniker")
|
35
|
+
end
|
19
36
|
|
20
37
|
it 'finds calls on fields' do
|
21
|
-
assert
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
")
|
38
|
+
assert field.parse_with_debug("url.site(www).upcase()")
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'fields that return objects' do
|
42
|
+
it 'finds them' do
|
43
|
+
assert field.parse_with_debug("birthdate { month, year }")
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'finds them with aliases' do
|
47
|
+
assert field.parse_with_debug("birthdate as d_o_b { month, year }")
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'finds them with calls' do
|
51
|
+
assert field.parse_with_debug("friends.after(123) { count { edges { node { id } } } }")
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'finds them with calls and aliases' do
|
55
|
+
assert field.parse_with_debug("friends.after(123) as pals { count { edges { node { id } } } }")
|
56
|
+
end
|
31
57
|
end
|
32
58
|
end
|
33
59
|
|
@@ -37,15 +63,13 @@ describe GraphQL::Parser do
|
|
37
63
|
assert call.parse_with_debug("node(123)")
|
38
64
|
assert call.parse_with_debug("viewer()")
|
39
65
|
end
|
40
|
-
end
|
41
66
|
|
42
|
-
|
43
|
-
|
44
|
-
it 'finds deep calls' do
|
45
|
-
assert call_chain.parse_with_debug("friends.after(123).first(2)")
|
67
|
+
it 'finds calls with multiple arguments' do
|
68
|
+
assert call.parse_with_debug("node(4, 6)")
|
46
69
|
end
|
47
|
-
|
48
|
-
|
70
|
+
|
71
|
+
it 'finds calls with variables' do
|
72
|
+
assert call.parse_with_debug("like_page(<page>)")
|
49
73
|
end
|
50
74
|
end
|
51
75
|
|
@@ -71,7 +95,8 @@ describe GraphQL::Parser do
|
|
71
95
|
end
|
72
96
|
|
73
97
|
it 'parses nested nodes' do
|
74
|
-
assert node.parse_with_debug("
|
98
|
+
assert node.parse_with_debug("
|
99
|
+
node(someone)
|
75
100
|
{
|
76
101
|
id,
|
77
102
|
name,
|
@@ -86,4 +111,29 @@ describe GraphQL::Parser do
|
|
86
111
|
")
|
87
112
|
end
|
88
113
|
end
|
114
|
+
|
115
|
+
describe 'variable' do
|
116
|
+
let(:variable) { parser.variable }
|
117
|
+
|
118
|
+
it 'gets scalar variables' do
|
119
|
+
assert variable.parse_with_debug(%{<some_number>: 888})
|
120
|
+
assert variable.parse_with_debug(%{<some_string>: my_string})
|
121
|
+
end
|
122
|
+
it 'gets json variables' do
|
123
|
+
assert variable.parse_with_debug(%{<my_input>: {"key": "value"}})
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'gets variables with nesting' do
|
127
|
+
assert variable.parse_with_debug(%{
|
128
|
+
<my_input>: {
|
129
|
+
"key": "value",
|
130
|
+
"1": 2,
|
131
|
+
"true": false,
|
132
|
+
"nested": {
|
133
|
+
"key" : "value"
|
134
|
+
}
|
135
|
+
}
|
136
|
+
})
|
137
|
+
end
|
138
|
+
end
|
89
139
|
end
|
data/spec/graphql/query_spec.rb
CHANGED
@@ -2,153 +2,255 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe GraphQL::Query do
|
4
4
|
let(:query_string) { "post(123) { title, content } "}
|
5
|
-
let(:
|
6
|
-
let(:query) { GraphQL::Query.new(query_string,
|
5
|
+
let(:context) { Context.new(person_name: "Han Solo") }
|
6
|
+
let(:query) { GraphQL::Query.new(query_string, context: context) }
|
7
|
+
let(:result) { query.as_result }
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
before do
|
10
|
+
@post = Post.create(id: 123, content: "So many great things", title: "My great post", published_at: Date.new(2010,1,4))
|
11
|
+
@comment1 = Comment.create(id: 444, post_id: 123, content: "I agree", rating: 5)
|
12
|
+
@comment2 = Comment.create(id: 445, post_id: 123, content: "I disagree", rating: 1)
|
13
|
+
@like1 = Like.create(id: 991, post_id: 123)
|
14
|
+
@like2 = Like.create(id: 992, post_id: 123)
|
15
|
+
end
|
16
|
+
|
17
|
+
after do
|
18
|
+
@post.destroy
|
19
|
+
@comment1.destroy
|
20
|
+
@comment2.destroy
|
21
|
+
@like1.destroy
|
22
|
+
@like2.destroy
|
12
23
|
end
|
13
24
|
|
14
|
-
describe '#
|
15
|
-
|
16
|
-
|
17
|
-
@comment1 = Comment.create(id: 444, post_id: 123, content: "I agree")
|
18
|
-
@comment2 = Comment.create(id: 445, post_id: 123, content: "I disagree")
|
25
|
+
describe '#as_result' do
|
26
|
+
it 'finds fields that delegate to a target' do
|
27
|
+
assert_equal result, {"123" => {"title" => "My great post", "content" => "So many great things"}}
|
19
28
|
end
|
20
29
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
30
|
+
describe 'with multiple roots' do
|
31
|
+
let(:query_string) { "comment(444, 445) { content } "}
|
32
|
+
it 'adds each as a key-value of the response' do
|
33
|
+
assert_equal ["444", "445"], result.keys
|
34
|
+
end
|
25
35
|
end
|
26
36
|
|
27
|
-
|
28
|
-
|
29
|
-
|
37
|
+
describe 'when accessing fields that return objects' do
|
38
|
+
describe 'when making calls on the field' do
|
39
|
+
let(:query_string) { "post(123) { published_at.minus_days(200) { year } }"}
|
40
|
+
it 'returns the modified value' do
|
41
|
+
assert_equal 2009, result["123"]["published_at"]["year"]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
describe 'when requesting more fields' do
|
45
|
+
let(:query_string) { "post(123) { published_at { month, year } }"}
|
46
|
+
it 'returns those fields' do
|
47
|
+
assert_equal({"month" => 1, "year" => 2010}, result["123"]["published_at"])
|
48
|
+
end
|
49
|
+
end
|
30
50
|
end
|
51
|
+
describe 'when aliasing things' do
|
52
|
+
let(:query_string) { "post(123) { title as headline, content as what_it_says }"}
|
31
53
|
|
32
|
-
|
33
|
-
|
34
|
-
"123"
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
}
|
54
|
+
it 'applies aliases to fields' do
|
55
|
+
assert_equal @post.title, result["123"]["headline"]
|
56
|
+
assert_equal @post.content, result["123"]["what_it_says"]
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'applies aliases to edges' # dunno the syntax yet
|
39
60
|
end
|
40
61
|
|
41
62
|
describe 'when requesting fields defined on the node' do
|
42
|
-
let(:query_string) { "post(123) {
|
63
|
+
let(:query_string) { "post(123) { length } "}
|
43
64
|
it 'finds fields defined on the node' do
|
44
|
-
assert_equal
|
65
|
+
assert_equal 20, result["123"]["length"]
|
45
66
|
end
|
46
67
|
end
|
47
68
|
|
69
|
+
describe 'when accessing custom fields' do
|
70
|
+
let(:query_string) { "comment(444) { letters }"}
|
71
|
+
it 'uses the custom field' do
|
72
|
+
assert_equal "I agree", result["444"]["letters"]
|
73
|
+
end
|
74
|
+
|
75
|
+
describe 'when making calls on fields' do
|
76
|
+
let(:query_string) { "comment(444) {
|
77
|
+
letters.select(4, 3),
|
78
|
+
letters.from(3).for(2) as snippet
|
79
|
+
}"}
|
80
|
+
|
81
|
+
it 'works with aliases' do
|
82
|
+
assert result["444"]["snippet"].present?
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'applies calls' do
|
86
|
+
assert_equal "gr", result["444"]["snippet"]
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'applies calls with multiple arguments' do
|
90
|
+
assert_equal "ree", result["444"]["letters"]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe 'when requesting fields overriden on a child class' do
|
95
|
+
let(:query_string) { 'thumb_up(991) { id }'}
|
96
|
+
it 'uses the child implementation' do
|
97
|
+
assert_equal '991991', result["991991"]["id"]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
48
101
|
|
49
102
|
describe 'when requesting an undefined field' do
|
50
103
|
let(:query_string) { "post(123) { destroy } "}
|
51
104
|
it 'raises a FieldNotDefined error' do
|
52
|
-
assert_raises(GraphQL::FieldNotDefinedError) { query.
|
105
|
+
assert_raises(GraphQL::FieldNotDefinedError) { query.as_result }
|
53
106
|
assert(Post.find(123).present?)
|
54
107
|
end
|
55
108
|
end
|
56
109
|
|
57
110
|
describe 'when the root call doesnt have an argument' do
|
58
|
-
let(:query_string) { "
|
59
|
-
it 'calls the node with
|
60
|
-
|
61
|
-
query.to_json
|
111
|
+
let(:query_string) { "context() { person_name }"}
|
112
|
+
it 'calls the node with no arguments' do
|
113
|
+
assert_equal "Han Solo", result["context"]["person_name"]
|
62
114
|
end
|
63
115
|
end
|
64
116
|
|
65
117
|
describe 'when requesting a collection' do
|
66
118
|
let(:query_string) { "post(123) {
|
67
119
|
title,
|
68
|
-
comments {
|
69
|
-
count,
|
70
|
-
edges {
|
71
|
-
cursor,
|
72
|
-
node {
|
73
|
-
content
|
74
|
-
}
|
75
|
-
}
|
76
|
-
}
|
120
|
+
comments { count, edges { cursor, node { content } } }
|
77
121
|
}"}
|
122
|
+
|
78
123
|
it 'returns collection data' do
|
79
|
-
assert_equal
|
124
|
+
assert_equal result, {
|
80
125
|
"123" => {
|
81
126
|
"title" => "My great post",
|
82
127
|
"comments" => {
|
83
128
|
"count" => 2,
|
84
129
|
"edges" => [
|
85
|
-
{
|
86
|
-
|
87
|
-
"node" => {
|
88
|
-
"content" => "I agree"
|
89
|
-
}
|
90
|
-
},
|
91
|
-
{
|
92
|
-
"cursor" => "445",
|
93
|
-
"node" => {
|
94
|
-
"content" => "I disagree"
|
95
|
-
}
|
96
|
-
}
|
130
|
+
{ "cursor" => "444", "node" => {"content" => "I agree"} },
|
131
|
+
{ "cursor" => "445", "node" => {"content" => "I disagree"}}
|
97
132
|
]
|
98
|
-
|
99
|
-
}
|
100
|
-
}
|
133
|
+
}}}
|
101
134
|
end
|
102
135
|
end
|
103
136
|
|
104
137
|
describe 'when making calls on a collection' do
|
105
|
-
let(:query_string) { "post(123) {
|
106
|
-
comments.first(1) {
|
107
|
-
edges { cursor, node { content } }
|
108
|
-
}
|
109
|
-
}"}
|
138
|
+
let(:query_string) { "post(123) { comments.first(1) { edges { cursor, node { content } } } }"}
|
110
139
|
|
111
140
|
it 'executes those calls' do
|
112
|
-
assert_equal
|
141
|
+
assert_equal result, {
|
113
142
|
"123" => {
|
114
143
|
"comments" => {
|
115
144
|
"edges" => [
|
116
|
-
{
|
117
|
-
"cursor" => "444",
|
118
|
-
"node" => {
|
119
|
-
"content" => "I agree"
|
120
|
-
}
|
121
|
-
}
|
145
|
+
{ "cursor" => "444", "node" => { "content" => "I agree"} }
|
122
146
|
]
|
123
|
-
|
124
|
-
}
|
125
|
-
}
|
147
|
+
}}}
|
126
148
|
end
|
127
149
|
end
|
128
150
|
|
129
151
|
describe 'when making DEEP calls on a collection' do
|
130
|
-
let(:query_string) { "post(123) {
|
131
|
-
comments.after(444).first(1) {
|
152
|
+
let(:query_string) { "post(123) { comments.after(444).first(1) {
|
132
153
|
edges { cursor, node { content } }
|
133
|
-
}
|
134
|
-
}"}
|
154
|
+
}}"}
|
135
155
|
|
136
156
|
it 'executes those calls' do
|
137
|
-
assert_equal
|
157
|
+
assert_equal result, {
|
138
158
|
"123" => {
|
139
159
|
"comments" => {
|
140
160
|
"edges" => [
|
141
161
|
{
|
142
162
|
"cursor" => "445",
|
143
|
-
"node" => {
|
144
|
-
"content" => "I disagree"
|
145
|
-
}
|
163
|
+
"node" => { "content" => "I disagree"}
|
146
164
|
}
|
147
165
|
]
|
148
|
-
|
149
|
-
}
|
150
|
-
}
|
166
|
+
}}}
|
151
167
|
end
|
152
168
|
end
|
169
|
+
|
170
|
+
describe 'when requesting fields at collection-level' do
|
171
|
+
let(:query_string) { "post(123) { comments { average_rating } }"}
|
172
|
+
|
173
|
+
it 'executes those calls' do
|
174
|
+
assert_equal result, { "123" => { "comments" => { "average_rating" => 3 } } }
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe 'when making calls on node fields' do
|
179
|
+
let(:query_string) { "post(123) { comments { edges { node { letters.from(3).for(3) }} } }"}
|
180
|
+
|
181
|
+
it 'makes calls on the fields' do
|
182
|
+
assert_equal ["gre", "isa"], result["123"]["comments"]["edges"].map {|e| e["node"]["letters"] }
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe 'when requesting collection-level fields that dont exist' do
|
187
|
+
let(:query_string) { "post(123) { comments { bogus_field } }"}
|
188
|
+
|
189
|
+
it 'raises FieldNotDefined' do
|
190
|
+
assert_raises(GraphQL::FieldNotDefinedError) { query.as_result }
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
describe 'when requesting fields on a related object' do
|
196
|
+
let(:query_string) { "comment(444) { post { title } }"}
|
197
|
+
it 'finds fields on that object' do
|
198
|
+
assert_equal "My great post", result["444"]["post"]["title"]
|
199
|
+
end
|
200
|
+
|
201
|
+
describe 'when the object doesnt exist' do
|
202
|
+
before do
|
203
|
+
Post.all.map(&:destroy)
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'blows_up' do # what _should_ this do?
|
207
|
+
assert_raises(RuntimeError) { result }
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe 'when edge classes were named explicitly' do
|
213
|
+
let(:query_string) { "post(123) { likes { any, edges { node { id } } } }"}
|
214
|
+
|
215
|
+
it 'gets node values' do
|
216
|
+
assert_equal ["991991","992992"], result["123"]["likes"]["edges"].map {|e| e["node"]["id"] }
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'gets edge values' do
|
220
|
+
assert_equal true, result["123"]["likes"]["any"]
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
describe '#context' do
|
225
|
+
let(:query_string) { "context() { person_name }"}
|
226
|
+
|
227
|
+
it 'is accessible inside nodes' do
|
228
|
+
assert_equal({"context" => {"person_name" => "Han Solo"}}, result)
|
229
|
+
end
|
230
|
+
|
231
|
+
describe 'inside edges' do
|
232
|
+
let(:query_string) { "post(123) { comments { viewer_name_length } }"}
|
233
|
+
it 'is accessible' do
|
234
|
+
assert_equal 8, result["123"]["comments"]["viewer_name_length"]
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
describe 'parsing error' do
|
240
|
+
let(:query_string) { "\n\n<< bogus >>"}
|
241
|
+
|
242
|
+
it 'raises SyntaxError' do
|
243
|
+
assert_raises(GraphQL::SyntaxError) { result }
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'contains line an character number' do
|
247
|
+
err = assert_raises(GraphQL::SyntaxError) { result }
|
248
|
+
assert_match(/1, 1/, err.to_s)
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'contains sample of text' do
|
252
|
+
err = assert_raises(GraphQL::SyntaxError) { result }
|
253
|
+
assert_includes(err.to_s, "<< bogus >>")
|
254
|
+
end
|
153
255
|
end
|
154
256
|
end
|