graphql 0.18.14 → 0.18.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/graphql/analysis/query_complexity.rb +15 -6
- data/lib/graphql/analysis/query_depth.rb +11 -10
- data/lib/graphql/directive.rb +2 -6
- data/lib/graphql/directive/include_directive.rb +0 -4
- data/lib/graphql/directive/skip_directive.rb +0 -4
- data/lib/graphql/execution/directive_checks.rb +22 -13
- data/lib/graphql/execution_error.rb +7 -0
- data/lib/graphql/internal_representation/node.rb +20 -2
- data/lib/graphql/internal_representation/rewrite.rb +66 -20
- data/lib/graphql/language/generation.rb +22 -8
- data/lib/graphql/language/nodes.rb +48 -20
- data/lib/graphql/language/parser.rb +436 -423
- data/lib/graphql/language/parser.y +22 -19
- data/lib/graphql/language/parser_tests.rb +131 -2
- data/lib/graphql/query/serial_execution/field_resolution.rb +1 -0
- data/lib/graphql/query/serial_execution/selection_resolution.rb +1 -1
- data/lib/graphql/query/serial_execution/value_resolution.rb +4 -1
- data/lib/graphql/schema/printer.rb +1 -1
- data/lib/graphql/static_validation/message.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/readme.md +10 -12
- data/spec/graphql/directive_spec.rb +139 -1
- data/spec/graphql/execution_error_spec.rb +63 -3
- data/spec/graphql/introspection/type_type_spec.rb +2 -0
- data/spec/graphql/language/generation_spec.rb +55 -7
- data/spec/graphql/query/executor_spec.rb +4 -2
- data/spec/graphql/schema/catchall_middleware_spec.rb +1 -0
- data/spec/graphql/schema/printer_spec.rb +1 -1
- data/spec/graphql/schema/timeout_middleware_spec.rb +10 -5
- data/spec/graphql/static_validation/rules/argument_literals_are_compatible_spec.rb +6 -6
- data/spec/graphql/static_validation/rules/arguments_are_defined_spec.rb +4 -4
- data/spec/graphql/static_validation/rules/directives_are_defined_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/directives_are_in_valid_locations_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fields_are_defined_on_type_spec.rb +3 -3
- data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fragment_spreads_are_possible_spec.rb +3 -3
- data/spec/graphql/static_validation/rules/fragment_types_exist_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fragments_are_finite_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/fragments_are_named_spec.rb +1 -1
- data/spec/graphql/static_validation/rules/fragments_are_on_composite_types_spec.rb +3 -3
- data/spec/graphql/static_validation/rules/fragments_are_used_spec.rb +2 -2
- data/spec/graphql/static_validation/rules/mutation_root_exists_spec.rb +1 -1
- data/spec/graphql/static_validation/rules/required_arguments_are_present_spec.rb +3 -3
- data/spec/graphql/static_validation/rules/subscription_root_exists_spec.rb +1 -1
- data/spec/graphql/static_validation/rules/variable_default_values_are_correctly_typed_spec.rb +4 -4
- data/spec/graphql/static_validation/rules/variable_usages_are_allowed_spec.rb +4 -4
- data/spec/graphql/static_validation/rules/variables_are_input_types_spec.rb +3 -3
- data/spec/graphql/static_validation/rules/variables_are_used_and_defined_spec.rb +3 -3
- data/spec/graphql/static_validation/validator_spec.rb +1 -1
- data/spec/support/dairy_app.rb +8 -0
- 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
|
-
|
150
|
-
|
151
|
-
|
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[
|
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[
|
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[
|
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
|
317
|
-
return make_node(:EnumTypeDefinition, name: val[1], values: val[
|
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[
|
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 {
|
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
|
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
|
|
@@ -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
|
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
|
-
"{
|
97
|
+
"{#{fields}}"
|
98
98
|
when NonNullType
|
99
99
|
print_value(value, type.of_type)
|
100
100
|
when ListType
|
data/lib/graphql/version.rb
CHANGED
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
|
-
-
|
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(:
|
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
|