graphql 1.8.0.pre10 → 1.8.0.pre11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +5 -5
  2. data/lib/generators/graphql/install_generator.rb +14 -8
  3. data/lib/graphql.rb +1 -24
  4. data/lib/graphql/backtrace.rb +1 -1
  5. data/lib/graphql/deprecated_dsl.rb +2 -2
  6. data/lib/graphql/execution/execute.rb +6 -0
  7. data/lib/graphql/execution/lazy/lazy_method_map.rb +1 -1
  8. data/lib/graphql/introspection/base_object.rb +1 -0
  9. data/lib/graphql/language/document_from_schema_definition.rb +4 -1
  10. data/lib/graphql/language/nodes.rb +5 -2
  11. data/lib/graphql/language/parser.rb +288 -288
  12. data/lib/graphql/language/parser.y +1 -1
  13. data/lib/graphql/language/printer.rb +12 -2
  14. data/lib/graphql/non_null_type.rb +1 -1
  15. data/lib/graphql/query.rb +1 -1
  16. data/lib/graphql/query/arguments.rb +1 -1
  17. data/lib/graphql/query/context.rb +2 -2
  18. data/lib/graphql/query/null_context.rb +1 -1
  19. data/lib/graphql/query/result.rb +1 -1
  20. data/lib/graphql/query/variables.rb +21 -3
  21. data/lib/graphql/relay.rb +1 -0
  22. data/lib/graphql/relay/mongo_relation_connection.rb +40 -0
  23. data/lib/graphql/scalar_type.rb +14 -2
  24. data/lib/graphql/schema.rb +17 -1
  25. data/lib/graphql/schema/argument.rb +39 -7
  26. data/lib/graphql/schema/enum.rb +7 -0
  27. data/lib/graphql/schema/field.rb +145 -39
  28. data/lib/graphql/schema/finder.rb +4 -4
  29. data/lib/graphql/schema/input_object.rb +13 -2
  30. data/lib/graphql/schema/interface.rb +50 -16
  31. data/lib/graphql/schema/list.rb +28 -0
  32. data/lib/graphql/schema/member.rb +8 -106
  33. data/lib/graphql/schema/member/accepts_definition.rb +58 -24
  34. data/lib/graphql/schema/member/base_dsl_methods.rb +96 -0
  35. data/lib/graphql/schema/member/build_type.rb +15 -9
  36. data/lib/graphql/schema/member/cached_graphql_definition.rb +26 -0
  37. data/lib/graphql/schema/member/graphql_type_names.rb +21 -0
  38. data/lib/graphql/schema/member/has_arguments.rb +1 -1
  39. data/lib/graphql/schema/member/has_fields.rb +91 -8
  40. data/lib/graphql/schema/member/type_system_helpers.rb +34 -0
  41. data/lib/graphql/schema/middleware_chain.rb +5 -1
  42. data/lib/graphql/schema/mutation.rb +24 -12
  43. data/lib/graphql/schema/non_null.rb +34 -0
  44. data/lib/graphql/schema/object.rb +24 -11
  45. data/lib/graphql/schema/relay_classic_mutation.rb +14 -11
  46. data/lib/graphql/schema/rescue_middleware.rb +8 -7
  47. data/lib/graphql/schema/scalar.rb +9 -2
  48. data/lib/graphql/schema/union.rb +4 -0
  49. data/lib/graphql/static_validation/definition_dependencies.rb +1 -1
  50. data/lib/graphql/static_validation/literal_validator.rb +16 -4
  51. data/lib/graphql/static_validation/validation_context.rb +1 -1
  52. data/lib/graphql/subscriptions.rb +90 -16
  53. data/lib/graphql/upgrader/member.rb +27 -89
  54. data/lib/graphql/version.rb +1 -1
  55. data/spec/dummy/app/channels/graphql_channel.rb +1 -1
  56. data/spec/dummy/log/test.log +206 -0
  57. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/-x/-xYZjAnuuzgR79fcznLTQtSdh6AARxu8FcQ_J6p7L3U.cache +0 -0
  58. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/13/13HiV12xyoQvT-1L39ZzLwMZxjyaGMiENmfw7f-QTIc.cache +0 -0
  59. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/3W/3Wtf5pCWdqq0AB-iB0Y9uUNrTkruRxIEf1XFn_BETU0.cache +1 -0
  60. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/5i/5iguGafb4hOn8262Kn8Q37ogNN9MxxQKGKNzHAzUcvI.cache +1 -0
  61. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/8m/8mj2T6yy847Mc2Z7k3Xzh8O91hhVJt3NrPe8ASNDlIA.cache +1 -0
  62. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/DT/DTQyMpr4ABZYQetsdRJ5A7S4jf1r3ie4FGOR7GZBNSs.cache +3 -0
  63. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Dq/DqJ5_yJPrP5iLlOQyTQsjAVI5FE5LCVDkED0f7GgsSo.cache +3 -0
  64. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/F8/F8MUNRzORGFgr329fNM0xLaoWCXdv3BIalT7dsvLfjs.cache +0 -0
  65. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/KB/KB07ZaKNC5uXJ7TjLi-WqnY6g7dq8wWp_8N3HNjBNxg.cache +0 -0
  66. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Rw/RwDuCV-XpnCtjNkvhpJfBuxXMk0b5AD3L9eR6M-wcy0.cache +3 -0
  67. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/UL/ULdjhhb0bRuqmaG7XSZlFYzGYCXTDnqZuJBTWRlzqgw.cache +0 -0
  68. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Up/UpPNgh0yYoUsyMDh5zWqe_U6qJIyTC6-dxMMAs1vvlM.cache +1 -0
  69. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Wg/Wguh-szFGTI1gaL6npYwPekMXflugRei7F_mOyRucXg.cache +0 -0
  70. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/X-/X-khLYMA9mqFRPg3zAi86mREDxpKl4bdKYp3uF6WHos.cache +0 -0
  71. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/bi/BIkdhfxsezxM4q-HZ4oCNTq97WEJTigcq0tpX2cDvbY.cache +0 -0
  72. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/ff/FfxmA4CMHQZT7exx0G7NS1Wpcnny0vzp-Jhc2H36bp8.cache +1 -0
  73. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/gE/gEiiG4GZNy_djEjK2pHm_NgA-gyhLZhdQvo0Yt96GqE.cache +0 -0
  74. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/gn/gnA9ZSqpjccNL2m8pe_jBvY6SinXlCzXDWyop83Od8s.cache +1 -0
  75. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/lO/lOAan3cMwCE_Hli6gsDML88xFNfn0nxPmvrSkW7eEOw.cache +1 -0
  76. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/m1/M1pv8MJEPLXGLvS8QxVh3DSO9cI4mRt5FHFWdrvUj6o.cache +2 -0
  77. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/m7/m77qH7ZqH0_0SmwJbiKGDd-aLau1Dav847DC6ge46zY.cache +1 -0
  78. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/sj/sjRjnjRB37lH2vrgtkdJ8Cz84__IJ978IuKTM7HcztI.cache +0 -0
  79. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/um/um1JrirR4hJhK-1rE-HywlyCi5ibgxHVrReiujZBWJM.cache +1 -0
  80. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/v4/v4fwVytD7ITcE0_GDbslZEYud8a5Okm85fV1o7SDl6g.cache +0 -0
  81. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/v_/v_0PAQt0iipQjFP5zjgkkk9Stnpf4VzvnMv67d1Keuw.cache +1 -0
  82. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/wd/wdT9U4MKxe1PyqNjVuCKMpCl3dxGCIRJIlwUTfh2DQU.cache +1 -0
  83. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/xI/xIaxut_fEIhKBDqljTNwYaADK9kj3gG0ESrfHs-5_og.cache +3 -0
  84. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/y0/y0SJOqIx2fn1SKqOkAihsQow0trRJrSIyAswufVuoA8.cache +0 -0
  85. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/zg/zgpzeaX-KZErHyGJ1aBH3ZusweNXMneVZule88XsIJI.cache +1 -0
  86. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/zy/zYFltDy-8VC-uKq2BVEiJJyYXNFvVzAKuMlR3ZIYZsk.cache +0 -0
  87. data/spec/dummy/tmp/screenshots/failures_test_it_handles_subscriptions.png +0 -0
  88. data/spec/fixtures/upgrader/photo.original.rb +10 -0
  89. data/spec/fixtures/upgrader/photo.transformed.rb +12 -0
  90. data/spec/fixtures/upgrader/starrable.original.rb +4 -1
  91. data/spec/fixtures/upgrader/starrable.transformed.rb +25 -22
  92. data/spec/fixtures/upgrader/subscribable.transformed.rb +32 -33
  93. data/spec/graphql/execution_error_spec.rb +18 -0
  94. data/spec/graphql/introspection/schema_type_spec.rb +1 -0
  95. data/spec/graphql/object_type_spec.rb +2 -1
  96. data/spec/graphql/query/variables_spec.rb +41 -0
  97. data/spec/graphql/relay/mongo_relation_connection_spec.rb +474 -0
  98. data/spec/graphql/schema/argument_spec.rb +65 -9
  99. data/spec/graphql/schema/build_from_definition_spec.rb +4 -2
  100. data/spec/graphql/schema/enum_spec.rb +1 -1
  101. data/spec/graphql/schema/field_spec.rb +79 -4
  102. data/spec/graphql/schema/input_object_spec.rb +56 -0
  103. data/spec/graphql/schema/instrumentation_spec.rb +4 -3
  104. data/spec/graphql/schema/interface_spec.rb +40 -25
  105. data/spec/graphql/schema/member/accepts_definition_spec.rb +38 -11
  106. data/spec/graphql/schema/member/has_fields_spec.rb +129 -0
  107. data/spec/graphql/schema/member/type_system_helpers_spec.rb +63 -0
  108. data/spec/graphql/schema/mutation_spec.rb +48 -0
  109. data/spec/graphql/schema/object_spec.rb +34 -8
  110. data/spec/graphql/schema/relay_classic_mutation_spec.rb +10 -0
  111. data/spec/graphql/schema/rescue_middleware_spec.rb +11 -0
  112. data/spec/graphql/schema/scalar_spec.rb +55 -0
  113. data/spec/graphql/subscriptions_spec.rb +31 -4
  114. data/spec/graphql/upgrader/member_spec.rb +14 -6
  115. data/spec/spec_helper.rb +7 -0
  116. data/spec/support/dummy/schema.rb +8 -0
  117. data/spec/support/jazz.rb +89 -19
  118. data/spec/support/star_trek/data.rb +109 -0
  119. data/spec/support/star_trek/schema.rb +388 -0
  120. metadata +80 -7
  121. data/lib/graphql/schema/field/dynamic_resolve.rb +0 -70
  122. data/lib/graphql/schema/field/unwrapped_resolve.rb +0 -20
  123. data/lib/graphql/schema/member/list_type_proxy.rb +0 -25
  124. data/lib/graphql/schema/member/non_null_type_proxy.rb +0 -25
