graphql 1.7.14 → 1.8.0.pre1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. checksums.yaml +5 -5
  2. data/lib/generators/graphql/function_generator.rb +1 -1
  3. data/lib/generators/graphql/loader_generator.rb +1 -1
  4. data/lib/generators/graphql/mutation_generator.rb +1 -6
  5. data/lib/generators/graphql/templates/function.erb +2 -2
  6. data/lib/generators/graphql/templates/loader.erb +2 -2
  7. data/lib/graphql.rb +2 -0
  8. data/lib/graphql/argument.rb +0 -1
  9. data/lib/graphql/backwards_compatibility.rb +2 -3
  10. data/lib/graphql/base_type.rb +18 -16
  11. data/lib/graphql/compatibility/query_parser_specification.rb +0 -117
  12. data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -14
  13. data/lib/graphql/define/assign_object_field.rb +5 -12
  14. data/lib/graphql/deprecated_dsl.rb +28 -0
  15. data/lib/graphql/directive.rb +0 -1
  16. data/lib/graphql/enum_type.rb +1 -3
  17. data/lib/graphql/execution.rb +0 -1
  18. data/lib/graphql/execution/multiplex.rb +29 -12
  19. data/lib/graphql/field.rb +5 -20
  20. data/lib/graphql/function.rb +12 -0
  21. data/lib/graphql/input_object_type.rb +1 -3
  22. data/lib/graphql/internal_representation/node.rb +14 -26
  23. data/lib/graphql/internal_representation/visit.rb +6 -3
  24. data/lib/graphql/introspection/arguments_field.rb +0 -1
  25. data/lib/graphql/introspection/enum_values_field.rb +0 -1
  26. data/lib/graphql/introspection/fields_field.rb +0 -1
  27. data/lib/graphql/introspection/input_fields_field.rb +0 -1
  28. data/lib/graphql/introspection/interfaces_field.rb +0 -1
  29. data/lib/graphql/introspection/of_type_field.rb +0 -1
  30. data/lib/graphql/introspection/possible_types_field.rb +0 -1
  31. data/lib/graphql/introspection/schema_field.rb +0 -1
  32. data/lib/graphql/introspection/type_by_name_field.rb +0 -1
  33. data/lib/graphql/introspection/typename_field.rb +0 -1
  34. data/lib/graphql/language.rb +0 -3
  35. data/lib/graphql/language/generation.rb +182 -3
  36. data/lib/graphql/language/lexer.rb +69 -144
  37. data/lib/graphql/language/lexer.rl +4 -15
  38. data/lib/graphql/language/nodes.rb +76 -136
  39. data/lib/graphql/language/parser.rb +621 -668
  40. data/lib/graphql/language/parser.y +11 -17
  41. data/lib/graphql/language/token.rb +3 -10
  42. data/lib/graphql/object_type.rb +6 -1
  43. data/lib/graphql/query.rb +13 -8
  44. data/lib/graphql/query/arguments.rb +33 -48
  45. data/lib/graphql/query/context.rb +1 -0
  46. data/lib/graphql/query/literal_input.rb +1 -4
  47. data/lib/graphql/relay/connection_resolve.rb +3 -0
  48. data/lib/graphql/relay/global_id_resolve.rb +5 -1
  49. data/lib/graphql/relay/relation_connection.rb +19 -14
  50. data/lib/graphql/schema.rb +219 -12
  51. data/lib/graphql/schema/argument.rb +33 -0
  52. data/lib/graphql/schema/build_from_definition.rb +18 -64
  53. data/lib/graphql/schema/enum.rb +76 -0
  54. data/lib/graphql/schema/field.rb +127 -0
  55. data/lib/graphql/schema/field/dynamic_resolve.rb +63 -0
  56. data/lib/graphql/schema/field/unwrapped_resolve.rb +20 -0
  57. data/lib/graphql/schema/input_object.rb +61 -0
  58. data/lib/graphql/schema/interface.rb +32 -0
  59. data/lib/graphql/schema/loader.rb +2 -2
  60. data/lib/graphql/schema/member.rb +97 -0
  61. data/lib/graphql/schema/member/build_type.rb +106 -0
  62. data/lib/graphql/schema/member/has_fields.rb +56 -0
  63. data/lib/graphql/schema/member/instrumentation.rb +113 -0
  64. data/lib/graphql/schema/member/list_type_proxy.rb +21 -0
  65. data/lib/graphql/schema/member/non_null_type_proxy.rb +21 -0
  66. data/lib/graphql/schema/object.rb +65 -0
  67. data/lib/graphql/schema/printer.rb +266 -33
  68. data/lib/graphql/schema/scalar.rb +25 -0
  69. data/lib/graphql/schema/traversal.rb +26 -17
  70. data/lib/graphql/schema/union.rb +48 -0
  71. data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +1 -5
  72. data/lib/graphql/static_validation/rules/fields_will_merge.rb +8 -15
  73. data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +1 -11
  74. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +5 -7
  75. data/lib/graphql/tracing.rb +0 -1
  76. data/lib/graphql/tracing/platform_tracing.rb +7 -20
  77. data/lib/graphql/tracing/scout_tracing.rb +2 -2
  78. data/lib/graphql/unresolved_type_error.rb +2 -3
  79. data/lib/graphql/version.rb +1 -1
  80. data/readme.md +1 -1
  81. data/spec/dummy/app/channels/graphql_channel.rb +1 -22
  82. data/spec/dummy/log/development.log +0 -239
  83. data/spec/dummy/log/test.log +0 -204
  84. data/spec/dummy/test/system/action_cable_subscription_test.rb +0 -4
  85. data/spec/dummy/tmp/screenshots/failures_test_it_handles_subscriptions.png +0 -0
  86. data/spec/generators/graphql/function_generator_spec.rb +0 -26
  87. data/spec/generators/graphql/loader_generator_spec.rb +0 -24
  88. data/spec/graphql/analysis/max_query_complexity_spec.rb +3 -3
  89. data/spec/graphql/analysis/max_query_depth_spec.rb +3 -3
  90. data/spec/graphql/backtrace_spec.rb +0 -10
  91. data/spec/graphql/base_type_spec.rb +5 -19
  92. data/spec/graphql/boolean_type_spec.rb +3 -3
  93. data/spec/graphql/directive_spec.rb +1 -3
  94. data/spec/graphql/enum_type_spec.rb +5 -18
  95. data/spec/graphql/execution/execute_spec.rb +1 -1
  96. data/spec/graphql/execution/multiplex_spec.rb +2 -2
  97. data/spec/graphql/float_type_spec.rb +2 -2
  98. data/spec/graphql/id_type_spec.rb +1 -1
  99. data/spec/graphql/input_object_type_spec.rb +2 -15
  100. data/spec/graphql/int_type_spec.rb +2 -2
  101. data/spec/graphql/internal_representation/rewrite_spec.rb +2 -2
  102. data/spec/graphql/introspection/schema_type_spec.rb +0 -1
  103. data/spec/graphql/language/generation_spec.rb +186 -21
  104. data/spec/graphql/language/lexer_spec.rb +1 -21
  105. data/spec/graphql/language/nodes_spec.rb +12 -21
  106. data/spec/graphql/language/parser_spec.rb +1 -1
  107. data/spec/graphql/query/arguments_spec.rb +15 -37
  108. data/spec/graphql/query/serial_execution/value_resolution_spec.rb +2 -2
  109. data/spec/graphql/query/variables_spec.rb +1 -1
  110. data/spec/graphql/query_spec.rb +5 -31
  111. data/spec/graphql/rake_task_spec.rb +1 -3
  112. data/spec/graphql/relay/base_connection_spec.rb +1 -1
  113. data/spec/graphql/relay/connection_instrumentation_spec.rb +2 -2
  114. data/spec/graphql/relay/connection_resolve_spec.rb +1 -1
  115. data/spec/graphql/relay/connection_type_spec.rb +1 -1
  116. data/spec/graphql/relay/mutation_spec.rb +3 -3
  117. data/spec/graphql/relay/relation_connection_spec.rb +1 -65
  118. data/spec/graphql/schema/build_from_definition_spec.rb +4 -86
  119. data/spec/graphql/schema/enum_spec.rb +60 -0
  120. data/spec/graphql/schema/field_spec.rb +14 -0
  121. data/spec/graphql/schema/input_object_spec.rb +43 -0
  122. data/spec/graphql/schema/interface_spec.rb +98 -0
  123. data/spec/graphql/schema/object_spec.rb +119 -0
  124. data/spec/graphql/schema/printer_spec.rb +15 -92
  125. data/spec/graphql/schema/scalar_spec.rb +40 -0
  126. data/spec/graphql/schema/union_spec.rb +35 -0
  127. data/spec/graphql/schema/validation_spec.rb +1 -1
  128. data/spec/graphql/schema/warden_spec.rb +11 -11
  129. data/spec/graphql/schema_spec.rb +25 -23
  130. data/spec/graphql/static_validation/rules/fields_have_appropriate_selections_spec.rb +2 -10
  131. data/spec/graphql/static_validation/rules/fields_will_merge_spec.rb +2 -2
  132. data/spec/graphql/string_type_spec.rb +3 -3
  133. data/spec/graphql/subscriptions_spec.rb +1 -1
  134. data/spec/graphql/tracing/platform_tracing_spec.rb +1 -60
  135. data/spec/support/dummy/schema.rb +25 -39
  136. data/spec/support/jazz.rb +334 -0
  137. data/spec/support/lazy_helpers.rb +21 -23
  138. data/spec/support/star_wars/data.rb +7 -6
  139. data/spec/support/star_wars/schema.rb +109 -142
  140. metadata +39 -33
  141. data/lib/graphql/execution/instrumentation.rb +0 -82
  142. data/lib/graphql/language/block_string.rb +0 -47
  143. data/lib/graphql/language/document_from_schema_definition.rb +0 -277
  144. data/lib/graphql/language/printer.rb +0 -351
  145. data/lib/graphql/tracing/data_dog_tracing.rb +0 -49
  146. data/spec/graphql/execution/instrumentation_spec.rb +0 -165
  147. data/spec/graphql/language/block_string_spec.rb +0 -70
  148. data/spec/graphql/language/document_from_schema_definition_spec.rb +0 -770
  149. data/spec/graphql/language/printer_spec.rb +0 -203
