graphql 1.6.7 → 1.6.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cf91ec48fafdc82dbda6deb667fab007e575f2a3
4
- data.tar.gz: 32ae2960557c969bee15e14552727d22c782a858
3
+ metadata.gz: '056695dd78098e5adfe501785c8e7e111cb8bc2d'
4
+ data.tar.gz: 5ef5aa896020c5b149c1960a5e870d8f13e4a2f8
5
5
  SHA512:
6
- metadata.gz: 60b47807f1b5c868f300f173b7191522b6361d9ebd4cf0ad3fc52842da586f500d223cf1df9f719e1902f191d918fd1f5f6fef14dab7d686a853e1a49b58a09a
7
- data.tar.gz: 0c3bf0b9fdfd281603ce140af59e7b75542ad8b992ac247b676876b0ca14586b1ede1462490cc1ed33236ec6e6643b67cdd4e1e724b75321972a73cfcdd1f07e
6
+ metadata.gz: 50d4e93b57572c9a3cce63468b0e6b23daca8f61a97120e5899613018c1bdfc4fe9ecade9b8906e4243c383a55f636b37d066e52d14310c002911e7e7c3c086f
7
+ data.tar.gz: 63d326d4a3ea184e7840308d6841afb7af3336d570f9d8362ffdad5d0e351016e0d67c72bf9ec62e3629a5ce768bf4fe1b92bc0873b7effa47b37aa3f370f7f9
@@ -1,5 +1,11 @@
1
1
  Types::MutationType = GraphQL::ObjectType.define do
2
2
  name "Mutation"
3
3
 
4
- # TODO: Add Mutations as fields
4
+ # TODO: Remove me
5
+ field :testField, types.String do
6
+ description "An example field added by the generator"
7
+ resolve ->(obj, args, ctx) {
8
+ "Hello World!"
9
+ }
10
+ end
5
11
  end
@@ -5,22 +5,28 @@ require "set"
5
5
  require "singleton"
6
6
 
7
7
  module GraphQL
8
- # Ruby stdlib was pretty busted until this fix:
9
- # https://github.com/ruby/ruby/commit/46c0e79bb5b96c45c166ef62f8e585f528862abb#diff-43adf0e587a50dbaf51764a262008d40
10
- module Delegate
11
- def def_delegators(accessor, *method_names)
12
- method_names.each do |method_name|
13
- class_eval <<-RUBY
14
- def #{method_name}(*args)
15
- if block_given?
16
- #{accessor}.#{method_name}(*args, &Proc.new)
17
- else
18
- #{accessor}.#{method_name}(*args)
8
+ if RUBY_VERSION == "2.4.0"
9
+ # Ruby stdlib was pretty busted until this fix:
10
+ # https://bugs.ruby-lang.org/issues/13111
11
+ # https://github.com/ruby/ruby/commit/46c0e79bb5b96c45c166ef62f8e585f528862abb#diff-43adf0e587a50dbaf51764a262008d40
12
+ module Delegate
13
+ def def_delegators(accessor, *method_names)
14
+ method_names.each do |method_name|
15
+ class_eval <<-RUBY
16
+ def #{method_name}(*args)
17
+ if block_given?
18
+ #{accessor}.#{method_name}(*args, &Proc.new)
19
+ else
20
+ #{accessor}.#{method_name}(*args)
21
+ end
19
22
  end
23
+ RUBY
20
24
  end
21
- RUBY
22
25
  end
23
26
  end
27
+ else
28
+ require "forwardable"
29
+ Delegate = Forwardable
24
30
  end
25
31
 
26
32
  class Error < StandardError
@@ -138,11 +138,26 @@ module GraphQL
138
138
  accepts_definitions(*ATTRIBUTES)
139
139
  attr_accessor(*ATTRIBUTES)
140
140
  ensure_defined(*ATTRIBUTES)
141
+
142
+ def name=(new_name)
143
+ # Validate that the name is correct
144
+ unless new_name =~ /^[_a-zA-Z][_a-zA-Z0-9]*$/
145
+ raise(
146
+ GraphQL::EnumType::InvalidEnumNameError,
147
+ "Names must match /^[_a-zA-Z][_a-zA-Z0-9]*$/ but '#{new_name}' does not"
148
+ )
149
+ end
150
+
151
+ @name = new_name
152
+ end
141
153
  end
142
154
 
143
155
  class UnresolvedValueError < GraphQL::Error
144
156
  end
145
157
 
158
+ class InvalidEnumNameError < GraphQL::Error
159
+ end
160
+
146
161
  private
147
162
 