@@ -271,4 +271,22 @@ describe GraphQL::ExecutionError do
271
271
  assert_equal(expected_result, result)
272
272
  end
273
273
  end
274
+
275
+ describe "more than one ExecutionError" do
276
+ let(:query_string) { %|{ multipleErrorsOnNonNullableField} |}
277
+ it "the errors are inserted into the errors key and the data is nil even for a NonNullable field " do
278
+ expected_result = {
279
+ "data"=>nil,
280
+ "errors"=>
281
+ [{"message"=>"This is an error message for some error.",
282
+ "locations"=>[{"line"=>1, "column"=>3}],
283
+ "path"=>["multipleErrorsOnNonNullableField", 0]},
284
+ {"message"=>"This is another error message for a different error.",
285
+ "locations"=>[{"line"=>1, "column"=>3}],
286
+ "path"=>["multipleErrorsOnNonNullableField", 1]}]
287
+ }
288
+ assert_equal(expected_result, result)
289
+ end
290
+ end
291
+
274
292
  end
@@ -35,6 +35,7 @@ describe GraphQL::Introspection::SchemaType do
35
35
  {"name"=>"fromSource"},
36
36
  {"name"=>"maybeNull"},
37
37
  {"name"=>"milk"},
38
+ {"name"=>"multipleErrorsOnNonNullableField"},
38
39
  {"name"=>"root"},
