class GraphQL::Relay::BaseConnection

Subclasses must implement:

- {#cursor_from_node}, which returns an opaque cursor for the given item
- {#sliced_nodes}, which slices by `before` & `after`
- {#paged_nodes}, which applies `first` & `last` limits

In a subclass, you have access to

- {#nodes}, the collection which the connection will wrap
- {#first}, {#after}, {#last}, {#before} (arguments passed to the field)
- {#max_page_size} (the specified maximum page size that can be returned from a connection)

Constants

CONNECTION_IMPLEMENTATIONS

Map of collection class names -> connection_classes eg `{“Array” => ArrayConnection}`

CURSOR_SEPARATOR

Just to encode data in the cursor, use something that won't conflict

Attributes

arguments[R]
context[R]
field[R]
max_page_size[R]
nodes[R]
parent[R]

Public Class Methods

connection_for_nodes(nodes) click to toggle source

Find a connection implementation suitable for exposing `nodes`

@param nodes [Object] A collection of nodes (eg, Array, AR::Relation) @return [subclass of BaseConnection] a connection Class for wrapping `nodes`

# File lib/graphql/relay/base_connection.rb, line 27
def connection_for_nodes(nodes)
  # If it's a new-style connection object, it's already ready to go
  if nodes.is_a?(GraphQL::Pagination::Connection)
    return nodes
  end
  # Check for class _names_ because classes can be redefined in Rails development
  nodes.class.ancestors.each do |ancestor|
    conn_impl = CONNECTION_IMPLEMENTATIONS[ancestor.name]
    if conn_impl
      return conn_impl
    end
  end
  # Should have found a connection during the loop:
  raise("No connection implementation to wrap #{nodes.class} (#{nodes})")
end
new(nodes, arguments, field: nil, max_page_size: nil, parent: nil, context: nil) click to toggle source

Make a connection, wrapping `nodes` @param nodes [Object] The collection of nodes @param arguments [GraphQL::Query::Arguments] Query arguments @param field [GraphQL::Field] The underlying field @param max_page_size [Int] The maximum number of results to return @param parent [Object] The object which this collection belongs to @param context [GraphQL::Query::Context] The context from the field being resolved

# File lib/graphql/relay/base_connection.rb, line 61
def initialize(nodes, arguments, field: nil, max_page_size: nil, parent: nil, context: nil)
  GraphQL::Deprecation.warn "GraphQL::Relay::BaseConnection (used for #{self.class}) will be removed from GraphQL-Ruby 2.0, use GraphQL::Pagination::Connections instead: https://graphql-ruby.org/pagination/overview.html"

  deprecated_caller = caller(0, 10).find { |c| !c.include?("lib/graphql") }
  if deprecated_caller
    GraphQL::Deprecation.warn "  -> called from #{deprecated_caller}"
  end

  @context = context
  @nodes = nodes
  @arguments = arguments
  @field = field
  @parent = parent
  @encoder = context ? @context.schema.cursor_encoder : GraphQL::Schema::Base64Encoder
  @max_page_size = max_page_size.nil? && context ? @context.schema.default_max_page_size : max_page_size
end
register_connection_implementation(nodes_class, connection_class) click to toggle source

Add `connection_class` as the connection wrapper for `nodes_class` eg, `RelationConnection` is the implementation for `AR::Relation` @param nodes_class [Class] A class representing a collection (eg, Array, AR::Relation) @param connection_class [Class] A class implementing Connection methods

# File lib/graphql/relay/base_connection.rb, line 47
def register_connection_implementation(nodes_class, connection_class)
  CONNECTION_IMPLEMENTATIONS[nodes_class.name] = connection_class
end

Public Instance Methods

after() click to toggle source

The value passed as `after:`, if there was one @return [String, nil]

# File lib/graphql/relay/base_connection.rb, line 100
def after
  arguments[:after]
end
before() click to toggle source

The value passed as `before:`, if there was one @return [String, nil]

# File lib/graphql/relay/base_connection.rb, line 112
def before
  arguments[:before]
end
cursor_from_node(object) click to toggle source

An opaque operation which returns a connection-specific cursor.

# File lib/graphql/relay/base_connection.rb, line 156
def cursor_from_node(object)
  raise GraphQL::RequiredImplementationMissingError, "must return a cursor for this object/connection pair"
end
decode(data) click to toggle source
# File lib/graphql/relay/base_connection.rb, line 82
def decode(data)
  @encoder.decode(data, nonce: true)
end
edge_nodes() click to toggle source

These are the nodes to render for this connection, probably wrapped by {GraphQL::Relay::Edge}

# File lib/graphql/relay/base_connection.rb, line 118
def edge_nodes
  @edge_nodes ||= paged_nodes
end
encode(data) click to toggle source
# File lib/graphql/relay/base_connection.rb, line 78
def encode(data)
  @encoder.encode(data, nonce: true)
end
end_cursor() click to toggle source

Used by `pageInfo`

# File lib/graphql/relay/base_connection.rb, line 147
def end_cursor
  if end_node = (respond_to?(:paged_nodes_array, true) ? paged_nodes_array : paged_nodes).last
    return cursor_from_node(end_node)
  else
    return nil
  end
end
first() click to toggle source

The value passed as `first:`, if there was one. Negative numbers become `0`. @return [Integer, nil]

# File lib/graphql/relay/base_connection.rb, line 88
def first
  @first ||= begin
    capped = limit_pagination_argument(arguments[:first], max_page_size)
    if capped.nil? && last.nil?
      capped = max_page_size
    end
    capped
  end
end
has_next_page() click to toggle source

Used by `pageInfo`

# File lib/graphql/relay/base_connection.rb, line 128
def has_next_page
  !!(first && sliced_nodes.count > first)
end
has_previous_page() click to toggle source

Used by `pageInfo`

# File lib/graphql/relay/base_connection.rb, line 133
def has_previous_page
  !!(last && sliced_nodes.count > last)
end
inspect() click to toggle source
# File lib/graphql/relay/base_connection.rb, line 160
def inspect
  "#<GraphQL::Relay::Connection @parent=#{@parent.inspect} @arguments=#{@arguments.to_h.inspect}>"
end
last() click to toggle source

The value passed as `last:`, if there was one. Negative numbers become `0`. @return [Integer, nil]

# File lib/graphql/relay/base_connection.rb, line 106
def last
  @last ||= limit_pagination_argument(arguments[:last], max_page_size)
end
page_info() click to toggle source

Support the `pageInfo` field

# File lib/graphql/relay/base_connection.rb, line 123
def page_info
  self
end
start_cursor() click to toggle source

Used by `pageInfo`

# File lib/graphql/relay/base_connection.rb, line 138
def start_cursor
  if start_node = (respond_to?(:paged_nodes_array, true) ? paged_nodes_array : paged_nodes).first
    return cursor_from_node(start_node)
  else
    return nil
  end
end

Private Instance Methods

limit_pagination_argument(argument, max_page_size) click to toggle source

@param argument [nil, Integer] `first` or `last`, as provided by the client @param max_page_size [nil, Integer] @return [nil, Integer] `nil` if the input was `nil`, otherwise a value between `0` and `max_page_size`

# File lib/graphql/relay/base_connection.rb, line 169
def limit_pagination_argument(argument, max_page_size)
  if argument
    if argument < 0
      argument = 0
    elsif max_page_size && argument > max_page_size
      argument = max_page_size
    end
  end
  argument
end
paged_nodes() click to toggle source
# File lib/graphql/relay/base_connection.rb, line 180
def paged_nodes
  raise GraphQL::RequiredImplementationMissingError, "must return nodes for this connection after paging"
end
sliced_nodes() click to toggle source
# File lib/graphql/relay/base_connection.rb, line 184
def sliced_nodes
  raise GraphQL::RequiredImplementationMissingError, "must return  all nodes for this connection after chopping off first and last"
end