graphql 0.18.14 → 0.18.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/analysis/query_complexity.rb +15 -6
  3. data/lib/graphql/analysis/query_depth.rb +11 -10
  4. data/lib/graphql/directive.rb +2 -6
  5. data/lib/graphql/directive/include_directive.rb +0 -4
  6. data/lib/graphql/directive/skip_directive.rb +0 -4
  7. data/lib/graphql/execution/directive_checks.rb +22 -13
  8. data/lib/graphql/execution_error.rb +7 -0
  9. data/lib/graphql/internal_representation/node.rb +20 -2
  10. data/lib/graphql/internal_representation/rewrite.rb +66 -20
  11. data/lib/graphql/language/generation.rb +22 -8
  12. data/lib/graphql/language/nodes.rb +48 -20
  13. data/lib/graphql/language/parser.rb +436 -423
  14. data/lib/graphql/language/parser.y +22 -19
  15. data/lib/graphql/language/parser_tests.rb +131 -2
  16. data/lib/graphql/query/serial_execution/field_resolution.rb +1 -0
  17. data/lib/graphql/query/serial_execution/selection_resolution.rb +1 -1
  18. data/lib/graphql/query/serial_execution/value_resolution.rb +4 -1
  19. data/lib/graphql/schema/printer.rb +1 -1
  20. data/lib/graphql/static_validation/message.rb +1 -1
  21. data/lib/graphql/version.rb +1 -1
  22. data/readme.md +10 -12
  23. data/spec/graphql/directive_spec.rb +139 -1
  24. data/spec/graphql/execution_error_spec.rb +63 -3
  25. data/spec/graphql/introspection/type_type_spec.rb +2 -0
  26. data/spec/graphql/language/generation_spec.rb +55 -7
  27. data/spec/graphql/query/executor_spec.rb +4 -2
  28. data/spec/graphql/schema/catchall_middleware_spec.rb +1 -0
  29. data/spec/graphql/schema/printer_spec.rb +1 -1
  30. data/spec/graphql/schema/timeout_middleware_spec.rb +10 -5
  31. data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +6 -6
  32. data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +4 -4
  33. data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +2 -2
  34. data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +2 -2
  35. data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +3 -3
  36. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +2 -2
  37. data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +3 -3
  38. data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +2 -2
  39. data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +2 -2
  40. data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +1 -1
  41. data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +3 -3
  42. data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +2 -2
  43. data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +1 -1
  44. data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +3 -3
  45. data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +1 -1
  46. data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +4 -4
  47. data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +4 -4
  48. data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +3 -3
  49. data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +3 -3
  50. data/spec/graphql/static_validation/validator_spec.rb +1 -1
  51. data/spec/support/dairy_app.rb +8 -0
  52. metadata +30 -2
@@ -146,9 +146,12 @@ rule
146
146
  name { return [val[0].to_s]}
147
147
  | name_list name { val[0] << val[1].to_s }
148
148
 
149
- enum_name_list:
150
- enum_name { return [val[0].to_s]}
151
- | enum_name_list enum_name { return val[0] << val[1].to_s }
149
+ enum_value_definition:
150
+ enum_name directives_list_opt { return make_node(:EnumValueDefinition, name: val[0], directives: val[1]) }
151
+
152
+ enum_value_definitions:
153
+ enum_value_definition { return [val[0]] }
154
+ | enum_value_definitions enum_value_definition { return val[0] << val[1] }
152
155
 
153
156
  arguments_opt:
154
157
  /* none */ { return [] }
@@ -194,7 +197,7 @@ rule
194
197
  object_value_field:
195
198
  name COLON input_value { return make_node(:Argument, name: val[0], value: val[2], position_source: val[0])}
196
199
 
197
- enum_value: enum_name { return make_node(:Enum, name: val[0], position_source: val[0])}
200
+ enum_value: enum_name { return make_node(:Enum, name: val[0], position_source: val[0]) }
198
201
 
199
202
  directives_list_opt:
200
203
  /* none */ { return [] }
@@ -265,11 +268,11 @@ rule
265
268
  | enum_type_definition