@@ -82,7 +82,8 @@ rule
82
82
  | EQUALS literal_value { return val[1] }
83
83
 
84
84
  selection_set:
85
- LCURLY selection_list RCURLY { return val[1] }
85
+ LCURLY RCURLY { return [] }
86
+ | LCURLY selection_list RCURLY { return val[1] }
86
87
 
87
88
  selection_set_opt:
88
89
  /* none */ { return [] }
@@ -152,8 +153,12 @@ rule
152
153
  | operation_type
153
154
  | schema_keyword
154
155
 
156
+ name_list:
157
+ name { return [make_node(:TypeName, name: val[0])] }
158
+ | name_list name { val[0] << make_node(:TypeName, name: val[1]) }
159
+
155
160
  enum_value_definition:
156
- enum_name directives_list_opt { return make_node(:EnumValueDefinition, name: val[0], directives: val[1], description: get_description(val[0]), position_source: val[0]) }
161
+ enum_name directives_list_opt { return make_node(:EnumValueDefinition, name: val[0], directives: val[1], description: get_description(val[0])) }
157
162
 
158
163
  enum_value_definitions:
159
164
  enum_value_definition { return [val[0]] }
@@ -302,21 +307,11 @@ rule
302
307
 
303
308
  implements_opt:
304
309
  /* none */ { return [] }
