class GraphQL::Pagination::Connection
A Connection
wraps a list of items and provides cursor-based pagination over it.
Connections
were introduced by Facebook’s ‘Relay` front-end framework, but proved to be generally useful for GraphQL
APIs. When in doubt, use connections to serve lists (like Arrays, ActiveRecord::Relations) via GraphQL
.
Unlike the previous connection implementation, these default to bidirectional pagination.
Pagination
arguments and context may be provided at initialization or assigned later (see {Schema::Field::ConnectionExtension}).
Attributes
Raw access to client-provided values. (‘max_page_size` not applied to first or last.)
@return [Hash<Symbol => Object>] The field arguments from the field that returned this connection
Raw access to client-provided values. (‘max_page_size` not applied to first or last.)
@return [GraphQL::Query::Context]
@return [Class] A wrapper class for edges of this connection
@return [GraphQL::Schema::Field] The field this connection was returned by
Raw access to client-provided values. (‘max_page_size` not applied to first or last.)
@return [Object] A list object, from the application. This is the unpaginated value passed into the connection.
Raw access to client-provided values. (‘max_page_size` not applied to first or last.)
@return [Object] the object this collection belongs to
Public Class Methods
@param items [Object] some unpaginated collection item, like an ‘Array` or `ActiveRecord::Relation` @param context [Query::Context] @param parent [Object] The object this collection belongs to @param first [Integer, nil] The limit parameter from the client, if it provided one @param after [String, nil] A cursor for pagination, if the client provided one @param last [Integer, nil] Limit parameter from the client, if provided @param before [String, nil] A cursor for pagination, if the client provided one. @param arguments [Hash] The arguments to the field that returned the collection wrapped by this connection @param max_page_size
[Integer, nil] A configured value to cap the result size. Applied as `first` if neither first or last are given and no `default_page_size` is set. @param default_page_size
[Integer, nil] A configured value to determine the result size when neither first or last are given.
# File lib/graphql/pagination/connection.rb, line 61 def initialize(items, parent: nil, field: nil, context: nil, first: nil, after: nil, max_page_size: :not_given, default_page_size: :not_given, last: nil, before: nil, edge_class: nil, arguments: nil) @items = items @parent = parent @context = context @field = field @first_value = first @after_value = after @last_value = last @before_value = before @arguments = arguments @edge_class = edge_class || self.class::Edge # 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 @has_default_page_size_override = default_page_size != :not_given @default_page_size = if default_page_size == :not_given nil else default_page_size end end
Public Instance Methods
@return [String, nil] the client-provided cursor. ‘“”` is treated as `nil`.
# File lib/graphql/pagination/connection.rb, line 40 def after if defined?(@after) @after else @after = @after_value == "" ? nil : @after_value end end
@return [String, nil] the client-provided cursor. ‘“”` is treated as `nil`.
# File lib/graphql/pagination/connection.rb, line 31 def before if defined?(@before) @before else @before = @before_value == "" ? nil : @before_value end end
Return a cursor for this item. @param item [Object] one of the passed in {items}, taken from {nodes} @return [String]
# File lib/graphql/pagination/connection.rb, line 205 def cursor_for(item) raise PaginationImplementationMissingError, "Implement #{self.class}#cursor_for(item) to return the cursor for #{item.inspect}" end
# File lib/graphql/pagination/connection.rb, line 110 def default_page_size if @has_default_page_size_override @default_page_size else context.schema.default_page_size end end
# File lib/graphql/pagination/connection.rb, line 105 def default_page_size=(new_value) @has_default_page_size_override = true @default_page_size = new_value end
A dynamic alias for compatibility with {Relay::BaseConnection}. @deprecated use {#nodes} instead
# File lib/graphql/pagination/connection.rb, line 173 def edge_nodes nodes end
@return [Array<Edge>] {nodes}, but wrapped with Edge
instances
# File lib/graphql/pagination/connection.rb, line 156 def edges @edges ||= nodes.map { |n| @edge_class.new(n, self) } end
@return [String] The cursor of the last item in {nodes}
# File lib/graphql/pagination/connection.rb, line 198 def end_cursor nodes.last && cursor_for(nodes.last) end
@return [Integer, nil]
A clamped `first` value. (The underlying instance variable doesn't have limits on it.) If neither `first` nor `last` is given, but `default_page_size` is present, default_page_size is used for first. If `default_page_size` is greater than `max_page_size``, it'll be clamped down to `max_page_size`. If `default_page_size` is nil, use `max_page_size`.
# File lib/graphql/pagination/connection.rb, line 130 def first @first ||= begin capped = limit_pagination_argument(@first_value, max_page_size) if capped.nil? && last.nil? capped = limit_pagination_argument(default_page_size, max_page_size) || max_page_size end capped end end
# File lib/graphql/pagination/connection.rb, line 118 def has_default_page_size_override? @has_default_page_size_override end
# File lib/graphql/pagination/connection.rb, line 101 def has_max_page_size_override? @has_max_page_size_override end
@return [Boolean] True if there are more items after this page
# File lib/graphql/pagination/connection.rb, line 183 def has_next_page raise PaginationImplementationMissingError, "Implement #{self.class}#has_next_page to return the next-page check" end
@return [Boolean] True if there were items before these items
# File lib/graphql/pagination/connection.rb, line 188 def has_previous_page raise PaginationImplementationMissingError, "Implement #{self.class}#has_previous_page to return the previous-page check" end
@return [Integer, nil] A clamped ‘last` value. (The underlying instance variable doesn’t have limits on it)
# File lib/graphql/pagination/connection.rb, line 151 def last @last ||= limit_pagination_argument(@last_value, max_page_size) end
# File lib/graphql/pagination/connection.rb, line 93 def max_page_size if @has_max_page_size_override @max_page_size else context.schema.default_max_page_size end end
# File lib/graphql/pagination/connection.rb, line 88 def max_page_size=(new_value) @has_max_page_size_override = true @max_page_size = new_value end
@return [Array<Object>] A slice of {items}, constrained by {@first_value}/{@after_value}/{@last_value}/{@before_value}
# File lib/graphql/pagination/connection.rb, line 167 def nodes raise PaginationImplementationMissingError, "Implement #{self.class}#nodes to paginate `@items`" end
The connection object itself implements ‘PageInfo` fields
# File lib/graphql/pagination/connection.rb, line 178 def page_info self end
This is called by ‘Relay::RangeAdd` – it can be overridden when `item` needs some modifications based on this connection’s state.
@param item [Object] An item newly added to ‘items` @return [Edge]
# File lib/graphql/pagination/connection.rb, line 145 def range_add_edge(item) edge_class.new(item, self) end
@return [String] The cursor of the first item in {nodes}
# File lib/graphql/pagination/connection.rb, line 193 def start_cursor nodes.first && cursor_for(nodes.first) end
Private Instance Methods
# File lib/graphql/pagination/connection.rb, line 225 def decode(cursor) context.schema.cursor_encoder.decode(cursor, nonce: true) end
# File lib/graphql/pagination/connection.rb, line 229 def encode(cursor) context.schema.cursor_encoder.encode(cursor, nonce: true) end
@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/pagination/connection.rb, line 214 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