tinygql 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,46 +1,34 @@
1
1
  module TinyGQL
2
2
  module Visitors
3
3
  module Visitor
4
- <%- nodes.each do |node| -%>
4
+ <% nodes.each do |node| %>
5
5
  def handle_<%= node.human_name %> obj
6
6
  <%- node.fields.find_all(&:visitable?).each do |field| -%>
7
- <%- if field.nullable? -%>
8
- if obj.<%= field.name %>
9
- <%- end -%>
10
7
  <%- if field.list? -%>
11
- obj.<%= field.name %>.each { |v| v.accept self }
8
+ obj.<%= field.name %>.each { |v| v.accept self }<% if field.nullable? %> if obj.<%= field.name %><% end %>
12
9
  <%- end -%>
13
10
  <%- if field.node? -%>
14
- obj.<%= field.name %>.accept self
15
- <%- end -%>
16
- <%- if field.nullable? -%>
17
- end
11
+ obj.<%= field.name %>.accept(self)<% if field.nullable? %> if obj.<%= field.name %><% end %>
18
12
  <%- end -%>
19
13
  <%- end -%>
20
14
  end
21
- <%- end -%>
15
+ <% end %>
22
16
  end
23
17
 
24
18
  module Fold
25
- <%- nodes.each do |node| -%>
19
+ <% nodes.each do |node| %>
26
20
  def handle_<%= node.human_name %> obj, seed
27
21
  <%- node.fields.find_all(&:visitable?).each do |field| -%>
28
- <%- if field.nullable? -%>
29
- if obj.<%= field.name %>
30
- <%- end -%>
31
22
  <%- if field.list? -%>
32
- obj.<%= field.name %>.each { |v| seed = v.fold(self, seed) }
23
+ obj.<%= field.name %>.each { |v| seed = v.fold(self, seed) }<% if field.nullable? %> if obj.<%= field.name %><% end %>
33
24
  <%- end -%>
34
25
  <%- if field.node? -%>
35
- seed = obj.<%= field.name %>.fold self, seed
36
- <%- end -%>
37
- <%- if field.nullable? -%>
38
- end
26
+ seed = obj.<%= field.name %>.fold(self, seed)<% if field.nullable? %> if obj.<%= field.name %><% end %>
39
27
  <%- end -%>
40
28
  <%- end -%>
41
29
  seed
42
30
  end
43
- <%- end -%>
31
+ <% end %>
44
32
  end
45
33
  end
46
34
  end
data/test/lexer_test.rb CHANGED
@@ -101,5 +101,83 @@ eod
101
101
  [:RCURLY, "}"],
102
102
  [:RCURLY, "}"]], toks
103
103
  end
104
+
105
+ def test_lex_4
106
+ words = ["true", "null", "enum", "type"]
107
+ doc = words.join(" ")
108
+
109
+ lexer = Lexer.new doc
110
+ toks = []
111
+ while tok = lexer.next_token
112
+ toks << tok
113
+ end
114
+
115
+ assert_equal words.map { |x| [x.upcase.to_sym, x] }, toks
116
+ end
117
+
118
+ def test_lex_5
119
+ words = ["input", "false", "query", "union"]
120
+ doc = words.join(" ")
121
+
122
+ lexer = Lexer.new doc
123
+ toks = []
124
+ while tok = lexer.next_token
125
+ toks << tok
126
+ end
127
+
128
+ assert_equal words.map { |x| [x.upcase.to_sym, x] }, toks
129
+ end
130
+
131
+ def test_lex_6
132
+ words = ["extend", "scalar", "schema"]
133
+ doc = words.join(" ")
134
+
135
+ lexer = Lexer.new doc
136
+ toks = []
137
+ while tok = lexer.next_token
138
+ toks << tok
139
+ end
140
+
141
+ assert_equal words.map { |x| [x.upcase.to_sym, x] }, toks
142
+ end
143
+
144
+ def test_lex_8
145
+ words = ["mutation", "fragment"]
146
+ doc = words.join(" ")
147
+
148
+ lexer = Lexer.new doc
149
+ toks = []
150
+ while tok = lexer.next_token
151
+ toks << tok
152
+ end
153
+
154
+ assert_equal words.map { |x| [x.upcase.to_sym, x] }, toks
155
+ end
156
+
157
+ def test_lex_9
158
+ words = ["interface", "directive"]
159
+ doc = words.join(" ")
160
+
161
+ lexer = Lexer.new doc
162
+ toks = []
163
+ while tok = lexer.next_token
164
+ toks << tok
165
+ end
166
+
167
+ assert_equal words.map { |x| [x.upcase.to_sym, x] }, toks
168
+ end
169
+
170
+ def test_kw_lex
171
+ words = ["on", "fragment", "true", "false", "null", "query", "mutation", "subscription", "schema", "scalar", "type", "extend", "implements", "interface", "union", "enum", "input", "directive", "repeatable"]
172
+ doc = words.join(" ")
173
+
174
+ lexer = Lexer.new doc
175
+ toks = []
176
+ while tok = lexer.next_token
177
+ toks << tok
178
+ end
179
+
180
+ assert_equal words.map { |x| [x.upcase.to_sym, x] }, toks
181
+ end
104
182
  end
105
183
  end
data/test/parser_test.rb CHANGED
@@ -3,6 +3,13 @@ require "tinygql"
3
3
 
4
4
  module TinyGQL
5
5
  class ParserTest < Test
6
+ def test_homogeneous_ast
7
+ %w{ kitchen-sink.graphql schema-extensions.graphql schema-kitchen-sink.graphql }.each do |f|
8
+ ast = Parser.parse File.read(File.join(__dir__, f))
9
+ assert ast.all? { |x| x.is_a?(TinyGQL::Nodes::Node) }
10
+ end
11
+ end
12
+
6
13
  def test_multi_tok
