graphql 0.18.5 → 0.18.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9d69978a50350e058883fa1f9fdfc5c6e5dcc80b
4
- data.tar.gz: 97cc2fdfc3778f6b75cf34a2b9d5dcf6354a1a28
3
+ metadata.gz: 097a1f2ab62a05d6617d2445c0771066c1d547a3
4
+ data.tar.gz: c65cc3378d3a1e525881abfde3c520b2f2eac71a
5
5
  SHA512:
6
- metadata.gz: c6177a5c17291fc6f95f0f2d8e14f3831ebc9af7f46addd15bc3283a63310151c8fc7fbfc1acc332a181ab808060afb399fd87ce83db6e0088c093adabd8b35b
7
- data.tar.gz: b0464b86095e2aafa933d4dc5b6e5491ef2354df6025943967a78d36d63d7f7c2111e6bfaefe3b11abd5d8937c1ba14e160b5fe9d255cc7b5501d56b0f8e92a1
6
+ metadata.gz: 913f57d14573f3fef716bd604e1dc62827d1fb62361bde854e42fe32f357a3e88ee382f1f1605a1bb11a16fcc80f2a9e7ff5e223a408c83bf5b224b8e9d76913
7
+ data.tar.gz: cfd8abc3faad374f484e97ef7b3505486c60067fefb6c1295f3eb55f0478f750dd344c3da9a876c87179a8f3772597245a05e561430df4a4c4f685f055e17a4b
data/lib/graphql.rb CHANGED
@@ -58,6 +58,7 @@ require "graphql/introspection"
58
58
  require "graphql/language"
59
59
  require "graphql/analysis"
60
60
  require "graphql/schema"
61
+ require "graphql/schema/loader"
61
62
  require "graphql/schema/printer"
62
63
 
63
64
  # Order does not matter for these:
@@ -26,5 +26,19 @@ module GraphQL
26
26
  end
27
27
 
28
28
  attr_writer :name
29
+
30
+ def type=(new_return_type)
31
+ ensure_defined
32
+ @clean_type = nil
33
+ @dirty_type = new_return_type
34
+ end
35
+
36
+ # Get the return type for this field.
37
+ def type
38
+ @clean_type ||= begin
39
+ ensure_defined
40
+ GraphQL::BaseType.resolve_related_type(@dirty_type)
41
+ end
42
+ end
29
43
  end
30
44
  end
@@ -56,7 +56,7 @@ module GraphQL
56
56
  # }
57
57
  #
58
58
  class EnumType < GraphQL::BaseType
59
- accepts_definitions value: GraphQL::Define::AssignEnumValue
59
+ accepts_definitions :values, value: GraphQL::Define::AssignEnumValue
60
60
 
61
61
  def initialize
62
62
  @values_by_name = {}
@@ -124,6 +124,10 @@ module GraphQL
124
124
  #
125
125
  # Created with the `value` helper
126
126
  class EnumValue
127
+ def self.define(name:, description: nil, deprecation_reason: nil, value: nil)
128
+ new(name: name, description: description, deprecation_reason: deprecation_reason, value: value)
129
+ end
130
+
127
131
  attr_accessor :name, :description, :deprecation_reason, :value
128
132
  def initialize(name:, description:, deprecation_reason:, value:)
129
133
  @name = name
data/lib/graphql/field.rb CHANGED
@@ -120,7 +120,7 @@ module GraphQL
120
120
  #
121
121
  class Field
122
122
  include GraphQL::Define::InstanceDefinable
123
- accepts_definitions :name, :description, :resolve, :type, :property, :deprecation_reason, :complexity, :hash_key, argument: GraphQL::Define::AssignArgument
123
+ accepts_definitions :name, :description, :resolve, :type, :property, :deprecation_reason, :complexity, :hash_key, :arguments, argument: GraphQL::Define::AssignArgument
124
124
 
125
125
  lazy_defined_attr_accessor :deprecation_reason, :description, :property, :hash_key
126
126
 
@@ -24,6 +24,7 @@ module GraphQL
24
24
  #
25
25
  class InputObjectType < GraphQL::BaseType
26
26
  accepts_definitions(
27
+ :arguments,
27
28
  input_field: GraphQL::Define::AssignArgument,
28
29
  argument: GraphQL::Define::AssignArgument
29
30
  )