148
163
  # Get the underlying value for this enum value
@@ -205,6 +205,7 @@ module GraphQL
205
205
  @relay_node_field = false
206
206
  @connection = false
207
207
  @connection_max_page_size = nil
208
+ @edge_class = nil
208
209
  end
209
210
 
210
211
  def initialize_copy(other)
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
+ class DoubleNonNullTypeError < GraphQL::Error
4
+ end
5
+
3
6
  # A non-null type modifies another type.
4
7
  #
5
8
  # Non-null types can be created with `!` (`InnerType!`)
@@ -34,6 +37,13 @@ module GraphQL
34
37
 
35
38
  attr_reader :of_type
36
39
  def initialize(of_type:)
40
+ if of_type.is_a?(GraphQL::NonNullType)
41
+ raise(
42
+ DoubleNonNullTypeError,
43
+ "You tried to add a non-null constraint twice (!! instead of !)"
44
+ )
45
+ end
46
+
37
47
  super()
38
48
  @of_type = of_type
39
49
  end
@@ -44,6 +44,7 @@ module GraphQL
44
44
 
45
45
  # @return [String, nil] The name of the operation to run (may be inferred)
46
46
  def selected_operation_name
47
+ return nil unless selected_operation
47
48
  selected_operation.name
48
49
  end
49
50
 
@@ -161,7 +162,10 @@ module GraphQL
161
162
  end
162
163
 
163
164
  def irep_selection
164
- @selection ||= internal_representation.operation_definitions[selected_operation.name]
165
+ @selection ||= begin
166
+ return nil unless selected_operation
167
+ internal_representation.operation_definitions[selected_operation.name]
168
+ end
165
169
  end
166
170
 
167
171
  # Node-level cache for calculating arguments. Used during execution and query analysis.
@@ -24,11 +24,11 @@ module GraphQL
24
24
  end
25
25
 
26
26
  def has_next_page
27
- !!(first && sliced_nodes_count > first)
27
+ !!(first && paged_nodes_length >= first && sliced_nodes_count > first)
28
28
  end
29
29
 
30
30
  def has_previous_page
31
- !!(last && sliced_nodes_count > last)
31
+ !!(last && paged_nodes_length >= last && sliced_nodes_count > last)
32
32
  end
33
33
 
34
34
  def first
@@ -68,7 +68,8 @@ module GraphQL
68
68
  items = items.offset(offset).limit(last)
69
69
  end
70
70
  else
71
- offset = (relation_offset(items) || 0) + relation_count(items) - last
71
+ slice_count = relation_count(items)
72
+ offset = (relation_offset(items) || 0) + slice_count - [last, slice_count].min
72
73
  items = items.offset(offset).limit(last)
73
74
  end
74
75
  end
@@ -121,17 +122,26 @@ module GraphQL
121
122
 
122
123
  if before && after
123
124
  if offset_from_cursor(after) < offset_from_cursor(before)
124
- @sliced_nodes = @sliced_nodes.limit(offset_from_cursor(before) - offset_from_cursor(after) - 1)
125
+ @sliced_nodes = limit_nodes(@sliced_nodes, offset_from_cursor(before) - offset_from_cursor(after) - 1)
125
126
  else
126
- @sliced_nodes = @sliced_nodes.limit(0)
127
+ @sliced_nodes = limit_nodes(@sliced_nodes, 0)
127
128
  end
129
+
128
130
  elsif before
129
- @sliced_nodes = @sliced_nodes.limit(offset_from_cursor(before) - 1)
131
+ @sliced_nodes = limit_nodes(@sliced_nodes, offset_from_cursor(before) - 1)
130
132
  end
131
133
 
132
134
  @sliced_nodes
133
135
  end
134
136
 
137
+ def limit_nodes(sliced_nodes, limit)
138
+ if limit > 0 || defined?(ActiveRecord::Relation) && sliced_nodes.is_a?(ActiveRecord::Relation)
139
+ sliced_nodes.limit(limit)
140
+ else
141
+ sliced_nodes.where(false)
142
+ end
143
+ end
144
+
135
145
  def sliced_nodes_count
136
146
  return @sliced_nodes_count if defined? @sliced_nodes_count
137
147
 
@@ -147,6 +157,14 @@ module GraphQL
147
157
  return @paged_nodes_array if defined?(@paged_nodes_array)
148
158
  @paged_nodes_array = paged_nodes.to_a
149
159
  end
160
+
161
+ def paged_nodes_length
162
+ if paged_nodes.respond_to?(:length)
163
+ paged_nodes.length
164
+ else
165
+ paged_nodes_array.length
166
+ end
167
+ end
150
168
  end