305
- | IMPLEMENTS AMP interfaces_list { return val[2] }
306
- | IMPLEMENTS interfaces_list { return val[1] }
307
- | IMPLEMENTS legacy_interfaces_list { return val[1] }
308
-
309
- interfaces_list:
310
- name { return [make_node(:TypeName, name: val[0], position_source: val[0])] }
311
- | interfaces_list AMP name { val[0] << make_node(:TypeName, name: val[2], position_source: val[2]) }
312
-
313
- legacy_interfaces_list:
314
- name { return [make_node(:TypeName, name: val[0], position_source: val[0])] }
315
- | legacy_interfaces_list name { val[0] << make_node(:TypeName, name: val[1], position_source: val[1]) }
310
+ | IMPLEMENTS name_list { return val[1] }
316
311
 
317
312
  input_value_definition:
318
313
  name COLON type default_value_opt directives_list_opt {
319
- return make_node(:InputValueDefinition, name: val[0], type: val[2], default_value: val[3], directives: val[4], description: get_description(val[0]), position_source: val[0])
314
+ return make_node(:InputValueDefinition, name: val[0], type: val[2], default_value: val[3], directives: val[4], description: get_description(val[0]))
320
315
  }
321
316
 
322
317
  input_value_definition_list:
@@ -329,12 +324,11 @@ rule
329
324
 