@@ -23,7 +23,7 @@ module GraphQL
23
23
  #
24
24
  class InterfaceType < GraphQL::BaseType
25
25
  include GraphQL::BaseType::HasPossibleTypes
26
- accepts_definitions :resolve_type, field: GraphQL::Define::AssignObjectField
26
+ accepts_definitions :resolve_type, :fields, field: GraphQL::Define::AssignObjectField
27
27
 
28
28
  lazy_defined_attr_accessor :fields
29
29
 
@@ -0,0 +1,577 @@
1
+ module GraphQL
2
+ module Language
3
+ # If you create your own GraphQL parser, can verify it using these tests.
4
+ #
5
+ # @example Include these tests in a Minitest suite
6
+ # require 'graphql/language/parser_tests'
7
+ #
8
+ # describe MyParser do
9
+ # include GraphQL::Language::ParserTests
10
+ # subject { MyParser }
11
+ # end
12
+ module ParserTests
13
+ def self.included(test)
14
+ test.send(:describe, "Parser Tests") do
15
+ let(:document) { subject.parse(query_string) }
16
+ let(:query_string) {%|
17
+ query getStuff($someVar: Int = 1, $anotherVar: [String!] ) @skip(if: false) {
18
+ myField: someField(someArg: $someVar, ok: 1.4) @skip(if: $anotherVar) @thing(or: "Whatever")
19
+
20
+ anotherField(someArg: [1,2,3]) {
21
+ nestedField
22
+ ... moreNestedFields @skip(if: true)
23
+ }
24
+
25
+ ... on OtherType @include(unless: false){
26
+ field(arg: [{key: "value", anotherKey: 0.9, anotherAnotherKey: WHATEVER}])
27
+ anotherField
28
+ }
29
+
30
+ ... {
31
+ id
32
+ }
33
+ }
34
+
35
+ fragment moreNestedFields on NestedType @or(something: "ok") {
36
+ anotherNestedField
37
+ }
38
+ |}
39
+
40
+ describe ".parse" do
41
+ it "parses queries" do
42
+ assert document
43
+ end
44
+
45
+ describe "visited nodes" do
46
+ let(:query) { document.definitions.first }
47
+ let(:fragment_def) { document.definitions.last }
48
+
49
+ it "creates a valid document" do
50
+ assert document.is_a?(GraphQL::Language::Nodes::Document)
51
+ assert_equal 2, document.definitions.length
52
+ end
53
+
54
+ it "creates a valid operation" do
55
+ assert query.is_a?(GraphQL::Language::Nodes::OperationDefinition)
56
+ assert_equal "getStuff", query.name
57
+ assert_equal "query", query.operation_type
58
+ assert_equal 2, query.variables.length
59
+ assert_equal 4, query.selections.length
60
+ assert_equal 1, query.directives.length
61
+ assert_equal [2, 13], [query.line, query.col]
62
+ end
63
+
64
+ it "creates a valid fragment definition" do
65
+ assert fragment_def.is_a?(GraphQL::Language::Nodes::FragmentDefinition)
66
+ assert_equal "moreNestedFields", fragment_def.name
67
+ assert_equal 1, fragment_def.selections.length
68
+ assert_equal "NestedType", fragment_def.type
69
+ assert_equal 1, fragment_def.directives.length
70
+ assert_equal [20, 13], fragment_def.position
71
+ end
72
+
73
+ describe "variable definitions" do
74
+ let(:optional_var) { query.variables.first }
75
+ it "gets name and type" do
76
+ assert_equal "someVar", optional_var.name
77
+ assert_equal "Int", optional_var.type.name
78
+ end
79
+
80
+ it "gets default value" do
81
+ assert_equal 1, optional_var.default_value
82
+ end
83
+
84
+ it "gets position info" do
85
+ assert_equal [2, 28], optional_var.position
86
+ end
87
+ end
88
+
89
+ describe "fields" do
90
+ let(:leaf_field) { query.selections.first }
91
+ let(:parent_field) { query.selections[1] }
92
+
93
+ it "gets name, alias, arguments and directives" do
94
+ assert_equal "someField", leaf_field.name
95
+ assert_equal "myField", leaf_field.alias
96
+ assert_equal 2, leaf_field.directives.length
97
+ assert_equal 2, leaf_field.arguments.length
98
+ end
99
+
100
+ it "gets nested fields" do
101
+ assert_equal 2, parent_field.selections.length
102
+ end
103
+
104
+ it "gets location info" do
105
+ assert_equal [3 ,15], leaf_field.position
106
+ end
107
+
108
+ describe "when the arguments list is empty" do
109
+ let(:query_string) { "{ field() }"}
110
+ let(:field) { query.selections.first }
111
+ it "has zero arguments" do
112
+ assert_equal 0, field.arguments.length
113
+ end
114
+ end
115
+
116
+ describe "when selections are empty" do
117
+ let(:query_string) { "{ field { } }"}
118
+ let(:field) { query.selections.first }
119
+ it "has zero selections" do
120
+ assert_equal 0, field.selections.length
121
+ end
122
+ end
123
+ end
124
+
125
+ describe "arguments" do
126
+ let(:literal_argument) { query.selections.first.arguments.last }
127
+ let(:variable_argument) { query.selections.first.arguments.first }
128
+
129
+ it "gets name and literal value" do
130
+ assert_equal "ok", literal_argument.name
131
+ assert_equal 1.4, literal_argument.value
132
+ end
133
+
134
+ it "gets name and variable value" do
135
+ assert_equal "someArg", variable_argument.name
136
+ assert_equal "someVar", variable_argument.value.name
137
+ end
138
+
139
+
140
+ it "gets position info" do
141
+ assert_equal [3, 34], variable_argument.position
142
+ end
143
+ end
144
+
145
+ describe "fragment spreads" do
146
+ let(:fragment_spread) { query.selections[1].selections.last }
147
+ it "gets the name and directives" do
148
+ assert_equal "moreNestedFields", fragment_spread.name
149
+ assert_equal 1, fragment_spread.directives.length
150
+ end
151
+
152
+ it "gets position info" do
153
+ assert_equal [7, 17], fragment_spread.position
154
+ end
155
+ end
156
+
157
+ describe "directives" do
158
+ let(:variable_directive) { query.selections.first.directives.first }
159
+
160
+ it "gets the name and arguments" do
161
+ assert_equal "skip", variable_directive.name
162
+ assert_equal "if", variable_directive.arguments.first.name
163
+ assert_equal 1, variable_directive.arguments.length
164
+ end
165
+
166
+ it "gets position info" do
167
+ assert_equal [3, 62], variable_directive.position
168
+ end
169
+ end
170
+
171
+ describe "inline fragments" do
172
+ let(:inline_fragment) { query.selections[2] }
173
+ let(:typeless_inline_fragment) { query.selections[3] }
174
+
175
+ it "gets the type and directives" do
176
+ assert_equal "OtherType", inline_fragment.type
177
+ assert_equal 2, inline_fragment.selections.length
178
+ assert_equal 1, inline_fragment.directives.length
179
+ end
180
+
181
+ it "gets inline fragments without type conditions" do
182
+ assert_equal nil, typeless_inline_fragment.type
183
+ assert_equal 1, typeless_inline_fragment.selections.length
184
+ assert_equal 0, typeless_inline_fragment.directives.length
185
+ end
186
+
187
+ it "gets position info" do
188
+ assert_equal [10, 15], inline_fragment.position
189
+ end
190
+ end
191
+
192
+ describe "inputs" do
193
+ let(:query_string) {%|
194
+ {
195
+ field(
196
+ int: 3,
197
+ float: 4.7e-24,
198
+ bool: false,
199
+ string: "☀︎🏆\\n escaped \\" unicode \\u00b6 /",
200
+ enum: ENUM_NAME,
201
+ array: [7, 8, 9]
202
+ object: {a: [1,2,3], b: {c: "4"}}
203
+ unicode_bom: "\xef\xbb\xbfquery"
204
+ keywordEnum: on
205
+ )
206
+ }
207
+ |}
208
+
209
+ let(:inputs) { document.definitions.first.selections.first.arguments }
210
+
211
+ it "parses ints" do
212
+ assert_equal 3, inputs[0].value
213
+ end
214
+
215
+ it "parses floats" do
216
+ assert_equal 0.47e-23, inputs[1].value
217
+ end
218
+
219
+ it "parses booleans" do
220
+ assert_equal false, inputs[2].value
221
+ end
222
+
223
+ it "parses UTF-8 strings" do
224
+ assert_equal %|☀︎🏆\n escaped " unicode ¶ /|, inputs[3].value
225
+ end
226
+
227
+ it "parses enums" do
228
+ assert_instance_of GraphQL::Language::Nodes::Enum, inputs[4].value
229
+ assert_equal "ENUM_NAME", inputs[4].value.name
230
+ end
231
+
232
+ it "parses arrays" do
233
+ assert_equal [7,8,9], inputs[5].value
234
+ end
235
+
236
+ it "parses objects" do
237
+ obj = inputs[6].value
238
+ assert_equal "a", obj.arguments[0].name
239
+ assert_equal [1,2,3], obj.arguments[0].value
240
+ assert_equal "b", obj.arguments[1].name
241
+ assert_equal "c", obj.arguments[1].value.arguments[0].name
242
+ assert_equal "4", obj.arguments[1].value.arguments[0].value
243
+ end
244
+
245
+ it "parses unicode bom" do
246
+ obj = inputs[7].value
247
+ assert_equal %|\xef\xbb\xbfquery|, inputs[7].value
248
+ end
249
+
250
+ it "parses enum 'on''" do
251
+ assert_equal "on", inputs[8].value.name
252
+ end
253
+ end
254
+ end
255
+
256
+ describe "unnamed queries" do
257
+ let(:query_string) {%|
258
+ { name, age, height }
259
+ |}
260
+ let(:operation) { document.definitions.first }
261
+
262
+ it "parses unnamed queries" do
263
+ assert_equal 1, document.definitions.length
264
+ assert_equal "query", operation.operation_type
265
+ assert_equal nil, operation.name
266
+ assert_equal 3, operation.selections.length
267
+ end
268
+ end
269
+
270
+ describe "introspection query" do
271
+ let(:query_string) { GraphQL::Introspection::INTROSPECTION_QUERY }
272
+
273
+ it "parses a big ol' query" do
274
+ assert(document)
275
+ end
276
+ end
277
+
278
+ describe "schema" do
279
+ it "parses the test schema" do
280
+ schema = DummySchema
281
+ schema_string = GraphQL::Schema::Printer.print_schema(schema)
282
+ document = subject.parse(schema_string)
283
+
284
+ assert_equal schema_string, document.to_query_string
285
+ end
286
+
287
+ it "parses mimal schema definition" do
288
+ document = subject.parse('schema { query: QueryRoot }')
289
+
290
+ schema = document.definitions.first
291
+ assert_equal 'QueryRoot', schema.query
292
+ assert_equal nil, schema.mutation
293
+ assert_equal nil, schema.subscription
294
+ end
295
+
296
+ it "parses full schema definitions" do
297
+ document = subject.parse('
298
+ schema {
299
+ query: QueryRoot
300
+ mutation: MutationRoot
301
+ subscription: SubscriptionRoot
302
+ }
303
+ ')
304
+
305
+ schema = document.definitions.first
306
+ assert_equal 'QueryRoot', schema.query
307
+ assert_equal 'MutationRoot', schema.mutation
308
+ assert_equal 'SubscriptionRoot', schema.subscription
309
+ end
310
+
311
+ it "parses object types" do
312
+ document = subject.parse('
313
+ type Comment implements Node {
314
+ id: ID!
315
+ }
316
+ ')
317
+
318
+ type = document.definitions.first
319
+ assert_equal GraphQL::Language::Nodes::ObjectTypeDefinition, type.class
320
+ assert_equal 'Comment', type.name
321
+ assert_equal ['Node'], type.interfaces
322
+ assert_equal ['id'], type.fields.map(&:name)
323
+ assert_equal [], type.fields[0].arguments
324
+ assert_equal 'ID', type.fields[0].type.of_type.name
325
+ end
326
+
327
+ it "parses field arguments" do
328
+ document = subject.parse('
329
+ type Mutation {
330
+ post(id: ID!, data: PostData = { message: "First!1!", type: BLOG, tags: ["Test", "Annoying"] }): Post
331
+ }
332
+ ')
333
+
334
+ field = document.definitions.first.fields.first
335
+ assert_equal ['id', 'data'], field.arguments.map(&:name)
336
+ data_arg = field.arguments[1]
337
+ assert_equal 'PostData', data_arg.type.name
338
+ assert_equal ['message', 'type', 'tags'], data_arg.default_value.arguments.map(&:name)
339
+ tags_arg = data_arg.default_value.arguments[2]
340
+ assert_equal ['Test', 'Annoying'], tags_arg.value
341
+ end
342
+
343
+ it "parses scalar types" do
344
+ document = subject.parse('scalar DateTime')
345
+
346
+ type = document.definitions.first
347
+ assert_equal GraphQL::Language::Nodes::ScalarTypeDefinition, type.class
348
+ assert_equal 'DateTime', type.name
349
+ end
350
+
351
+ it "parses interface types" do
352
+ document = subject.parse('
353
+ interface Node {
354
+ id: ID!
355
+ }
356
+ ')
357
+
358
+ type = document.definitions.first
359
+ assert_equal GraphQL::Language::Nodes::InterfaceTypeDefinition, type.class
360
+ assert_equal 'Node', type.name
361
+ assert_equal ['id'], type.fields.map(&:name)
362
+ assert_equal [], type.fields[0].arguments
363
+ assert_equal 'ID', type.fields[0].type.of_type.name
364
+ end
365
+
366
+ it "parses enum types" do
367
+ document = subject.parse('
368
+ enum DogCommand { SIT, DOWN, HEEL }
369
+ ')
370
+
371
+ type = document.definitions.first
372
+ assert_equal GraphQL::Language::Nodes::EnumTypeDefinition, type.class
373
+ assert_equal 'DogCommand', type.name
374
+ assert_equal ['SIT', 'DOWN', 'HEEL'], type.values
375
+ end
376
+
377
+ it "parses input object types" do
378
+ document = subject.parse('
379
+ input EmptyMutationInput {
380
+ clientMutationId: String
381
+ }
382
+ ')
383
+
384
+ type = document.definitions.first
385
+ assert_equal GraphQL::Language::Nodes::InputObjectTypeDefinition, type.class
386
+ assert_equal 'EmptyMutationInput', type.name
387
+ assert_equal ['clientMutationId'], type.fields.map(&:name)
388
+ assert_equal 'String', type.fields[0].type.name
389
+ assert_equal nil, type.fields[0].default_value
390
+ end
391
+ end
392
+ end
393
+
394
+ describe "errors" do
395
+ let(:query_string) {%| query doSomething { bogus { } |}
396
+ it "raises a parse error" do
397
+ err = assert_raises(GraphQL::ParseError) { document }
398
+ end
399
+
400
+ it "correctly identifies parse error location and content" do
401
+ e = assert_raises(GraphQL::ParseError) do
402
+ GraphQL.parse("
403
+ query getCoupons {
404
+ allCoupons: {data{id}}
405
+ }
406
+ ")
407
+ end
408
+ assert_includes(e.message, '"{"')
409
+ assert_includes(e.message, "RCURLY")
410
+ assert_equal(3, e.line)
411
+ assert_equal(33, e.col)
412
+ end
413
+
414
+ it "handles unexpected ends" do
415
+ err = assert_raises(GraphQL::ParseError) { GraphQL.parse("{ ") }
416
+ assert_equal "Unexpected end of document", err.message
417
+ end
418
+
419
+ it "rejects unsupported characters" do
420
+ e = assert_raises(GraphQL::ParseError) do
421
+ GraphQL.parse("{ field; }")
422
+ end
423
+
424
+ assert_includes(e.message, "Parse error on \";\"")
425
+ end
426
+
427
+ it "rejects control characters" do
428
+ e = assert_raises(GraphQL::ParseError) do
429
+ GraphQL.parse("{ \afield }")
430
+ end
431
+
432
+ assert_includes(e.message, "Parse error on \"\\a\"")
433
+ end
434
+
435
+ it "rejects partial BOM" do
436
+ e = assert_raises(GraphQL::ParseError) do
437
+ GraphQL.parse("{ \xeffield }")
438
+ end
439
+
440
+ assert_includes(e.message, "Parse error on \"\\xEF\"")
441
+ end
442
+
443
+ it "rejects vertical tabs" do
444
+ e = assert_raises(GraphQL::ParseError) do
445
+ GraphQL.parse("{ \vfield }")
446
+ end
447
+
448
+ assert_includes(e.message, "Parse error on \"\\v\"")
449
+ end
450
+
451
+ it "rejects form feed" do
452
+ e = assert_raises(GraphQL::ParseError) do
453
+ GraphQL.parse("{ \ffield }")
454
+ end
455
+
456
+ assert_includes(e.message, "Parse error on \"\\f\"")
457
+ end
458
+
459
+ it "rejects no break space" do
460
+ e = assert_raises(GraphQL::ParseError) do
461
+ GraphQL.parse("{ \xa0field }")
462
+ end
463
+
464
+ assert_includes(e.message, "Parse error on \"\\xA0\"")
465
+ end
466
+
467
+ it "rejects unterminated strings" do
468
+ e = assert_raises(GraphQL::ParseError) do
469
+ GraphQL.parse("\"")
470
+ end
471
+
472
+ assert_includes(e.message, "Parse error on \"\\\"\"")
473
+
474
+ e = assert_raises(GraphQL::ParseError) do
475
+ GraphQL.parse("\"\n\"")
476
+ end
477
+
478
+ assert_includes(e.message, "Parse error on \"\\n\"")
479
+ end
480
+
481
+ it "rejects bad escape sequence in strings" do
482
+ e = assert_raises(GraphQL::ParseError) do
483
+ GraphQL.parse("{ field(arg:\"\\x\") }")
484
+ end
485
+
486
+ assert_includes(e.message, "Parse error on bad Unicode escape sequence")
487
+ end
488
+
489
+ it "rejects incomplete escape sequence in strings" do
490
+ e = assert_raises(GraphQL::ParseError) do
491
+ GraphQL.parse("{ field(arg:\"\\u1\") }")
492
+ end
493
+
494
+ assert_includes(e.message, "bad Unicode escape sequence")
495
+ end
496
+
497
+ it "rejects unicode escape with bad chars" do
498
+ e = assert_raises(GraphQL::ParseError) do
499
+ GraphQL.parse("{ field(arg:\"\\u0XX1\") }")
500
+ end
501
+
502
+ assert_includes(e.message, "bad Unicode escape sequence")
503
+
504
+ e = assert_raises(GraphQL::ParseError) do
505
+ GraphQL.parse("{ field(arg:\"\\uXXXX\") }")
506
+ end
507
+
508
+ assert_includes(e.message, "bad Unicode escape sequence")
509
+
510
+
511
+ e = assert_raises(GraphQL::ParseError) do
512
+ GraphQL.parse("{ field(arg:\"\\uFXXX\") }")
513
+ end
514
+
515
+ assert_includes(e.message, "bad Unicode escape sequence")
516
+
517
+
518
+ e = assert_raises(GraphQL::ParseError) do
519
+ GraphQL.parse("{ field(arg:\"\\uXXXF\") }")
520
+ end
521
+
522
+ assert_includes(e.message, "bad Unicode escape sequence")
523
+ end
524
+
525
+ it "rejects fragments named 'on'" do
526
+ e = assert_raises(GraphQL::ParseError) do
527
+ GraphQL.parse("fragment on on on { on }")
528
+ end
529
+
530
+ assert_includes(e.message, "Parse error on \"on\"")
531
+ end
532
+
533
+ it "rejects fragment spread of 'on'" do
534
+ e = assert_raises(GraphQL::ParseError) do
535
+ GraphQL.parse("{ ...on }")
536
+ end
537
+
538
+ assert_includes(e.message, "Parse error on \"}\"")
539
+ end
540
+
541
+ it "rejects null value" do
542
+ e = assert_raises(GraphQL::ParseError) do
543
+ GraphQL.parse("{ fieldWithNullableStringInput(input: null) }")
544
+ end
545
+
546
+ assert_includes(e.message, "Parse error on \"null\"")
547
+ end
548
+ end
549
+
550
+
551
+ describe "whitespace" do
552
+ describe "whitespace-only queries" do
553
+ let(:query_string) { " " }
554
+ it "doesn't blow up" do
555
+ assert_equal [], document.definitions
556
+ end
557
+ end
558
+
559
+ describe "empty string queries" do
560
+ let(:query_string) { "" }
561
+ it "doesn't blow up" do
562
+ assert_equal [], document.definitions
563
+ end
564
+ end
565
+
566
+ describe "using tabs as whitespace" do
567
+ let(:query_string) { "\t{\t\tid, \tname}"}
568
+ it "parses the query" do
569
+ assert_equal 1, document.definitions.length
570
+ end
571
+ end
572
+ end
573
+ end
574
+ end
575
+ end
576
+ end
577
+ end