class GraphQL::Pagination::Connection

Pagination arguments and context may be provided at initialization or assigned later (see {Schema::Field::ConnectionExtension}).
Unlike the previous connection implementation, these default to bidirectional pagination.
to serve lists (like Arrays, ActiveRecord::Relations) via GraphQL.
proved to be generally useful for GraphQL APIs. When in doubt, use connections
Connections were introduced by Facebook’s ‘Relay` front-end framework, but
A Connection wraps a list of items and provides cursor-based pagination over it.

def self.edge_class

Returns:
  • (Class) - The class to use for wrapping items as `edges { ... }`. Defaults to `Connection::Edge`
def self.edge_class
  self::Edge
end

def after

Returns:
  • (String, nil) - the client-provided cursor. `""` is treated as `nil`.
def after
  if defined?(@after)
    @after
  else
    @after = @after_value == "" ? nil : @after_value
  end
end

def before

Returns:
  • (String, nil) - the client-provided cursor. `""` is treated as `nil`.
def before
  if defined?(@before)
    @before
  else
    @before = @before_value == "" ? nil : @before_value
  end
end

def cursor_for(item)

Returns:
  • (String) -

Parameters:
  • item (Object) -- one of the passed in {items}, taken from {nodes}
def cursor_for(item)
  raise PaginationImplementationMissingError, "Implement #{self.class}#cursor_for(item) to return the cursor for #{item.inspect}"
end

def decode(cursor)

def decode(cursor)
  context.schema.cursor_encoder.decode(cursor, nonce: true)
end

def edge_nodes

Deprecated:
  • use {#nodes} instead
def edge_nodes
  nodes
end

def edges

Returns:
  • (Array) - {nodes}, but wrapped with Edge instances
def edges
  @edges ||= nodes.map { |n| self.class.edge_class.new(n, self) }
end

def encode(cursor)

def encode(cursor)
  context.schema.cursor_encoder.encode(cursor, nonce: true)
end

def end_cursor

Returns:
  • (String) - The cursor of the last item in {nodes}
def end_cursor
  nodes.last && cursor_for(nodes.last)
end

def first

Returns:
  • (Integer, nil) -
def first
  @first ||= begin
    capped = limit_pagination_argument(@first_value, max_page_size)
    if capped.nil? && last.nil?
      capped = max_page_size
    end
    capped
  end
end

def has_max_page_size_override?

def has_max_page_size_override?
  @has_max_page_size_override
end

def has_next_page

Returns:
  • (Boolean) - True if there are more items after this page
def has_next_page
  raise PaginationImplementationMissingError, "Implement #{self.class}#has_next_page to return the next-page check"
end

def has_previous_page

Returns:
  • (Boolean) - True if there were items before these items
def has_previous_page
  raise PaginationImplementationMissingError, "Implement #{self.class}#has_previous_page to return the previous-page check"
end

def initialize(items, context: nil, first: nil, after: nil, max_page_size: :not_given, last: nil, before: nil)

Parameters:
  • max_page_size (Integer, nil) -- A configured value to cap the result size. Applied as `first` if neither first or last are given.
  • before (String, nil) -- A cursor for pagination, if the client provided one.
  • last (Integer, nil) -- Limit parameter from the client, if provided
  • after (String, nil) -- A cursor for pagination, if the client provided one
  • first (Integer, nil) -- The limit parameter from the client, if it provided one
  • context (Query::Context) --
  • items (Object) -- some unpaginated collection item, like an `Array` or `ActiveRecord::Relation`
def initialize(items, context: nil, first: nil, after: nil, max_page_size: :not_given, last: nil, before: nil)
  @items = items
  @context = context
  @first_value = first
  @after_value = after
  @last_value = last
  @before_value = before
  # This is only true if the object was _initialized_ with an override
  # or if one is assigned later.
  @has_max_page_size_override = max_page_size != :not_given
  @max_page_size = if max_page_size == :not_given
    nil
  else
    max_page_size
  end
end

def last

Returns:
  • (Integer, nil) - A clamped `last` value. (The underlying instance variable doesn't have limits on it)
def last
  @last ||= limit_pagination_argument(@last_value, max_page_size)
end

def limit_pagination_argument(argument, max_page_size)

Returns:
  • (nil, Integer) - `nil` if the input was `nil`, otherwise a value between `0` and `max_page_size`

Parameters:
  • max_page_size (nil, Integer) --
  • argument (nil, Integer) -- `first` or `last`, as provided by the client
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

def max_page_size

def max_page_size
  if @has_max_page_size_override
    @max_page_size
  else
    context.schema.default_max_page_size
  end
end

def max_page_size=(new_value)

def max_page_size=(new_value)
  @has_max_page_size_override = true
  @max_page_size = new_value
end

def nodes

Returns:
  • (Array) - A slice of {items}, constrained by {@first_value}/{@after_value}/{@last_value}/{@before_value}
    def nodes
      raise PaginationImplementationMissingError, "Implement #{self.class}#nodes to paginate `@items`"
    end

    def page_info

    The connection object itself implements `PageInfo` fields
    def page_info
      self
    end

    def start_cursor

    Returns:
    • (String) - The cursor of the first item in {nodes}
    def start_cursor
      nodes.first && cursor_for(nodes.first)
    end