330
325
  field_definition:
331
326
  name arguments_definitions_opt COLON type directives_list_opt {
332
- return make_node(:FieldDefinition, name: val[0], arguments: val[1], type: val[3], directives: val[4], description: get_description(val[0]), position_source: val[0])
327
+ return make_node(:FieldDefinition, name: val[0], arguments: val[1], type: val[3], directives: val[4], description: get_description(val[0]))
333
328
  }
334
329
 
335
330
  field_definition_list:
336
- /* none */ { return [] }
337
- | field_definition { return [val[0]] }
331
+ field_definition { return [val[0]] }
338
332
  | field_definition_list field_definition { val[0] << val[1] }
339
333
 
340
334
  interface_type_definition:
@@ -5,30 +5,23 @@ module GraphQL
5
5
  # Contains type, value and position data.
6
6
  class Token
7
7
  # @return [Symbol] The kind of token this is
8
- attr_reader :name
9
- # @return [String] The text of this token
10
- attr_reader :value
11
- attr_reader :prev_token, :line, :col
8
+ attr_reader :name, :prev_token, :line
12
9
 
13
10
  def initialize(value:, name:, line:, col:, prev_token:)
14
11
  @name = name
15
- @value = value.freeze
12
+ @value = value
16
13
  @line = line
17
14
  @col = col
18
15
  @prev_token = prev_token
19
16
  end
20
17
 
21
- alias to_s value
18
+ def to_s; @value; end
22
19
  def to_i; @value.to_i; end
23
20
  def to_f; @value.to_f; end
24
21
 
25
22
  def line_and_column
26
23
  [@line, @col]
27
24
  end
28
-
29
- def inspect
30
- "(#{@name} #{@value.inspect} [#{@line}:#{@col}])"
31
- end
32
25
  end
33
26
  end
34
27
  end
@@ -32,7 +32,7 @@ module GraphQL
32
32
  # @return [Hash<String => GraphQL::Field>] Map String fieldnames to their {GraphQL::Field} implementations
33
33
 
34
34
  # @!attribute mutation
35
- # @return [GraphQL::Relay::Mutation, nil] The mutation this object type was derived from, if it is an auto-generated payload type.
35
+ # @return [GraphQL::Relay::Mutation, nil] The mutation this field was derived from, if it was derived from a mutation
36
36
 
37
37
  def initialize
38
38
  super
@@ -102,6 +102,11 @@ module GraphQL
102
102
  dirty_ifaces.concat(interfaces)
103
103
  end
104
104
 
105
+ def name=(name)
106
+ GraphQL::NameValidator.validate!(name)
107
+ @name = name
108
+ end
109
+
105
110
  protected
106
111
 
107
112
  attr_reader :dirty_interfaces, :dirty_inherited_interfaces
data/lib/graphql/query.rb CHANGED
@@ -29,7 +29,10 @@ module GraphQL
29
29
  end
30
30
  end
31
31
 
32
- attr_reader :schema, :context, :root_value, :warden, :provided_variables
32
+ attr_reader :schema, :context, :warden, :provided_variables
33
+
34
+ # The value for root types
35
+ attr_accessor :root_value
33
36
 
34
37
  # @return [nil, String] The operation name provided by client or the one inferred from the document. Used to determine which operation to run.
35
38
  attr_accessor :operation_name
@@ -44,10 +47,6 @@ module GraphQL
44
47
  with_prepared_ast { @document }
45
48
  end
46
49
 
47
- def inspect
48
- "query ..."
49
- end
50
-
51
50
  # @return [String, nil] The name of the operation to run (may be inferred)
52
51
  def selected_operation_name
53
52
  return nil unless selected_operation
@@ -157,7 +156,7 @@ module GraphQL
157
156
  def result