39
40
  {"name"=>"searchDairy"},
40
41
  {"name"=>"tracingScalar"},
@@ -62,7 +62,8 @@ describe GraphQL::ObjectType do
62
62
  end
63
63
 
64
64
  it "doesnt convolute field names that differ with underscore" do
65
- interface = Class.new(GraphQL::Schema::Interface) do
65
+ interface = Module.new do
66
+ include GraphQL::Schema::Interface
66
67
  graphql_name 'TestInterface'
67
68
  description 'Requires an id'
68
69
 
@@ -48,6 +48,47 @@ describe GraphQL::Query::Variables do
48
48
  end
49
49
  end
50
50
 
51
+ describe "symbol keys" do
52
+ let(:query_string) { <<-GRAPHQL
53
+ query testVariables(
54
+ $dairy_product_1: DairyProductInput!
55
+ $dairy_product_2: DairyProductInput!
56
+ ) {
57
+ __typename
58
+ }
59
+ GRAPHQL
60
+ }
61
+
62
+ let(:provided_variables) {
63
+ {
64
+ dairy_product_1: { source: "COW", fatContent: 0.99 },
65
+ "dairy_product_2" => { source: "DONKEY", "fatContent": 0.89 },
66
+ }
67
+ }
68
+
69
+ it "checks for string matches" do
70
+ # These get merged into all the values above
71
+ default_values = {
72
+ "originDairy"=>"Sugar Hollow Dairy",
73
+ "organic"=>false,
74
+ "order_by"=>{"direction"=>"ASC"}
75
+ }
76
+
77
+ expected_input_1 = {
78
+ "source" => 1,
79
+ "fatContent" => 0.99,
80
+ }.merge(default_values)
81
+
82
+ assert_equal(expected_input_1, variables["dairy_product_1"].to_h)
83
+
84
+ expected_input_2 = {
85
+ "source" => :donkey,
86
+ "fatContent" => 0.89,
87
+ }.merge(default_values)
88
+ assert_equal(expected_input_2, variables["dairy_product_2"].to_h)
89
+ end
90
+ end
91
+
51
92
  describe "validating input objects" do