151
169
 
152
170
  if defined?(ActiveRecord::Relation)
@@ -280,6 +280,9 @@ module GraphQL
280
280
  resolve: ->(obj, args, ctx) { default_resolve.call(field, obj, args, ctx) },
281
281
  deprecation_reason: build_deprecation_reason(field_definition.directives),
282
282
  )
283
+
284
+ type_name = resolve_type_name(field_definition.type)
285
+ field.connection = type_name.end_with?("Connection")
283
286
  [field_definition.name, field]
284
287
  end
285
288
  end
@@ -294,6 +297,15 @@ module GraphQL
294
297
  end
295
298
  type
296
299
  end
300
+
301
+ def resolve_type_name(type)
302
+ case type
303
+ when GraphQL::Language::Nodes::TypeName
304
+ return type.name
305
+ else
306
+ resolve_type_name(type.of_type)
307
+ end
308
+ end
297
309
  end
298
310
 
299
311
  private_constant :Builder
@@ -29,6 +29,7 @@ module GraphQL
29
29
  def visit(member, context_description)
30
30
  case member
31
31
  when GraphQL::Schema
32
+ member.directives.each { |name, directive| visit(directive, "Directive #{name}") }
32
33
  # Find the starting points, then visit them
33
34
  visit_roots = [member.query, member.mutation, member.subscription]
34
35
  if @introspection
@@ -37,6 +38,10 @@ module GraphQL
37
38
  visit_roots.concat(member.orphan_types)
38
39
  visit_roots.compact!
39
40
  visit_roots.each { |t| visit(t, t.name) }
41
+ when GraphQL::Directive
42
+ member.arguments.each do |name, argument|
43
+ visit(argument.type, "Directive argument #{member.name}.#{name}")
44
+ end
40
45
  when GraphQL::BaseType
41
46
  type_defn = member.unwrap
42
47
  prev_type = @type_map[type_defn.name]
@@ -7,7 +7,7 @@ module GraphQL
7
7
  if argument_defn.nil?
8
8
  kind_of_node = node_type(parent)
9
9
  error_arg_name = parent_name(parent, defn)
10
- context.errors << message("#{kind_of_node} '#{error_arg_name}' doesn't accept argument '#{node.name}'", parent, context: context)
10
+ context.errors << message("#{kind_of_node} '#{error_arg_name}' doesn't accept argument '#{node.name}'", node, context: context)
11
11
  GraphQL::Language::Visitor::SKIP
12
12
  else
13
13
  nil
@@ -53,7 +53,13 @@ module GraphQL
53
53
  return
54
54
  end
55
55
  if !ast_var.default_value.nil?
56
- var_type = GraphQL::NonNullType.new(of_type: var_type)
56
+ unless var_type.is_a?(GraphQL::NonNullType)
57
+ # If the value is required, but the argument is not,
58
+ # and yet there's a non-nil default, then we impliclty
59
+ # make the argument also a required type.
60
+
61
+ var_type = GraphQL::NonNullType.new(of_type: var_type)
62
+ end
57
63
  end
58
64
 
59
65
  arg_defn = arguments[arg_node.name]
@@ -24,7 +24,10 @@ module GraphQL
24
24
  @parent_type = parent_type
25
25
  @resolved_type = resolved_type
26
26
  @possible_types = possible_types