158
157
  if !@executed
159
158
  with_prepared_ast {
160
- Execution::Multiplex.run_queries(@schema, [self], context: @context)
159
+ Execution::Multiplex.run_queries(@schema, [self])
161
160
  }
162
161
  end
163
162
  @result ||= Query::Result.new(query: self, values: @result_values)
@@ -194,8 +193,11 @@ module GraphQL
194
193
 
195
194
  def irep_selection
196
195
  @selection ||= begin
197
- return nil unless selected_operation
198
- internal_representation.operation_definitions[selected_operation.name]
196
+ if selected_operation && internal_representation
197
+ internal_representation.operation_definitions[selected_operation.name]
198
+ else
199
+ nil
200
+ end
199
201
  end
200
202
  end
201
203
 
@@ -238,6 +240,9 @@ module GraphQL
238
240
  value = abstract_type
239
241
  abstract_type = nil
240
242
  end
243
+ if value.is_a?(GraphQL::Schema::Object)
244
+ value = value.object
245
+ end
241
246
  @resolved_types_cache[abstract_type][value]
242
247
  end
243
248
 
@@ -12,40 +12,36 @@ module GraphQL
12
12
  argument_owner.arguments_class = Class.new(self) do
13
13
  self.argument_definitions = argument_definitions
14
14
 
15
- def initialize(values, defaults_used)
16
- super(values, argument_definitions: self.class.argument_definitions, defaults_used: defaults_used)
17
- end
18
-
19
15
  argument_definitions.each do |_arg_name, arg_definition|
20
16
  expose_as = arg_definition.expose_as.to_s
21
-
22
- # Don't define a helper method if it would override something.
23
- if instance_methods.include?(expose_as)
24
- warn(
25
- "Unable to define a helper for argument with name '#{expose_as}' "\
26
- "as this is a reserved name. If you're using an argument such as "\
27
- "`argument #{expose_as}`, consider renaming this argument.`"
28
- )
29
- next
30
- end
31
-
32
- define_method(expose_as) do
33
- self[expose_as]
17
+ expose_as_underscored = GraphQL::Schema::Member::BuildType.underscore(expose_as)
18
+ method_names = [expose_as, expose_as_underscored].uniq
19
+ method_names.each do |method_name|
20
+ # Don't define a helper method if it would override something.
21
+ if instance_methods.include?(method_name)
22
+ warn(
23
+ "Unable to define a helper for argument with name '#{method_name}' "\
24
+ "as this is a reserved name. If you're using an argument such as "\
25
+ "`argument #{method_name}`, consider renaming this argument.`"
26
+ )
27
+ else
28
+ define_method(method_name) do
29
+ # Always use `expose_as` here, since #[] doesn't accept underscored names
30
+ self[expose_as]
31
+ end
32
+ end
34
33
  end
35
34
  end
36
35
  end
37
36
  end
38
37
 
39
- def initialize(values, argument_definitions:, defaults_used:)
38
+ def initialize(values, context:)
40
39
  @argument_values = values.inject({}) do |memo, (inner_key, inner_value)|
41
- arg_name = inner_key.to_s
40
+ arg_defn = self.class.argument_definitions[inner_key.to_s]
42
41
 
43
- arg_defn = argument_definitions[arg_name]
44
- arg_default_used = defaults_used.include?(arg_name)
45
-
46
- arg_value = wrap_value(inner_value, arg_defn.type)
42
+ arg_value = wrap_value(inner_value, arg_defn.type, context)
47
43
  string_key = arg_defn.expose_as
48
- memo[string_key] = ArgumentValue.new(string_key, arg_value, arg_defn, arg_default_used)
44
+ memo[string_key] = ArgumentValue.new(string_key, arg_value, arg_defn)
49
45
  memo
50
46
  end
51
47
  end
@@ -64,13 +60,6 @@ module GraphQL
64
60
  @argument_values.key?(key_s)
65
61
  end
66
62
 
67
- # @param key [String, Symbol] name of value to access
68
- # @return [Boolean] true if the argument default was passed as the argument value to the resolver
69
- def default_used?(key)
70
- key_s = key.is_a?(String) ? key : key.to_s
71
- @argument_values.fetch(key_s, NULL_ARGUMENT_VALUE).default_used?
72
- end
73
-
74
63
  # Get the hash of all values, with stringified keys