52
93
  let(:query_string) {%|
53
94
  query searchMyDairy (
@@ -0,0 +1,474 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+
4
+ describe GraphQL::Relay::RelationConnection do
5
+ def get_names(result)
6
+ ships = result["data"]["federation"]["bases"]["edges"]
7
+ ships.map { |e| e["node"]["name"] }
8
+ end
9
+
10
+ def get_page_info(result)
11
+ result["data"]["federation"]["bases"]["pageInfo"]
12
+ end
13
+
14
+ def get_first_cursor(result)
15
+ result["data"]["federation"]["bases"]["edges"].first["cursor"]
16
+ end
17
+
18
+ def get_last_cursor(result)
19
+ result["data"]["federation"]["bases"]["edges"].last["cursor"]
20
+ end
21
+
22
+ describe "results" do
23
+ let(:query_string) {%|
24
+ query getShips($first: Int, $after: String, $last: Int, $before: String, $nameIncludes: String){
25
+ federation {
26
+ bases(first: $first, after: $after, last: $last, before: $before, nameIncludes: $nameIncludes) {
27
+ ... basesConnection
28
+ }
29
+ }
30
+ }
31
+
32
+ fragment basesConnection on BasesConnectionWithTotalCount {
33
+ totalCount,
34
+ edges {
35
+ cursor
36
+ node {
37
+ name
38
+ }
39
+ },
40
+ pageInfo {
41
+ hasNextPage
42
+ hasPreviousPage
43
+ startCursor
44
+ endCursor
45
+ }
46
+ }
47
+ |}
48
+
49
+ it 'limits the result' do
50
+ result = star_trek_query(query_string, "first" => 2)
51
+ assert_equal(2, get_names(result).length)
52
+ assert_equal(true, get_page_info(result)["hasNextPage"])
53
+ assert_equal(false, get_page_info(result)["hasPreviousPage"])
54
+ assert_equal("MQ==", get_page_info(result)["startCursor"])
55
+ assert_equal("Mg==", get_page_info(result)["endCursor"])
56
+ assert_equal("MQ==", get_first_cursor(result))
57
+ assert_equal("Mg==", get_last_cursor(result))
58
+
59
+ result = star_trek_query(query_string, "first" => 3)
60
+ assert_equal(3, get_names(result).length)
61
+ assert_equal(false, get_page_info(result)["hasNextPage"])
62
+ assert_equal(false, get_page_info(result)["hasPreviousPage"])
63
+ assert_equal("MQ==", get_page_info(result)["startCursor"])
64
+ assert_equal("Mw==", get_page_info(result)["endCursor"])
65
+ assert_equal("MQ==", get_first_cursor(result))
66
+ assert_equal("Mw==", get_last_cursor(result))
67
+ end
68
+
69
+ it 'provides custom fields on the connection type' do
70
+ result = star_trek_query(query_string, "first" => 2)
71
+ assert_equal(
72
+ StarTrek::Base.where(faction_id: 1).count,
73
+ result["data"]["federation"]["bases"]["totalCount"]
74
+ )
75
+ end
76
+
77
+ it "provides bidirectional_pagination" do
78
+ result = star_trek_query(query_string, "first" => 1)
79
+ last_cursor = get_last_cursor(result)
80
+
81
+ result = star_trek_query(query_string, "first" => 1, "after" => last_cursor)
82
+ assert_equal true, get_page_info(result)["hasNextPage"]
83
+ assert_equal false, get_page_info(result)["hasPreviousPage"]
84
+
85
+ result = with_bidirectional_pagination {
86
+ star_trek_query(query_string, "first" => 1, "after" => last_cursor)
87
+ }
88
+ assert_equal true, get_page_info(result)["hasNextPage"]
89
+ assert_equal true, get_page_info(result)["hasPreviousPage"]
90
+
91
+ last_cursor = get_last_cursor(result)
92
+ result = with_bidirectional_pagination {
93
+ star_trek_query(query_string, "last" => 1, "before" => last_cursor)
94
+ }
95
+ assert_equal true, get_page_info(result)["hasNextPage"]
96
+ assert_equal false, get_page_info(result)["hasPreviousPage"]
97
+
98
+ result = star_trek_query(query_string, "first" => 100)
99
+ last_cursor = get_last_cursor(result)
100
+
101
+ result = star_trek_query(query_string, "last" => 1, "before" => last_cursor)
102
+ assert_equal false, get_page_info(result)["hasNextPage"]
103
+ assert_equal true, get_page_info(result)["hasPreviousPage"]
104
+
105
+ result = with_bidirectional_pagination {
106
+ star_trek_query(query_string, "last" => 1, "before" => last_cursor)
107
+ }
108
+ assert_equal true, get_page_info(result)["hasNextPage"]
109
+ assert_equal true, get_page_info(result)["hasPreviousPage"]
110
+ end
111
+
112
+ it 'slices the result' do
113
+ result = star_trek_query(query_string, "first" => 2)
114
+ assert_equal(["Deep Space Station K-7", "Regula I"], get_names(result))
115
+
116
+ # After the last result, find the next 2:
117
+ last_cursor = get_last_cursor(result)
118
+
119
+ result = star_trek_query(query_string, "after" => last_cursor, "first" => 2)
120
+ assert_equal(["Deep Space Nine"], get_names(result))
121
+
122
+ last_cursor = get_last_cursor(result)
123
+
124
+ result = star_trek_query(query_string, "before" => last_cursor, "last" => 1)
125
+ assert_equal(["Regula I"], get_names(result))
126
+
127
+ result = star_trek_query(query_string, "before" => last_cursor, "last" => 2)
128
+ assert_equal(["Deep Space Station K-7", "Regula I"], get_names(result))
129
+
130
+ result = star_trek_query(query_string, "before" => last_cursor, "last" => 10)
131
+ assert_equal(["Deep Space Station K-7", "Regula I"], get_names(result))
132
+
133
+ result = star_trek_query(query_string, "last" => 2)
134
+ assert_equal(["Regula I", "Deep Space Nine"], get_names(result))
135
+
136
+ result = star_trek_query(query_string, "last" => 10)
137
+ assert_equal(["Deep Space Station K-7", "Regula I", "Deep Space Nine"], get_names(result))
138
+ assert_equal(false, result["data"]["federation"]["bases"]["pageInfo"]["hasNextPage"])
139
+ assert_equal(false, result["data"]["federation"]["bases"]["pageInfo"]["hasPreviousPage"])
140
+ end
141
+
142
+ it 'works with before and after specified together' do
143
+ result = star_trek_query(query_string, "first" => 2)
144
+ assert_equal(["Deep Space Station K-7", "Regula I"], get_names(result))
145
+
146
+ first_cursor = get_last_cursor(result)
147
+
148
+ # There is no records between before and after if they point to the same cursor
149
+ result = star_trek_query(query_string, "before" => first_cursor, "after" => first_cursor, "last" => 2)
150
+ assert_equal([], get_names(result))
151
+
152
+ result = star_trek_query(query_string, "after" => first_cursor, "first" => 2)
153
+ assert_equal(["Deep Space Nine"], get_names(result))
154
+
155
+ second_cursor = get_last_cursor(result)
156
+
157
+ result = star_trek_query(query_string, "after" => first_cursor, "before" => second_cursor, "first" => 3)
158
+ assert_equal([], get_names(result)) # TODO: test fails. fixme
159
+ end
160
+
161
+ it 'handles cursors above the bounds of the array' do
162
+ overreaching_cursor = Base64.strict_encode64("100")
163
+ result = star_trek_query(query_string, "after" => overreaching_cursor, "first" => 2)
164
+ assert_equal([], get_names(result))
165
+ end
166
+
167
+ it 'handles cursors below the bounds of the array' do
168
+ underreaching_cursor = Base64.strict_encode64("1")
169
+ result = star_trek_query(query_string, "before" => underreaching_cursor, "first" => 2)
170
+ assert_equal([], get_names(result))
171
+ end
172
+
173
+
174
+ it 'handles grouped connections with only last argument' do
175
+ grouped_conn_query = <<-GRAPHQL
176
+ query {
177
+ newestBasesGroupedByFaction(last: 2) {
178
+ edges {
179
+ node {
180
+ name
181
+ }
182
+ }
183
+ }
184
+ }
185
+ GRAPHQL
186
+
187
+ result = star_trek_query(grouped_conn_query)
188
+ names = result['data']['newestBasesGroupedByFaction']['edges'].map { |edge| edge['node']['name'] }
189
+ assert_equal(['Ganalda Space Station', 'Deep Space Nine'], names)
190
+ end
191
+
192
+ it "applies custom arguments" do
193
+ result = star_trek_query(query_string, "first" => 1, "nameIncludes" => "eep")
194
+ assert_equal(["Deep Space Station K-7"], get_names(result))
195
+
196
+ after = get_last_cursor(result)
197
+
198
+ result = star_trek_query(query_string, "first" => 2, "nameIncludes" => "eep", "after" => after )
199
+ assert_equal(["Deep Space Nine"], get_names(result))
200
+ before = get_last_cursor(result)
201
+
202
+ result = star_trek_query(query_string, "last" => 1, "nameIncludes" => "eep", "before" => before)
203
+ assert_equal(["Deep Space Station K-7"], get_names(result))
204
+ end
205
+
206
+ it 'works without first/last/after/before' do
207
+ result = star_trek_query(query_string)
208
+
209
+ assert_equal(3, result["data"]["federation"]["bases"]["edges"].length)
210
+ end
211
+
212
+ describe "applying max_page_size" do
213
+ let(:query_string) {%|
214
+ query getBases($first: Int, $after: String, $last: Int, $before: String){
215
+ federation {
216
+ bases: basesWithMaxLimitRelation(first: $first, after: $after, last: $last, before: $before) {
217
+ ... basesConnection
218
+ }
219
+ }
220
+ }
221
+
222
+ fragment basesConnection on BaseConnection {
223
+ edges {
224
+ cursor
225
+ node {
226
+ name
227
+ }
228
+ },
229
+ pageInfo {
230
+ hasNextPage
231
+ hasPreviousPage
232
+ startCursor
233
+ endCursor
234
+ }
235
+ }
236
+ |}
237
+
238
+ it "applies to queries by `first`" do
239
+ result = star_trek_query(query_string, "first" => 100)
240
+ assert_equal(2, result["data"]["federation"]["bases"]["edges"].size)
241
+ assert_equal(true, result["data"]["federation"]["bases"]["pageInfo"]["hasNextPage"])
242
+
243
+ # Max page size is applied _without_ `first`, also
244
+ result = star_trek_query(query_string)
245
+ assert_equal(2, result["data"]["federation"]["bases"]["edges"].size)
246
+ assert_equal(false, result["data"]["federation"]["bases"]["pageInfo"]["hasNextPage"], "hasNextPage is false when first is not specified")
247
+ end
248
+
249
+ it "applies to queries by `last`" do
250
+ second_to_last_two_names = ["Firebase P'ok", "Ganalda Space Station"]
251
+ first_and_second_names = ["Deep Space Station K-7", "Regula I"]
252
+
253
+ last_cursor = "Ng=="
254
+ result = star_trek_query(query_string, "last" => 100, "before" => last_cursor)
255
+ assert_equal(second_to_last_two_names, get_names(result))
256
+ assert_equal(true, result["data"]["federation"]["bases"]["pageInfo"]["hasPreviousPage"])
257
+
258
+ result = star_trek_query(query_string, "before" => last_cursor)
259
+ assert_equal(first_and_second_names, get_names(result))
260
+ assert_equal(false, result["data"]["federation"]["bases"]["pageInfo"]["hasPreviousPage"], "hasPreviousPage is false when last is not specified")
261
+
262
+ third_cursor = "Mw=="
263
+ result = star_trek_query(query_string, "last" => 100, "before" => third_cursor)
264
+ assert_equal(first_and_second_names, get_names(result))
265
+
266
+ result = star_trek_query(query_string, "before" => third_cursor)
267
+ assert_equal(first_and_second_names, get_names(result))
268
+ end
269
+ end
270
+
271
+ describe "applying default_max_page_size" do
272
+ let(:query_string) {%|
273
+ query getBases($first: Int, $after: String, $last: Int, $before: String){
274
+ federation {
275
+ bases: basesWithDefaultMaxLimitRelation(first: $first, after: $after, last: $last, before: $before) {
276
+ ... basesConnection
277
+ }
278
+ }
279
+ }
280
+
281
+ fragment basesConnection on BaseConnection {
282
+ edges {
283
+ cursor
284
+ node {
285
+ name
286
+ }
287
+ },
288
+ pageInfo {
289
+ hasNextPage
290
+ hasPreviousPage
291
+ startCursor
292
+ endCursor
293
+ }
294
+ }
295
+ |}
296
+
297
+ it "applies to queries by `first`" do
298
+ result = star_trek_query(query_string, "first" => 100)
299
+ assert_equal(3, result["data"]["federation"]["bases"]["edges"].size)
300
+ assert_equal(true, result["data"]["federation"]["bases"]["pageInfo"]["hasNextPage"])
301
+
302
+ # Max page size is applied _without_ `first`, also
303
+ result = star_trek_query(query_string)
304
+ assert_equal(3, result["data"]["federation"]["bases"]["edges"].size)
305
+ assert_equal(false, result["data"]["federation"]["bases"]["pageInfo"]["hasNextPage"], "hasNextPage is false when first is not specified")
306
+ end
307
+
308
+ it "applies to queries by `last`" do
309
+ second_to_last_three_names = ["Deep Space Nine", "Firebase P'ok", "Ganalda Space Station"]
310
+ first_second_and_third_names = ["Deep Space Station K-7", "Regula I", "Deep Space Nine"]
311
+
312
+ last_cursor = "Ng=="
313
+ result = star_trek_query(query_string, "last" => 100, "before" => last_cursor)
314
+ assert_equal(second_to_last_three_names, get_names(result))
315
+ assert_equal(true, result["data"]["federation"]["bases"]["pageInfo"]["hasPreviousPage"])
316
+
317
+ result = star_trek_query(query_string, "before" => last_cursor)
318
+ assert_equal(first_second_and_third_names, get_names(result))
319
+ assert_equal(false, result["data"]["federation"]["bases"]["pageInfo"]["hasPreviousPage"], "hasPreviousPage is false when last is not specified")
320
+
321
+ fourth_cursor = "NA=="
322
+ result = star_trek_query(query_string, "last" => 100, "before" => fourth_cursor)
323
+ assert_equal(first_second_and_third_names, get_names(result))
324
+
325
+ result = star_trek_query(query_string, "before" => fourth_cursor)
326
+ assert_equal(first_second_and_third_names, get_names(result))
327
+ end
328
+ end
329
+ end
330
+
331
+ describe "applying a max_page_size bigger than the results" do
332
+ let(:query_string) {%|
333
+ query getBases($first: Int, $after: String, $last: Int, $before: String){
334
+ federation {
335
+ bases: basesWithLargeMaxLimitRelation(first: $first, after: $after, last: $last, before: $before) {
336
+ ... basesConnection
337
+ }
338
+ }
339
+ }
340
+
341
+ fragment basesConnection on BaseConnection {
342
+ edges {
343
+ cursor
344
+ node {
345
+ name
346
+ }
347
+ },
348
+ pageInfo {
349
+ hasNextPage
350
+ hasPreviousPage
351
+ startCursor
352
+ endCursor
353
+ }
354
+ }
355
+ |}
356
+
357
+ it "applies to queries by `first`" do
358
+ result = star_trek_query(query_string, "first" => 100)
359
+ assert_equal(6, result["data"]["federation"]["bases"]["edges"].size)
360
+ assert_equal(false, result["data"]["federation"]["bases"]["pageInfo"]["hasNextPage"])
361
+
362
+ # Max page size is applied _without_ `first`, also
363
+ result = star_trek_query(query_string)
364
+ assert_equal(6, result["data"]["federation"]["bases"]["edges"].size)
365
+ assert_equal(false, result["data"]["federation"]["bases"]["pageInfo"]["hasNextPage"], "hasNextPage is false when first is not specified")
366
+ end
367
+
368
+ it "applies to queries by `last`" do
369
+ all_names = ["Deep Space Station K-7", "Regula I", "Deep Space Nine", "Firebase P'ok", "Ganalda Space Station", "Rh'Ihho Station"]
370
+
371
+ last_cursor = "Ng=="
372
+ result = star_trek_query(query_string, "last" => 100, "before" => last_cursor)
373
+ assert_equal(all_names[0..4], get_names(result))
374
+ assert_equal(false, result["data"]["federation"]["bases"]["pageInfo"]["hasPreviousPage"])
375
+
376
+ result = star_trek_query(query_string, "last" => 100)
377
+ assert_equal(all_names, get_names(result))
378
+ assert_equal(false, result["data"]["federation"]["bases"]["pageInfo"]["hasPreviousPage"])
379
+
380
+ result = star_trek_query(query_string, "before" => last_cursor)
381
+ assert_equal(all_names[0..4], get_names(result))
382
+ assert_equal(false, result["data"]["federation"]["bases"]["pageInfo"]["hasPreviousPage"], "hasPreviousPage is false when last is not specified")
383
+
384
+ fourth_cursor = "NA=="
385
+ result = star_trek_query(query_string, "last" => 100, "before" => fourth_cursor)
386
+ assert_equal(all_names[0..2], get_names(result))
387
+
388
+ result = star_trek_query(query_string, "before" => fourth_cursor)
389
+ assert_equal(all_names[0..2], get_names(result))
390
+ end
391
+ end
392
+
393
+ describe "without a block" do
394
+ let(:query_string) {%|
395
+ {
396
+ federation {
397
+ basesClone(first: 10) {
398
+ edges {
399
+ node {
400
+ name
401
+ }
402
+ }
403
+ }
404
+ }
405
+ }|}
406
+ it "uses default resolve" do
407
+ result = star_trek_query(query_string)
408
+ bases = result["data"]["federation"]["basesClone"]["edges"]
409
+ assert_equal(3, bases.length)
410
+ end
411
+ end
412
+
413
+ describe "custom ordering" do
414
+ let(:query_string) {%|
415
+ query getBases {
416
+ federation {
417
+ basesByName(first: 30) { ... basesFields }
418
+ bases(first: 30) { ... basesFields2 }
419
+ }
420
+ }
421
+ fragment basesFields on BaseConnection {
422
+ edges {
423
+ node {
424
+ name
425
+ }
426
+ }
427
+ }
428
+ fragment basesFields2 on BasesConnectionWithTotalCount {
429
+ edges {
430
+ node {
431
+ name
432
+ }
433
+ }
434
+ }
435
+ |}
436
+
437
+ def get_names(result, field_name)
438
+ bases = result["data"]["federation"][field_name]["edges"]
439
+ bases.map { |b| b["node"]["name"] }
440
+ end
441
+
442
+ it "applies the default value" do
443
+ result = star_trek_query(query_string)
444
+ bases_by_id = ["Deep Space Station K-7", "Regula I", "Deep Space Nine"]
445
+ bases_by_name = ["Deep Space Nine", "Deep Space Station K-7", "Regula I"]
446
+
447
+ assert_equal(bases_by_id, get_names(result, "bases"))
448
+ assert_equal(bases_by_name, get_names(result, "basesByName"))
449
+ end
450
+ end
451
+
452
+ describe "#cursor_from_node" do
453
+ let(:connection) { GraphQL::Relay::MongoRelationConnection.new(StarTrek::Base.where(faction_id: 1), {}) }
454
+
455
+ it "returns the cursor for a node in the connection" do
456
+ assert_equal "MQ==", connection.cursor_from_node(StarTrek::Base.all[0])
457
+ assert_equal "Mg==", connection.cursor_from_node(StarTrek::Base.all[1])
458
+ end
459
+
460
+ it "raises when the node isn't found" do
461
+ err = assert_raises(RuntimeError) {
462
+ connection.cursor_from_node(:not_found)
463
+ }
464
+ assert_includes err.message, "item not found"
465
+ end
466
+ end
467
+
468
+ it "is chosen for a relation" do
469
+ relation = StarTrek::Base.where(faction_id: 1)
470
+ assert relation.is_a?(Mongoid::Criteria)
471
+ connection = GraphQL::Relay::BaseConnection.connection_for_nodes(relation)
472
+ assert_equal GraphQL::Relay::MongoRelationConnection, connection
473
+ end
474
+ end