7
14
  doc = <<-eod
8
15
  mutation aaron($neat: Int = 123) @foo(lol: { lon: 456 }) {
@@ -39,6 +46,23 @@ eod
39
46
  assert_equal ["likeStory", "story", "likeCount"], ast.find_all(&:field?).map(&:name)
40
47
  end
41
48
 
49
+ def test_has_position_and_line
50
+ doc = <<-eod
51
+ mutation {
52
+ likeStory(sturyID: 12345) {
53
+ story {
54
+ likeCount
55
+ }
56
+ }
57
+ }
58
+ eod
59
+ parser = Parser.new doc
60
+ ast = parser.parse
61
+ expected = ["likeStory", "story", "likeCount"].map { |str| doc.index(str) + str.bytesize }
62
+ assert_equal expected, ast.find_all(&:field?).map(&:pos)
63
+ assert_equal [2, 3, 4], ast.find_all(&:field?).map { |n| n.line(doc) }
64
+ end
65
+
42
66
  def test_field_alias
43
67
  doc = <<-eod
44
68
  mutation {
@@ -187,5 +211,49 @@ directive @skip(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
187
211
  assert_equal "neat!", node.description.value
188
212
  assert_equal ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], node.directive_locations.map(&:name)
189
213
  end
214
+
215
+ def test_scalar_schema_extensions
216
+ ast = Parser.parse File.read(File.join(__dir__, "schema-extensions.graphql"))
217
+ node = ast.find { |x| x.scalar_type_extension? && x.name == "PositiveInt" }
218
+ assert node
219
+ assert_equal 2, node.directives.length
220
+ end
221
+
222
+ def test_scalar_schema_extensions_no_directives
223
+ ast = Parser.parse File.read(File.join(__dir__, "schema-extensions.graphql"))
224
+ node = ast.find { |x| x.scalar_type_extension? && x.name == "Aaron" }
225
+ assert node
226
+ assert_nil node.directives
227
+ end
228
+
229
+ def test_interface_extension
230
+ ast = Parser.parse File.read(File.join(__dir__, "schema-extensions.graphql"))
231
+ node = ast.find { |x| x.interface_type_extension? && x.name == "NamedEntity" }
232
+ assert node
233
+ assert_nil node.directives
234
+ assert node.fields_definition
235
+ end
236
+
237
+ def test_union_extension
238
+ ast = Parser.parse File.read(File.join(__dir__, "schema-extensions.graphql"))
239
+ node = ast.find { |x| x.union_type_extension? && x.name == "Cool" }
240
+ assert node
241
+ assert_equal 1, node.directives.length
242
+ assert_equal "foo", node.directives.first.name
243
+ end
244
+
245
+ def test_enum_extension
246
+ ast = Parser.parse File.read(File.join(__dir__, "schema-extensions.graphql"))
247
+ assert ast.find { |x| x.enum_type_extension? && x.name == "Direction" }
248
+ assert ast.find { |x| x.enum_type_extension? && x.name == "AnnotatedEnum" }
249
+ assert ast.find { |x| x.enum_type_extension? && x.name == "Neat" }
250
+ end
251
+
252
+ def test_input_extension
253
+ ast = Parser.parse File.read(File.join(__dir__, "schema-extensions.graphql"))
254
+ assert ast.find { |x| x.input_object_type_extension? && x.name == "InputType" }
255
+ assert ast.find { |x| x.input_object_type_extension? && x.name == "AnnotatedInput" }
256
+ assert ast.find { |x| x.input_object_type_extension? && x.name == "NeatInput" }
257
+ end
190
258
  end
191
259
  end
@@ -0,0 +1,48 @@
1
+ extend scalar PositiveInt
2
+ @serializationType(name: "global::System.Int32")
3
+ @runtimeType(name: "global::System.Int32")
4
+
5
+ extend scalar Aaron
6
+
7
+ extend interface NamedEntity {
8
+ nickname: String
9
+ }
10
+
11
+ extend type Person {
12
+ nickname: String
13
+ }
14
+
15
+ extend type Business {
16
+ nickname: String
17
+ }
18
+
19
+ extend interface NamedEntity @addedDirective
20
+
21
+ extend union Cool @foo
22
+
23
+ extend union Great @onUnion = A | B
24
+
25
+ extend enum Direction {
26
+ NORTH
27
+ EAST
28
+ SOUTH
29
+ WEST
30
+ }
31
+
32
+ extend enum AnnotatedEnum @onEnum {
33
+ ANNOTATED_VALUE @onEnumValue
34
+ OTHER_VALUE
35
+ }
36
+
37
+ extend enum Neat @onEnum
38
+
39
+ extend input InputType {
40
+ key: String!
41
+ answer: Int = 42
42
+ }
43
+
44
+ extend input AnnotatedInput @onInputObjectType {
45
+ annotatedField: Type @onField
46
+ }
47
+
48
+ extend input NeatInput @onInputObjectType
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tinygql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Patterson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-12 00:00:00.000000000 Z
11
+ date: 2023-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -67,6 +67,7 @@ files:
67
67
  - test/kitchen-sink.graphql
68
68
  - test/lexer_test.rb
69
69
  - test/parser_test.rb
70
+ - test/schema-extensions.graphql
70
71
  - test/schema-kitchen-sink.graphql
71
72
  - tinygql.gemspec
72
73
  homepage: https://github.com/tenderlove/tinygql
@@ -97,4 +98,5 @@ test_files:
97
98
  - test/kitchen-sink.graphql
98
99
  - test/lexer_test.rb
99
100
  - test/parser_test.rb
101
+ - test/schema-extensions.graphql
100
102
  - test/schema-kitchen-sink.graphql