75
64
  # @return [Hash] the stringified hash
76
65
  def to_h
@@ -84,7 +73,7 @@ module GraphQL
84
73
  end
85
74
  end
86
75
 
87
- def_delegators :to_h, :keys, :values, :each
76
+ def_delegators :to_h, :keys, :values, :each, :any?
88
77
 
89
78
  # Access each key, value and type for the arguments in this set.
90
79
  # @yield [argument_value] The {ArgumentValue} for each argument
@@ -95,45 +84,41 @@ module GraphQL
95
84
  end
96
85
  end
97
86
 
98
- NO_ARGS = self.new({}, argument_definitions: [], defaults_used: Set.new)
99
-
100
87
  class << self
101
88
  attr_accessor :argument_definitions
102
89
  end
103
90
 
91
+ NoArguments = Class.new(self) do
92
+ self.argument_definitions = []
93
+ end
94
+
95
+ NO_ARGS = NoArguments.new({}, context: nil)
96
+
104
97
  private
105
98
 
106
99
  class ArgumentValue
107
100
  attr_reader :key, :value, :definition
108
- attr_writer :default_used
109
-
110
- def initialize(key, value, definition, default_used)
101
+ def initialize(key, value, definition)
111
102
  @key = key
112
103
  @value = value
113
104
  @definition = definition
114
- @default_used = default_used
115
- end
116
-
117
- # @return [Boolean] true if the argument default was passed as the argument value to the resolver
118
- def default_used?
119
- @default_used
120
105
  end
121
106
  end
122
107
 
123
- NULL_ARGUMENT_VALUE = ArgumentValue.new(nil, nil, nil, nil)
108
+ NULL_ARGUMENT_VALUE = ArgumentValue.new(nil, nil, nil)
124
109
 
125
- def wrap_value(value, arg_defn_type)
110
+ def wrap_value(value, arg_defn_type, context)
126
111
  if value.nil?
127
112
  nil
128
113
  else
129
114
  case arg_defn_type
130
115
  when GraphQL::ListType
131
- value.map { |item| wrap_value(item, arg_defn_type.of_type) }
116
+ value.map { |item| wrap_value(item, arg_defn_type.of_type, context) }
132
117
  when GraphQL::NonNullType
133
- wrap_value(value, arg_defn_type.of_type)
118
+ wrap_value(value, arg_defn_type.of_type, context)
134
119
  when GraphQL::InputObjectType
135
120
  if value.is_a?(Hash)
136
- arg_defn_type.arguments_class.new(value, Set.new)
121
+ arg_defn_type.arguments_class.new(value, context: context)
137
122
  else
138
123
  value
139
124
  end
@@ -129,6 +129,7 @@ module GraphQL
129
129
  attr_writer :value
130
130
 
131
131
  def_delegators :@provided_values, :[], :[]=, :to_h, :key?, :fetch
132
+ def_delegators :@query, :trace
132
133
 
133
134
  # @!method [](key)
134
135
  # Lookup `key` from the hash passed to {Schema#execute} as `context:`
@@ -49,8 +49,6 @@ module GraphQL
49
49
  def self.from_arguments(ast_arguments, argument_owner, variables)
50
50
  context = variables ? variables.context : nil
51
51
  values_hash = {}
52
- defaults_used = Set.new
53
-
54
52
  indexed_arguments = case ast_arguments
55
53
  when Hash
56
54
  ast_arguments
@@ -95,7 +93,6 @@ module GraphQL
95
93
  # then add the default value.
96
94
  if arg_defn.default_value? && !values_hash.key?(arg_name)
97
95
  value = arg_defn.default_value
98
- defaults_used << arg_name
99
96
  # `context` isn't present when pre-calculating defaults
100
97
  if context
101
98
  value = arg_defn.prepare(value, context)
@@ -108,7 +105,7 @@ module GraphQL
108
105
  end
109
106
  end
110
107
 
111
- argument_owner.arguments_class.new(values_hash, defaults_used)
108
+ argument_owner.arguments_class.new(values_hash, context: context)
112
109
  end
113
110
  end
114
111
  end