266
269
  | input_object_type_definition
267
270
 
268
- scalar_type_definition: SCALAR name { return make_node(:ScalarTypeDefinition, name: val[1]) }
271
+ scalar_type_definition: SCALAR name directives_list_opt { return make_node(:ScalarTypeDefinition, name: val[1], directives: val[2]) }
269
272
 
270
273
  object_type_definition:
271
- TYPE name implements_opt RCURLY field_definition_list LCURLY {
272
- return make_node(:ObjectTypeDefinition, name: val[1], interfaces: val[2], fields: val[4])
274
+ TYPE name implements_opt directives_list_opt RCURLY field_definition_list LCURLY {
275
+ return make_node(:ObjectTypeDefinition, name: val[1], interfaces: val[2], directives: val[3], fields: val[5])
273
276
  }
274
277
 
275
278
  implements_opt:
@@ -277,8 +280,8 @@ rule
277
280
  | IMPLEMENTS name_list { return val[1] }
278
281
 
279
282
  input_value_definition:
280
- name COLON type default_value_opt {
281
- return make_node(:InputValueDefinition, name: val[0], type: val[2], default_value: val[3])
283
+ name COLON type default_value_opt directives_list_opt {
284
+ return make_node(:InputValueDefinition, name: val[0], type: val[2], default_value: val[3], directives: val[4])
282
285
  }
283
286
 
284
287
  input_value_definition_list:
@@ -290,8 +293,8 @@ rule
290
293
  | RPAREN input_value_definition_list LPAREN { return val[1] }
291
294
 
292
295
  field_definition:
293
- name arguments_definitions_opt COLON type {
294
- return make_node(:FieldDefinition, name: val[0], arguments: val[1], type: val[3])
296
+ name arguments_definitions_opt COLON type directives_list_opt {
297
+ return make_node(:FieldDefinition, name: val[0], arguments: val[1], type: val[3], directives: val[4])
295
298
  }
296
299
 
297
300
  field_definition_list:
@@ -299,8 +302,8 @@ rule
299
302
  | field_definition_list field_definition { val[0] << val[1] }
300
303
 
301
304
  interface_type_definition:
302
- INTERFACE name RCURLY field_definition_list LCURLY {
303
- return make_node(:InterfaceTypeDefinition, name: val[1], fields: val[3])
305
+ INTERFACE name directives_list_opt RCURLY field_definition_list LCURLY {
306
+ return make_node(:InterfaceTypeDefinition, name: val[1], directives: val[2], fields: val[4])
304
307
  }
305
308
 
306
309
  union_members:
@@ -308,18 +311,18 @@ rule
308
311
  | union_members PIPE name { val[0] << val[2].to_s }
309
312
 
310
313
  union_type_definition:
311
- UNION name EQUALS union_members {
312
- return make_node(:UnionTypeDefinition, name: val[1], types: val[3])
314
+ UNION name directives_list_opt EQUALS union_members {
315
+ return make_node(:UnionTypeDefinition, name: val[1], directives: val[2], types: val[4])
313
316
  }
314
317
 
315
318
  enum_type_definition:
316
- ENUM name RCURLY enum_name_list LCURLY {
317
- return make_node(:EnumTypeDefinition, name: val[1], values: val[3])
319
+ ENUM name directives_list_opt RCURLY enum_value_definitions LCURLY {
320
+ return make_node(:EnumTypeDefinition, name: val[1], directives: val[2], values: val[4])
318
321
  }
319
322
 
320
323
  input_object_type_definition:
321
- INPUT name RCURLY input_value_definition_list LCURLY {
322
- return make_node(:InputObjectTypeDefinition, name: val[1], fields: val[3])
324
+ INPUT name directives_list_opt RCURLY input_value_definition_list LCURLY {
325
+ return make_node(:InputObjectTypeDefinition, name: val[1], directives: val[2], fields: val[4])
323
326
  }
324
327
  end
325
328
 
@@ -279,6 +279,7 @@ module GraphQL
279
279
  it "parses the test schema" do
280
280
  schema = DummySchema
281
281
  schema_string = GraphQL::Schema::Printer.print_schema(schema)
282
+
282
283
  document = subject.parse(schema_string)
283
284
 
284
285
  assert_equal schema_string, document.to_query_string
@@ -324,6 +325,28 @@ module GraphQL
324
325
  assert_equal 'ID', type.fields[0].type.of_type.name
325
326
  end
326
327
 
328
+ it "parses object types with directives" do
329
+ document = subject.parse('
330
+ type Comment implements Node @deprecated(reason: "No longer supported") {
331
+ id: ID!
332
+ }
333
+ ')
334
+
335
+ type = document.definitions.first
336
+ assert_equal GraphQL::Language::Nodes::ObjectTypeDefinition, type.class
337
+ assert_equal 'Comment', type.name
338
+ assert_equal ['Node'], type.interfaces
339
+ assert_equal ['id'], type.fields.map(&:name)
340
+ assert_equal [], type.fields[0].arguments
341
+ assert_equal 'ID', type.fields[0].type.of_type.name
342
+ assert_equal 1, type.directives.length
343
+
344
+ deprecated_directive = type.directives[0]
345
+ assert_equal 'deprecated', deprecated_directive.name
346
+ assert_equal 'reason', deprecated_directive.arguments[0].name
347
+ assert_equal 'No longer supported', deprecated_directive.arguments[0].value
348
+ end
349
+
327
350
  it "parses field arguments" do
328
351
  document = subject.parse('
329
352
  type Mutation {
@@ -340,6 +363,23 @@ module GraphQL
340
363
  assert_equal ['Test', 'Annoying'], tags_arg.value
341
364
  end
342
365
 
366
+ it "parses field arguments with directives" do
367
+ document = subject.parse('
368
+ type Mutation {
369
+ post(id: ID! @deprecated(reason: "No longer supported"), data: String): Post
370
+ }
371
+ ')
372
+
373
+ field = document.definitions.first.fields.first
374
+ assert_equal ['id', 'data'], field.arguments.map(&:name)
375
+ id_arg = field.arguments[0]
376
+
377
+ deprecated_directive = id_arg.directives[0]
378
+ assert_equal 'deprecated', deprecated_directive.name
379
+ assert_equal 'reason', deprecated_directive.arguments[0].name
380
+ assert_equal 'No longer supported', deprecated_directive.arguments[0].value
381
+ end
382
+
343
383
  it "parses scalar types" do
344
384
  document = subject.parse('scalar DateTime')
345
385
 
@@ -348,6 +388,20 @@ module GraphQL
348
388
  assert_equal 'DateTime', type.name
349
389
  end
350
390
 
391
+ it "parses scalar types with directives" do
392
+ document = subject.parse('scalar DateTime @deprecated(reason: "No longer supported")')
393
+
394
+ type = document.definitions.first
395
+ assert_equal GraphQL::Language::Nodes::ScalarTypeDefinition, type.class
396
+ assert_equal 'DateTime', type.name
397
+ assert_equal 1, type.directives.length
398
+
399
+ deprecated_directive = type.directives[0]
400
+ assert_equal 'deprecated', deprecated_directive.name
401
+ assert_equal 'reason', deprecated_directive.arguments[0].name
402
+ assert_equal 'No longer supported', deprecated_directive.arguments[0].value
403
+ end
404
+
351
405
  it "parses interface types" do
352
406
  document = subject.parse('
353
407
  interface Node {
@@ -363,15 +417,68 @@ module GraphQL
363
417
  assert_equal 'ID', type.fields[0].type.of_type.name
364
418
  end
365
419
 
420
+ it "parses interface types with directives" do
421
+ document = subject.parse('
422
+ interface Node @deprecated(reason: "No longer supported") {
423
+ id: ID!
424
+ }
425
+ ')
426
+
427
+ type = document.definitions.first
428
+ assert_equal GraphQL::Language::Nodes::InterfaceTypeDefinition, type.class
429
+ assert_equal 'Node', type.name
430
+ assert_equal 1, type.directives.length
431
+
432
+ deprecated_directive = type.directives[0]
433
+ assert_equal 'deprecated', deprecated_directive.name
434
+ assert_equal 'reason', deprecated_directive.arguments[0].name
435
+ assert_equal 'No longer supported', deprecated_directive.arguments[0].value
436
+ end
437
+
366
438
  it "parses enum types" do
367
439
  document = subject.parse('
368
- enum DogCommand { SIT, DOWN, HEEL }
440
+ enum DogCommand {
441
+ SIT
442
+ DOWN @deprecated(reason: "No longer supported")
443
+ HEEL
444
+ }
445
+ ')
446
+
447
+ type = document.definitions.first
448
+ assert_equal GraphQL::Language::Nodes::EnumTypeDefinition, type.class
449
+ assert_equal 'DogCommand', type.name
450
+ assert_equal 3, type.values.length
451
+
452
+ assert_equal 'SIT', type.values[0].name
453
+ assert_equal [], type.values[0].directives
454
+
455
+ assert_equal 'DOWN', type.values[1].name
456
+ assert_equal 1, type.values[1].directives.length
457
+ deprecated_directive = type.values[1].directives[0]
458
+ assert_equal 'deprecated', deprecated_directive.name
459
+ assert_equal 'reason', deprecated_directive.arguments[0].name
460
+ assert_equal 'No longer supported', deprecated_directive.arguments[0].value
461
+
462
+ assert_equal 'HEEL', type.values[2].name
463
+ assert_equal [], type.values[2].directives
464
+ end
465
+
466
+ it "parses enum types with directives" do
467
+ document = subject.parse('
468
+ enum DogCommand @deprecated(reason: "No longer supported") {
469
+ SIT
470
+ }
369
471
  ')
370
472
 
371
473
  type = document.definitions.first
372
474
  assert_equal GraphQL::Language::Nodes::EnumTypeDefinition, type.class
373
475
  assert_equal 'DogCommand', type.name
374
- assert_equal ['SIT', 'DOWN', 'HEEL'], type.values
476
+ assert_equal 1, type.directives.length
477
+
478
+ deprecated_directive = type.directives[0]
479
+ assert_equal 'deprecated', deprecated_directive.name
480
+ assert_equal 'reason', deprecated_directive.arguments[0].name
481
+ assert_equal 'No longer supported', deprecated_directive.arguments[0].value
375
482
  end
376
483
 
377
484
  it "parses input object types" do
@@ -388,6 +495,28 @@ module GraphQL
388
495
  assert_equal 'String', type.fields[0].type.name
389
496
  assert_equal nil, type.fields[0].default_value
390
497
  end
498
+
499
+ it "parses input object types with directives" do
500
+ document = subject.parse('
501
+ input EmptyMutationInput @deprecated(reason: "No longer supported") {
502
+ clientMutationId: String
503
+ }
504
+ ')
505
+
506
+ type = document.definitions.first
507
+ assert_equal GraphQL::Language::Nodes::InputObjectTypeDefinition, type.class
508
+ assert_equal 'EmptyMutationInput', type.name
509
+ assert_equal ['clientMutationId'], type.fields.map(&:name)
510
+ assert_equal 'String', type.fields[0].type.name
511
+ assert_equal nil, type.fields[0].default_value
512
+ assert_equal 1, type.directives.length
513
+
514
+ deprecated_directive = type.directives[0]
515
+ assert_equal 'deprecated', deprecated_directive.name
516
+ assert_equal 'reason', deprecated_directive.arguments[0].name
517
+ assert_equal 'No longer supported', deprecated_directive.arguments[0].value
518
+
519
+ end
391
520
  end
392
521
  end
393
522
 
@@ -35,6 +35,7 @@ module GraphQL
35
35
  def get_finished_value(raw_value)
36
36
  if raw_value.is_a?(GraphQL::ExecutionError)
37
37
  raw_value.ast_node = irep_node.ast_node
38
+ raw_value.path = irep_node.path
38
39
  execution_context.add_error(raw_value)
39
40
  end
40
41
 
@@ -13,7 +13,7 @@ module GraphQL
13
13
 
14
14
  def result
15
15
  irep_node.children.each_with_object({}) do |(name, irep_node), memo|
16
- if GraphQL::Execution::DirectiveChecks.include?(irep_node, execution_context.query) && applies_to_type?(irep_node, type)
16
+ if irep_node.included? && applies_to_type?(irep_node, type)
17
17
  field_result = execution_context.strategy.field_resolution.new(
18
18
  irep_node,
19
19
  type,
@@ -45,10 +45,13 @@ module GraphQL
45
45
  def non_null_result
46
46
  wrapped_type = field_type.of_type
47
47
  strategy_class = get_strategy_for_kind(wrapped_type.kind)
48
- value.map do |item|
48
+ result = value.each_with_index.map do |item, index|
49
+ irep_node.index = index
49
50
  inner_strategy = strategy_class.new(item, wrapped_type, target, parent_type, irep_node, execution_context)
50
51
  inner_strategy.result
51
52
  end
53
+ irep_node.index = nil
54
+ result
52
55
  end
53
56
  end
54
57
 
@@ -94,7 +94,7 @@ module GraphQL
94
94
  field_type = type.input_fields.fetch(field_name.to_s).type
95
95
  "#{field_name}: #{print_value(field_value, field_type)}"
96
96
  }.join(", ")
97
- "{ #{fields} }"
97
+ "{#{fields}}"
98
98
  when NonNullType
99
99
  print_value(value, type.of_type)
100
100
  when ListType
@@ -26,7 +26,7 @@ module GraphQL
26
26
  {
27
27
  "message" => message,
28
28
  "locations" => locations,
29
- "path" => path,
29
+ "fields" => path,
30
30
  }
31
31
  end
32
32
 
@@ -1,3 +1,3 @@
1
1
  module GraphQL
2
- VERSION = "0.18.14"
2
+ VERSION = "0.18.15"
3
3
  end
data/readme.md CHANGED
@@ -1,4 +1,4 @@
1
- # graphql <img src="https://cloud.githubusercontent.com/assets/2231765/9094460/cb43861e-3b66-11e5-9fbf-71066ff3ab13.png" height=40 alt="graphql-ruby"/>
1
+ # graphql <img src="https://cloud.githubusercontent.com/assets/2231765/9094460/cb43861e-3b66-11e5-9fbf-71066ff3ab13.png" height="40" alt="graphql-ruby"/>
2
2
 
3
3
  [![Build Status](https://travis-ci.org/rmosolgo/graphql-ruby.svg?branch=master)](https://travis-ci.org/rmosolgo/graphql-ruby)
4
4
  [![Gem Version](https://badge.fury.io/rb/graphql.svg)](https://rubygems.org/gems/graphql)
@@ -8,16 +8,7 @@
8
8
 
9
9
  A Ruby implementation of [GraphQL](http://graphql.org/).
10
10
 
11
- - Guides
12
- - [Introduction](http://www.rubydoc.info/github/rmosolgo/graphql-ruby/file/guides/introduction.md)
13
- - [Defining Your Schema](http://www.rubydoc.info/github/rmosolgo/graphql-ruby/file/guides/defining_your_schema.md)
14
- - [Executing Queries](http://www.rubydoc.info/github/rmosolgo/graphql-ruby/file/guides/executing_queries.md)
15
- - [Testing](http://www.rubydoc.info/github/rmosolgo/graphql-ruby/file/guides/testing.md)
16
- - [Code Reuse](http://www.rubydoc.info/github/rmosolgo/graphql-ruby/file/guides/code_reuse.md)
17
- - [Security](http://www.rubydoc.info/github/rmosolgo/graphql-ruby/file/guides/security.md)
18
- - [Relay](http://www.rubydoc.info/github/rmosolgo/graphql-ruby/file/guides/relay.md)
19
-
20
-
11
+ - [Website](https://rmosolgo.github.io/graphql-ruby)
21
12
  - [API Documentation](http://www.rubydoc.info/github/rmosolgo/graphql-ruby)
22
13
 
23
14
  ## Installation
@@ -103,6 +94,7 @@ If you're building a backend for [Relay](http://facebook.github.io/relay/), you'
103
94
  - __Report bugs__ by posting a description, full stack trace, and all relevant code in a [GitHub issue](https://github.com/rmosolgo/graphql-ruby/issues).
104
95
  - __Features & patches__ are welcome! Consider discussing it in an [issue](https://github.com/rmosolgo/graphql-ruby/issues) or in the [#ruby channel on Slack](https://graphql-slack.herokuapp.com/) to make sure we're on the same page.
105
96
  - __Run the tests__ with `rake test` or start up guard with `bundle exec guard`.
97
+ - __Build the site__ with `rake site:serve`, then visit `localhost:4000`.
106
98
 
107
99
  ## Related Projects
108
100
 
@@ -110,7 +102,7 @@ If you're building a backend for [Relay](http://facebook.github.io/relay/), you'
110
102
 
111
103
  - `graphql-ruby` + Rails demo ([src](https://github.com/rmosolgo/graphql-ruby-demo) / [heroku](http://graphql-ruby-demo.herokuapp.com))
112
104
  - [`graphql-batch`](https://github.com/shopify/graphql-batch), a batched query execution strategy
113
- - [`graphql-libgraphqlparser`](https://github.com/rmosolgo/graphql-libgraphqlparser), bindings to [libgraphqlparser](https://github.com/graphql/libgraphqlparser), a C-level parser.
105
+ - [`graphql-libgraphqlparser`](https://github.com/rmosolgo/graphql-libgraphqlparser-ruby), bindings to [libgraphqlparser](https://github.com/graphql/libgraphqlparser), a C-level parser.
114
106
 
115
107
  ### Blog Posts
116
108
 
@@ -150,3 +142,9 @@ If you're building a backend for [Relay](http://facebook.github.io/relay/), you'
150
142
  - Renaming fragments from local names to unique names
151
143
  - Support AST subclasses? This would be hard, I think classes are used as hash keys in many places.
152
144
  - Support object deep-copy (schema, type, field, argument)? To support multiple schemas based on the same types.
145
+ - Improve the website
146
+ - Feature the logo in the header
147
+ - Split `readme.md` into `index.md` (a homepage with code samples) and a technical readme (how to install, link to homepage)
148
+ - Move "Related projects" to a guide
149
+ - Revisit guides, maybe split them into smaller, more specific pages
150
+ - Put guide titles into the `<title />`
@@ -1,7 +1,8 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe GraphQL::Directive do
4
- let(:result) { DummySchema.execute(query_string, variables: {"t" => true, "f" => false}) }
4
+ let(:variables) { {"t" => true, "f" => false} }
5
+ let(:result) { DummySchema.execute(query_string, variables: variables) }
5
6
  describe "on fields" do
6
7
  let(:query_string) { %|query directives($t: Boolean!, $f: Boolean!) {
7
8
  cheese(id: 1) {
@@ -74,4 +75,141 @@ describe GraphQL::Directive do
74
75
  assert_equal(expected, result)
75
76
  end
76
77
  end
78
+ describe "merging @skip and @include" do
79
+ let(:field_included?) { r = result["data"]["cheese"]; r.has_key?('flavor') && r.has_key?('withVariables') }
80
+ let(:skip?) { false }
81
+ let(:include?) { true }
82
+ let(:variables) { {"skip" => skip?, "include" => include?} }
83
+ let(:query_string) {"
84
+ query getCheese ($include: Boolean!, $skip: Boolean!) {
85
+ cheese(id: 1) {
86
+ flavor @include(if: #{include?}) @skip(if: #{skip?}),
87
+ withVariables: flavor @include(if: $include) @skip(if: $skip)
88
+ }
89
+ }
90
+ "}
91
+ # behavior as defined in
92
+ # https://github.com/facebook/graphql/blob/master/spec/Section%203%20--%20Type%20System.md#include
93
+ describe "when @skip=false and @include=true" do
94
+ let(:skip?) { false }
95
+ let(:include?) { true }
96
+ it "is included" do assert field_included? end
97
+ end
98
+ describe "when @skip=false and @include=false" do
99
+ let(:skip?) { false }
100
+ let(:include?) { false }
101
+ it "is not included" do assert !field_included? end
102
+ end
103
+ describe "when @skip=true and @include=true" do
104
+ let(:skip?) { true }
105
+ let(:include?) { true }
106
+ it "is not included" do assert !field_included? end
107
+ end
108
+ describe "when @skip=true and @include=false" do
109
+ let(:skip?) { true }
110
+ let(:include?) { false }
111
+ it "is not included" do assert !field_included? end
112
+ end
113
+ describe "when evaluating skip on query selection and fragment" do
114
+ describe "with @skip" do
115
+ let(:query_string) {"
116
+ query getCheese ($skip: Boolean!) {
117
+ cheese(id: 1) {
118
+ flavor,
119
+ withVariables: flavor,
120
+ ...F0
121
+ }
122
+ }
123
+ fragment F0 on Cheese {
124
+ flavor @skip(if: #{skip?})
125
+ withVariables: flavor @skip(if: $skip)
126
+ }
127
+ "}
128
+ describe "and @skip=false" do
129
+ let(:skip?) { false }
130
+ it "is included" do assert field_included? end
131
+ end
132
+ describe "and @skip=true" do
133
+ let(:skip?) { true }
134
+ it "is included" do assert field_included? end
135
+ end
136
+ end
137
+ end
138
+ describe "when evaluating conflicting @skip and @include on query selection and fragment" do
139
+ let(:query_string) {"
140
+ query getCheese ($include: Boolean!, $skip: Boolean!) {
141
+ cheese(id: 1) {
142
+ ... on Cheese @include(if: #{include?}) {
143
+ flavor
144
+ }
145
+ withVariables: flavor @include(if: $include),
146
+ ...F0
147
+ }
148
+ }
149
+ fragment F0 on Cheese {
150
+ flavor @skip(if: #{skip?}),
151
+ withVariables: flavor @skip(if: $skip)
152
+ }
153
+ "}
154
+ describe "when @skip=false and @include=true" do
155
+ let(:skip?) { false }
156
+ let(:include?) { true }
157
+ it "is included" do assert field_included? end
158
+ end
159
+ describe "when @skip=false and @include=false" do
160
+ let(:skip?) { false }
161
+ let(:include?) { false }
162
+ it "is included" do assert field_included? end
163
+ end
164
+ describe "when @skip=true and @include=true" do
165
+ let(:skip?) { true }
166
+ let(:include?) { true }
167
+ it "is included" do assert field_included? end
168
+ end
169
+ describe "when @skip=true and @include=false" do
170
+ let(:skip?) { true }
171
+ let(:include?) { false }
172
+ it "is not included" do
173
+ assert !field_included?
174
+ end
175
+ end
176
+ end
177
+
178
+ describe "when handling multiple fields at the same level" do
179
+ describe "when at least one occurrence would be included" do
180
+ let(:query_string) {"
181
+ query getCheese ($include: Boolean!, $skip: Boolean!) {
182
+ cheese(id: 1) {
183
+ ... on Cheese {
184
+ flavor
185
+ }
186
+ flavor @include(if: #{include?}),
187
+ flavor @skip(if: #{skip?}),
188
+ withVariables: flavor,
189
+ withVariables: flavor @include(if: $include),
190
+ withVariables: flavor @skip(if: $skip)
191
+ }
192
+ }
193
+ "}
194
+ let(:skip?) { true }
195
+ let(:include?) { false }
196
+ it "is included" do assert field_included? end
197
+ end
198
+ describe "when no occurrence would be included" do
199
+ let(:query_string) {"
200
+ query getCheese ($include: Boolean!, $skip: Boolean!) {
201
+ cheese(id: 1) {
202
+ flavor @include(if: #{include?}),
203
+ flavor @skip(if: #{skip?}),
204
+ withVariables: flavor @include(if: $include),
205
+ withVariables: flavor @skip(if: $skip)
206
+ }
207
+ }
208
+ "}
209
+ let(:skip?) { true }
210
+ let(:include?) { false }
211
+ it "is not included" do assert !field_included? end
212
+ end
213
+ end
214
+ end
77
215
  end