27
- message = %|The value from "#{field.name}" on "#{parent_type}" could not be resolved to "#{field.type}". (Received: #{resolved_type.inspect}, Expected: [#{possible_types.map(&:inspect).join(", ")}])|
27
+ message = "The value from \"#{field.name}\" on \"#{parent_type}\" could not be resolved to \"#{field.type}\". " \
28
+ "(Received: `#{resolved_type.inspect}`, Expected: [#{possible_types.map(&:inspect).join(", ")}]) " \
29
+ "Make sure you have defined a `type_from_object` proc on your schema and that value `#{value.inspect}` " \
30
+ "gets resolved to a valid type."
28
31
  super(message)
29
32
  end
30
33
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module GraphQL
3
- VERSION = "1.6.7"
3
+ VERSION = "1.6.8"
4
4
  end
@@ -37,6 +37,21 @@ describe GraphQL::EnumType do
37
37
  end
38
38
  end
39
39
 
40
+ describe "invalid names" do
41
+ it "rejects names with a space" do
42
+ assert_raises(GraphQL::EnumType::InvalidEnumNameError) {
43
+ InvalidEnumTest = GraphQL::EnumType.define do
44
+ name "InvalidEnumTest"
45
+
46
+ value("SPACE IN VALUE", "Invalid enum because it contains spaces", value: 1)
47
+ end
48
+
49
+ # Force evaluation
50
+ InvalidEnumTest.name
51
+ }
52
+ end
53
+ end
54
+
40
55
  describe "values that are Arrays" do
41
56
  let(:schema) {
42
57
  enum = GraphQL::EnumType.define do
@@ -4,6 +4,19 @@ require "spec_helper"
4
4
  describe GraphQL::ObjectType do
5
5
  let(:type) { Dummy::CheeseType }
6
6
 
7
+ it "doesn't allow double non-null constraints" do
8
+ assert_raises(GraphQL::DoubleNonNullTypeError) {
9
+ DoubleNullObject = GraphQL::ObjectType.define do
10
+ name "DoubleNull"
11
+
12
+ field :id, !!types.Int, "Fails because double !"
13
+ end
14
+
15
+ # Force evaluation
16
+ DoubleNullObject.name
17
+ }
18
+ end
19
+
7
20
  it "has a name" do
8
21
  assert_equal("Cheese", type.name)
9
22
  type.name = "Fromage"
@@ -35,7 +35,7 @@ describe GraphQL::Query::SerialExecution::ValueResolution do
35
35
  resolve ->(obj, args, ctx) { (args["today"] + 1) % 7 }
36
36
  end
37
37
  field :resolvesToNilInterface, interface do
38
- resolve ->(obj, args, ctx) { Object.new }
38
+ resolve ->(obj, args, ctx) { 1337 }
39
39
  end
40
40
  field :resolvesToWrongTypeInterface, interface do
41
41
  resolve ->(obj, args, ctx) { :something }
@@ -86,7 +86,10 @@ describe GraphQL::Query::SerialExecution::ValueResolution do
86
86
 
87
87
  it "raises an error" do
88
88
  err = assert_raises(GraphQL::UnresolvedTypeError) { result }
89
- expected_message = %|The value from "resolvesToNilInterface" on "Query" could not be resolved to "SomeInterface". (Received: nil, Expected: [SomeObject])|
89
+ expected_message = "The value from \"resolvesToNilInterface\" on \"Query\" could not be resolved to \"SomeInterface\". " \
90
+ "(Received: `nil`, Expected: [SomeObject]) " \
91
+ "Make sure you have defined a `type_from_object` proc on your schema and that value `1337` " \
92
+ "gets resolved to a valid type."
90
93
  assert_equal expected_message, err.message
91
94
  end
92
95
  end
@@ -100,7 +103,10 @@ describe GraphQL::Query::SerialExecution::ValueResolution do
100
103
 
101
104
  it "raises an error" do
102
105
  err = assert_raises(GraphQL::UnresolvedTypeError) { result }
103
- expected_message = %|The value from "resolvesToWrongTypeInterface" on "Query" could not be resolved to "SomeInterface". (Received: OtherObject, Expected: [SomeObject])|
106
+ expected_message = "The value from \"resolvesToWrongTypeInterface\" on \"Query\" could not be resolved to \"SomeInterface\". " \
107
+ "(Received: `OtherObject`, Expected: [SomeObject]) " \
108
+ "Make sure you have defined a `type_from_object` proc on your schema and that value `:something` " \
109
+ "gets resolved to a valid type."
104
110
  assert_equal expected_message, err.message
105
111
  end
106
112
  end
@@ -68,7 +68,7 @@ describe GraphQL::Query do
68
68
  end
69
69
  end
70
70
 
71
- describe "operation_name" do
71
+ describe "#operation_name" do
72
72
  describe "when provided" do
73
73
  let(:query_string) { <<-GRAPHQL
74
74
  query q1 { cheese(id: 1) { flavor } }
@@ -79,7 +79,6 @@ describe GraphQL::Query do
79
79
 
80
80
  it "returns the provided name" do
81
81
  assert_equal "q2", query.operation_name
82
- assert_equal "q2", query.selected_operation_name
83
82
  end
84
83
  end
85
84
 
@@ -91,7 +90,44 @@ describe GraphQL::Query do
91
90
 
92
91
  it "returns nil" do
93
92
  assert_equal nil, query.operation_name
94
- assert_equal "q3", query.selected_operation_name
93
+ end
94
+ end
95
+
96
+ describe "#selected_operation_name" do
97
+ describe "when an operation isprovided" do
98
+ let(:query_string) { <<-GRAPHQL
99
+ query q1 { cheese(id: 1) { flavor } }
100
+ query q2 { cheese(id: 2) { flavor } }
101
+ GRAPHQL
102
+ }
103
+ let(:operation_name) { "q2" }
104
+
105
+ it "returns the provided name" do
106
+ assert_equal "q2", query.selected_operation_name
107
+ end
108
+ end
109
+
110
+ describe "when operation is inferred" do
111
+ let(:query_string) { <<-GRAPHQL
112
+ query q3 { cheese(id: 3) { flavor } }
113
+ GRAPHQL
114
+ }
115
+
116
+ it "returns the inferred operation name" do
117
+ assert_equal "q3", query.selected_operation_name
118
+ end
119
+ end
120
+
121
+ describe "when there are no operations" do
122
+ let(:query_string) { <<-GRAPHQL
123
+ # Only Comments
124
+ # In this Query
125
+ GRAPHQL
126
+ }
127
+
128
+ it "returns the inferred operation name" do
129
+ assert_equal nil, query.selected_operation_name
130
+ end
95
131
  end
96
132
  end
97
133
 
@@ -633,6 +669,18 @@ describe GraphQL::Query do
633
669
  end
634
670
  end
635
671
 
672
+ describe '#irep_selection' do
673
+ it "returns the irep for the selected operation" do
674
+ assert_kind_of GraphQL::InternalRepresentation::Node, query.irep_selection
675
+ assert_equal 'getFlavor', query.irep_selection.name
676
+ end
677
+
678
+ it "returns nil when there is no selected operation" do
679
+ query = GraphQL::Query.new(schema, '# Only a comment')
680
+ assert_equal nil, query.irep_selection
681
+ end
682
+ end
683
+
636
684
  describe "query_execution_strategy" do
637
685
  let(:custom_execution_schema) {
638
686
  schema.redefine do
@@ -123,12 +123,19 @@ describe GraphQL::Relay::RelationConnection do
123
123
  assert_equal([], get_names(result))
124
124
  end
125
125
 
126
- it 'handles cursors beyond the bounds of the array' do
126
+ it 'handles cursors above the bounds of the array' do
127
127
  overreaching_cursor = Base64.strict_encode64("100")
128
128
  result = star_wars_query(query_string, "after" => overreaching_cursor, "first" => 2)
129
129
  assert_equal([], get_names(result))
130
130
  end
131
131
 
132
+ it 'handles cursors below the bounds of the array' do
133
+ underreaching_cursor = Base64.strict_encode64("1")
134
+ result = star_wars_query(query_string, "before" => underreaching_cursor, "first" => 2)
135
+ assert_equal([], get_names(result))
136
+ end
137
+
138
+
132
139
  it 'handles grouped connections with only last argument' do
133
140
  grouped_conn_query = <<-GRAPHQL
134
141
  query {
@@ -286,6 +293,68 @@ describe GraphQL::Relay::RelationConnection do
286
293
  end
287
294
  end
288
295
 
296
+ describe "applying a max_page_size bigger than the results" do
297
+ let(:query_string) {%|
298
+ query getBases($first: Int, $after: String, $last: Int, $before: String){
299
+ empire {
300
+ bases: basesWithLargeMaxLimitRelation(first: $first, after: $after, last: $last, before: $before) {
301
+ ... basesConnection
302
+ }
303
+ }
304
+ }
305
+
306
+ fragment basesConnection on BaseConnection {
307
+ edges {
308
+ cursor
309
+ node {
310
+ name
311
+ }
312
+ },
313
+ pageInfo {
314
+ hasNextPage
315
+ hasPreviousPage
316
+ startCursor
317
+ endCursor
318
+ }
319
+ }
320
+ |}
321
+
322
+ it "applies to queries by `first`" do
323
+ result = star_wars_query(query_string, "first" => 100)
324
+ assert_equal(6, result["data"]["empire"]["bases"]["edges"].size)
325
+ assert_equal(false, result["data"]["empire"]["bases"]["pageInfo"]["hasNextPage"])
326
+
327
+ # Max page size is applied _without_ `first`, also
328
+ result = star_wars_query(query_string)
329
+ assert_equal(6, result["data"]["empire"]["bases"]["edges"].size)
330
+ assert_equal(false, result["data"]["empire"]["bases"]["pageInfo"]["hasNextPage"], "hasNextPage is false when first is not specified")
331
+ end
332
+
333
+ it "applies to queries by `last`" do
334
+ all_names = ["Yavin", "Echo Base", "Secret Hideout", "Death Star", "Shield Generator", "Headquarters"]
335
+
336
+ last_cursor = "Ng=="
337
+ result = star_wars_query(query_string, "last" => 100, "before" => last_cursor)
338
+ assert_equal(all_names[0..4], get_names(result))
339
+ assert_equal(false, result["data"]["empire"]["bases"]["pageInfo"]["hasPreviousPage"])
340
+
341
+ result = star_wars_query(query_string, "last" => 100)
342
+ assert_equal(all_names, get_names(result))
343
+ assert_equal(false, result["data"]["empire"]["bases"]["pageInfo"]["hasPreviousPage"])
344
+
345
+ result = star_wars_query(query_string, "before" => last_cursor)
346
+ assert_equal(all_names[0..4], get_names(result))
347
+ assert_equal(false, result["data"]["empire"]["bases"]["pageInfo"]["hasPreviousPage"], "hasPreviousPage is false when last is not specified")
348
+
349
+ fourth_cursor = "NA=="
350
+ result = star_wars_query(query_string, "last" => 100, "before" => fourth_cursor)
351
+ assert_equal(all_names[0..2], get_names(result))
352
+
353
+ result = star_wars_query(query_string, "before" => fourth_cursor)
354
+ assert_equal(all_names[0..2], get_names(result))
355
+ end
356
+ end
357
+
289
358
  describe "without a block" do
290
359
  let(:query_string) {%|
291
360
  {
@@ -441,6 +510,18 @@ describe GraphQL::Relay::RelationConnection do
441
510
 
442
511
  end
443
512
 
513
+ it 'handles cursors above the bounds of the array' do
514
+ overreaching_cursor = Base64.strict_encode64("100")
515
+ result = star_wars_query(query_string, "after" => overreaching_cursor, "first" => 2)
516
+ assert_equal([], get_names(result))
517
+ end
518
+
519
+ it 'handles cursors below the bounds of the array' do
520
+ underreaching_cursor = Base64.strict_encode64("1")
521
+ result = star_wars_query(query_string, "before" => underreaching_cursor, "first" => 2)
522
+ assert_equal([], get_names(result))
523
+ end
524
+
444
525
  it "applies custom arguments" do
445
526
  result = star_wars_query(query_string, "first" => 1, "nameIncludes" => "ea")
446
527
  assert_equal(["Death Star"], get_names(result))
@@ -206,6 +206,85 @@ type Hello {
206
206
  build_schema_and_compare_output(schema.chop)
207
207
  end
208
208
 
209
+ it 'properly understands connections' do
210
+ schema = <<-SCHEMA
211
+ schema {
212
+ query: Type
213
+ }
214
+
215
+ type Organization {
216
+ email: String
217
+ }
218
+
219
+ # The connection type for Organization.
220
+ type OrganizationConnection {
221
+ # A list of edges.
222
+ edges: [OrganizationEdge]
223
+
224
+ # A list of nodes.
225
+ nodes: [Organization]
226
+
227
+ # Information to aid in pagination.
228
+ pageInfo: PageInfo!
229
+
230
+ # Identifies the total count of items in the connection.
231
+ totalCount: Int!
232
+ }
233
+
234
+ # An edge in a connection.
235
+ type OrganizationEdge {
236
+ # A cursor for use in pagination.
237
+ cursor: String!
238
+
239
+ # The item at the end of the edge.
240
+ node: Organization
241
+ }
242
+
243
+ # Information about pagination in a connection.
244
+ type PageInfo {
245
+ # When paginating forwards, the cursor to continue.
246
+ endCursor: String
247
+
248
+ # When paginating forwards, are there more items?
249
+ hasNextPage: Boolean!
250
+
251
+ # When paginating backwards, are there more items?
252
+ hasPreviousPage: Boolean!
253
+
254
+ # When paginating backwards, the cursor to continue.
255
+ startCursor: String
256
+ }
257
+
258
+ type Type {
259
+ name: String
260
+ organization(
261
+ # The login of the organization to find.
262
+ login: String!
263
+ ): Organization
264
+
265
+ # A list of organizations the user belongs to.
266
+ organizations(
267
+ # Returns the elements in the list that come after the specified global ID.
268
+ after: String
269
+
270
+ # Returns the elements in the list that come before the specified global ID.
271
+ before: String
272
+
273
+ # Returns the first _n_ elements from the list.
274
+ first: Int
275
+
276
+ # Returns the last _n_ elements from the list.
277
+ last: Int
278
+ ): OrganizationConnection!
279
+ }
280
+ SCHEMA
281
+
282
+ built_schema = build_schema_and_compare_output(schema.chop)
283
+ obj = built_schema.types["Type"]
284
+ refute obj.fields["organization"].connection?
285
+ assert obj.fields["organizations"].connection?
286
+ end
287
+
209
288
  it 'supports simple type with multiple arguments' do
210
289
  schema = <<-SCHEMA
211
290
  schema {
@@ -8,8 +8,19 @@ describe GraphQL::Schema::Traversal do
8
8
  traversal.type_map
9
9
  end
10
10
 
11
+ it "finds types from directives" do
12
+ expected = {
13
+ "Boolean" => GraphQL::BOOLEAN_TYPE, # `skip` argument
14
+ "String" => GraphQL::STRING_TYPE # `deprecated` argument
15
+ }
16
+ result = reduce_types([])
17
+ assert_equal(expected.keys.sort, result.keys.sort)
18
+ assert_equal(expected, result.to_h)
19
+ end
20
+
11
21
  it "finds types from a single type and its fields" do
12
22
  expected = {
23
+ "Boolean" => GraphQL::BOOLEAN_TYPE,
13
24
  "Cheese" => Dummy::CheeseType,
14
25
  "Float" => GraphQL::FLOAT_TYPE,
15
26
  "String" => GraphQL::STRING_TYPE,
@@ -57,9 +68,10 @@ describe GraphQL::Schema::Traversal do
57
68
 
58
69
  result = reduce_types([type_parent])
59
70
  expected = {
71
+ "Boolean" => GraphQL::BOOLEAN_TYPE,
72
+ "String" => GraphQL::STRING_TYPE,
60
73
  "InputTypeParent" => type_parent,
61
74
  "InputTypeChild" => type_child,
62
- "String" => GraphQL::STRING_TYPE
63
75
  }
64
76
  assert_equal(expected, result.to_h)
65
77
  end
@@ -24,28 +24,28 @@ describe GraphQL::StaticValidation::ArgumentsAreDefined do
24
24
 
25
25
  query_root_error = {
26
26
  "message"=>"Field 'cheese' doesn't accept argument 'silly'",
27
- "locations"=>[{"line"=>4, "column"=>7}],
27
+ "locations"=>[{"line"=>4, "column"=>14}],
28
28
  "fields"=>["query getCheese", "cheese", "silly"],
29
29
  }
30
30
  assert_includes(errors, query_root_error)
31
31
 
32
32
  input_obj_record = {
33
33
  "message"=>"InputObject 'DairyProductInput' doesn't accept argument 'wacky'",
34
- "locations"=>[{"line"=>5, "column"=>29}],
34
+ "locations"=>[{"line"=>5, "column"=>30}],
35
35
  "fields"=>["query getCheese", "searchDairy", "product", "wacky"],
36
36
  }
37
37
  assert_includes(errors, input_obj_record)
38
38
 
39
39
  fragment_error = {
40
40
  "message"=>"Field 'similarCheese' doesn't accept argument 'nonsense'",
41
- "locations"=>[{"line"=>9, "column"=>7}],
41
+ "locations"=>[{"line"=>9, "column"=>36}],
42
42
  "fields"=>["fragment cheeseFields", "similarCheese", "nonsense"],
43
43
  }
44
44
  assert_includes(errors, fragment_error)
45
45
 
46
46
  directive_error = {
47
47
  "message"=>"Directive 'skip' doesn't accept argument 'something'",
48
- "locations"=>[{"line"=>10, "column"=>10}],
48
+ "locations"=>[{"line"=>10, "column"=>16}],
49
49
  "fields"=>["fragment cheeseFields", "id", "something"],
50
50
  }
51
51
  assert_includes(errors, directive_error)
@@ -61,7 +61,7 @@ describe GraphQL::StaticValidation::ArgumentsAreDefined do
61
61
  it "finds undefined arguments" do
62
62
  assert_includes(errors, {
63
63
  "message"=>"Field '__type' doesn't accept argument 'somethingInvalid'",
64
- "locations"=>[{"line"=>3, "column"=>9}],
64
+ "locations"=>[{"line"=>3, "column"=>16}],
65
65
  "fields"=>["query", "__type", "somethingInvalid"],
66
66
  })
67
67
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ require "spec_helper"
3
+
4
+ describe 'Rails dependency sanity check' do
5
+ if rails_should_be_installed?
6
+ it "should have rails installed" do
7
+ assert defined?(Rails)
8
+ end
9
+ else
10
+ it "should not have rails installed" do
11
+ refute defined?(Rails)
12
+ end
13
+ end
14
+ end
@@ -1,13 +1,22 @@
1
1
  # frozen_string_literal: true
2
+
3
+ def rails_should_be_installed?
4
+ ENV['WITHOUT_RAILS'] != 'yes'
5
+ end
2
6
  require "codeclimate-test-reporter"
3
7
  CodeClimate::TestReporter.start
4
- require "rake"
5
- require "rails/all"
6
- require "rails/generators"
7
- require "jdbc/sqlite3" if RUBY_ENGINE == 'jruby'
8
- require "sqlite3" if RUBY_ENGINE == 'ruby'
9
- require "pg" if RUBY_ENGINE == 'ruby'
10
- require "sequel"
8
+
9
+ if rails_should_be_installed?
10
+ require "rake"
11
+ require "rails/all"
12
+ require "rails/generators"
13
+
14
+ require "jdbc/sqlite3" if RUBY_ENGINE == 'jruby'
15
+ require "sqlite3" if RUBY_ENGINE == 'ruby'
16
+ require "pg" if RUBY_ENGINE == 'ruby'
17
+ require "sequel"
18
+ end
19
+
11
20
  require "graphql"
12
21
  require "graphql/rake_task"
13
22
  require "benchmark"
@@ -45,8 +54,15 @@ end
45
54
  NO_OP_RESOLVE_TYPE = ->(type, obj, ctx) {
46
55
  raise "this should never be called"
47
56
  }
57
+
48
58
  # Load support files
49
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
59
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each do |f|
60
+ unless rails_should_be_installed?
61
+ next if f.end_with?('star_wars/data.rb')
62
+ next if f.end_with?('base_generator_test.rb')
63
+ end
64
+ require f
65
+ end
50
66
 
51
67
  def star_wars_query(string, variables={}, context: {})
52
68
  GraphQL::Query.new(StarWars::Schema, string, variables: variables, context: context).result
@@ -39,7 +39,7 @@ module StarWars
39
39
 
40
40
  ActiveRecord::Schema.define do
41
41
  self.verbose = false
42
- create_table :bases do |t|
42
+ create_table :bases, force: true do |t|
43
43
  t.column :name, :string
44
44
  t.column :planet, :string
45
45
  t.column :faction_id, :integer
@@ -167,6 +167,10 @@ module StarWars
167
167
  resolve ->(object, args, context) { Base.all.to_a }
168
168
  end
169
169
 
170
+ connection :basesWithLargeMaxLimitRelation, BaseType.connection_type, max_page_size: 1000 do
171
+ resolve ->(object, args, context) { Base.all }
172
+ end
173
+
170
174
  connection :basesAsSequelDataset, BaseConnectionWithTotalCountType, max_page_size: 1000 do
171
175
  argument :nameIncludes, types.String
172
176
  resolve ->(obj, args, ctx) {
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.7
4
+ version: 1.6.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Mosolgo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-11 00:00:00.000000000 Z
11
+ date: 2017-09-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: benchmark-ips
@@ -192,20 +192,6 @@ dependencies:
192
192
  - - "~>"
193
193
  - !ruby/object:Gem::Version
194
194
  version: '1.4'
195
- - !ruby/object:Gem::Dependency
196
- name: rails
197
- requirement: !ruby/object:Gem::Requirement
198
- requirements:
199
- - - ">="
200
- - !ruby/object:Gem::Version
201
- version: '0'
202
- type: :development
203
- prerelease: false
204
- version_requirements: !ruby/object:Gem::Requirement
205
- requirements:
206
- - - ">="
207
- - !ruby/object:Gem::Version
208
- version: '0'
209
195
  - !ruby/object:Gem::Dependency
210
196
  name: rake
211
197
  requirement: !ruby/object:Gem::Requirement
@@ -639,6 +625,7 @@ files:
639
625
  - spec/graphql/static_validation/validator_spec.rb
640
626
  - spec/graphql/string_type_spec.rb
641
627
  - spec/graphql/union_type_spec.rb
628
+ - spec/rails_dependency_sanity_spec.rb
642
629
  - spec/spec_helper.rb
643
630
  - spec/support/base_generator_test.rb
644
631
  - spec/support/dummy/data.rb
@@ -793,6 +780,7 @@ test_files:
793
780
  - spec/graphql/static_validation/validator_spec.rb
794
781
  - spec/graphql/string_type_spec.rb
795
782
  - spec/graphql/union_type_spec.rb
783
+ - spec/rails_dependency_sanity_spec.rb
796
784
  - spec/spec_helper.rb
797
785
  - spec/support/base_generator_test.rb
798
786
  - spec/support/dummy/data.rb