@@ -41,6 +41,9 @@ module GraphQL
41
41
  ctx.add_error(nodes)
42
42
  nil
43
43
  else
44
+ if parent.is_a?(GraphQL::Schema::Object)
45
+ parent = parent.object
46
+ end
44
47
  connection_class = GraphQL::Relay::BaseConnection.connection_for_nodes(nodes)
45
48
  connection_class.new(nodes, args, field: @field, max_page_size: @max_page_size, parent: parent, context: ctx)
46
49
  end
@@ -7,7 +7,11 @@ module GraphQL
7
7
  end
8
8
 
9
9
  def call(obj, args, ctx)
10
- ctx.query.schema.id_from_object(obj, @type, ctx)
10
+ if obj.is_a?(GraphQL::Schema::Object)
11
+ obj = obj.object
12
+ end
13
+ type = @type.respond_to?(:graphql_definition) ? @type.graphql_definition : @type
14
+ ctx.query.schema.id_from_object(obj, type, ctx)
11
15
  end
12
16
  end
13
17
  end
@@ -7,11 +7,11 @@ module GraphQL
7
7
  # - `Sequel::Dataset`
8
8
  class RelationConnection < BaseConnection
9
9
  def cursor_from_node(item)
10
- item_index = paged_nodes.index(item)
10
+ item_index = paged_nodes_array.index(item)
11
11
  if item_index.nil?
12
12
  raise("Can't generate cursor, item not found in connection: #{item}")
13
13
  else
14
- offset = item_index + 1 + ((paged_nodes_offset || 0) - (relation_offset(sliced_nodes) || 0))
14
+ offset = item_index + 1 + ((relation_offset(paged_nodes) || 0) - (relation_offset(sliced_nodes) || 0))
15
15
 
16
16
  if after
17
17
  offset += offset_from_cursor(after)
@@ -25,9 +25,9 @@ module GraphQL
25
25
 
26
26
  def has_next_page
27
27
  if first
28
- paged_nodes.length >= first && sliced_nodes_count > first
28
+ paged_nodes_length >= first && sliced_nodes_count > first
29
29
  elsif GraphQL::Relay::ConnectionType.bidirectional_pagination && last
30
- sliced_nodes_count >= last
30
+ sliced_nodes_count > last
31
31
  else
32
32
  false
33
33
  end
@@ -35,7 +35,7 @@ module GraphQL
35
35
 
36
36
  def has_previous_page
37
37
  if last
38
- paged_nodes.length >= last && sliced_nodes_count > last
38
+ paged_nodes_length >= last && sliced_nodes_count > last
39
39
  elsif GraphQL::Relay::ConnectionType.bidirectional_pagination && after
40
40
  # We've already paginated through the collection a bit,
41
41
  # there are nodes behind us
@@ -64,7 +64,6 @@ module GraphQL
64
64
  private
65
65
 
66
66
  # apply first / last limit results
67
- # @return [Array]
68
67
  def paged_nodes
69
68
  return @paged_nodes if defined? @paged_nodes
70
69
 
@@ -95,14 +94,7 @@ module GraphQL
95
94
  end
96
95
  end
97
96
 
98
- # Store this here so we can convert the relation to an Array
99
- # (this avoids an extra DB call on Sequel)
100
- @paged_nodes_offset = relation_offset(items)
101
- @paged_nodes = items.to_a
102
- end
103
-
104
- def paged_nodes_offset
105
- paged_nodes && @paged_nodes_offset
97
+ @paged_nodes = items
106
98
  end
107
99
 
108
100
  def relation_offset(relation)
@@ -174,6 +166,19 @@ module GraphQL
174
166
  def offset_from_cursor(cursor)
175
167
  decode(cursor).to_i
176
168
  end
169
+
170
+ def paged_nodes_array
171
+ return @paged_nodes_array if defined?(@paged_nodes_array)
172
+ @paged_nodes_array = paged_nodes.to_a
173
+ end
174
+
175
+ def paged_nodes_length
176
+ if paged_nodes.respond_to?(:length)
177
+ paged_nodes.length
178
+ else
179
+ paged_nodes_array.length
180
+ end
181
+ end
177
182
  end
178
183
 
179
184
  if defined?(ActiveRecord::Relation)