Class: GraphQL::Pagination::Connection

Inherits:
Object
  • Object
show all
Defined in:
lib/graphql/pagination/connection.rb

Overview

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).

Direct Known Subclasses

ArrayConnection, RelationConnection

Defined Under Namespace

Classes: Edge, PaginationImplementationMissingError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(items, context: nil, first: nil, after: nil, max_page_size: :not_given, last: nil, before: nil) ⇒ Connection

Returns a new instance of Connection.

Parameters:

  • items (Object)

    some unpaginated collection item, like an Array or ActiveRecord::Relation

  • context (Query::Context) (defaults to: nil)
  • first (Integer, nil) (defaults to: nil)

    The limit parameter from the client, if it provided one

  • after (String, nil) (defaults to: nil)

    A cursor for pagination, if the client provided one

  • last (Integer, nil) (defaults to: nil)

    Limit parameter from the client, if provided

  • before (String, nil) (defaults to: nil)

    A cursor for pagination, if the client provided one.

  • max_page_size (Integer, nil) (defaults to: :not_given)

    A configured value to cap the result size. Applied as first if neither first or last are given.



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/graphql/pagination/connection.rb', line 57

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

Instance Attribute Details

#after_valueObject

Raw access to client-provided values. (max_page_size not applied to first or last.)



30
31
32
# File 'lib/graphql/pagination/connection.rb', line 30

def after_value
  @after_value
end

#before_valueObject

Raw access to client-provided values. (max_page_size not applied to first or last.)



30
31
32
# File 'lib/graphql/pagination/connection.rb', line 30

def before_value
  @before_value
end

#contextGraphQL::Query::Context



27
28
29
# File 'lib/graphql/pagination/connection.rb', line 27

def context
  @context
end

#firstInteger?

Returns A clamped first value. (The underlying instance variable doesn’t have limits on it.) If neither first nor last is given, but max_page_size is present, max_page_size is used for first.

Returns:

  • (Integer, nil)

    A clamped first value. (The underlying instance variable doesn’t have limits on it.) If neither first nor last is given, but max_page_size is present, max_page_size is used for first.



97
98
99
100
101
102
103
104
105
# File 'lib/graphql/pagination/connection.rb', line 97

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

#first_valueObject

Raw access to client-provided values. (max_page_size not applied to first or last.)



30
31
32
# File 'lib/graphql/pagination/connection.rb', line 30

def first_value
  @first_value
end

#itemsObject (readonly)

Returns A list object, from the application. This is the unpaginated value passed into the connection.

Returns:

  • (Object)

    A list object, from the application. This is the unpaginated value passed into the connection.



24
25
26
# File 'lib/graphql/pagination/connection.rb', line 24

def items
  @items
end

#lastInteger?

Returns A clamped last value. (The underlying instance variable doesn’t have limits on it).

Returns:

  • (Integer, nil)

    A clamped last value. (The underlying instance variable doesn’t have limits on it)



109
110
111
# File 'lib/graphql/pagination/connection.rb', line 109

def last
  @last ||= limit_pagination_argument(@last_value, max_page_size)
end

#last_valueObject

Raw access to client-provided values. (max_page_size not applied to first or last.)



30
31
32
# File 'lib/graphql/pagination/connection.rb', line 30

def last_value
  @last_value
end

Class Method Details

.edge_classClass

Returns The class to use for wrapping items as edges { ... }. Defaults to Connection::Edge.

Returns:

  • (Class)

    The class to use for wrapping items as edges { ... }. Defaults to Connection::Edge



19
20
21
# File 'lib/graphql/pagination/connection.rb', line 19

def self.edge_class
  self::Edge
end

Instance Method Details

#afterString?

Returns the client-provided cursor. "" is treated as nil.

Returns:

  • (String, nil)

    the client-provided cursor. "" is treated as nil.



42
43
44
45
46
47
48
# File 'lib/graphql/pagination/connection.rb', line 42

def after
  if defined?(@after)
    @after
  else
    @after = @after_value == "" ? nil : @after_value
  end
end

#beforeString?

Returns the client-provided cursor. "" is treated as nil.

Returns:

  • (String, nil)

    the client-provided cursor. "" is treated as nil.



33
34
35
36
37
38
39
# File 'lib/graphql/pagination/connection.rb', line 33

def before
  if defined?(@before)
    @before
  else
    @before = @before_value == "" ? nil : @before_value
  end
end

#cursor_for(item) ⇒ String

Return a cursor for this item.

Parameters:

  • item (Object)

    one of the passed in #items, taken from #nodes

Returns:

  • (String)

Raises:



157
158
159
# File 'lib/graphql/pagination/connection.rb', line 157

def cursor_for(item)
  raise PaginationImplementationMissingError, "Implement #{self.class}#cursor_for(item) to return the cursor for #{item.inspect}"
end

#edge_nodesObject

Deprecated.

use #nodes instead

A dynamic alias for compatibility with Relay::BaseConnection.



125
126
127
# File 'lib/graphql/pagination/connection.rb', line 125

def edge_nodes
  nodes
end

#edgesArray<Edge>

Returns #nodes, but wrapped with Edge instances.

Returns:

  • (Array<Edge>)

    #nodes, but wrapped with Edge instances



114
115
116
# File 'lib/graphql/pagination/connection.rb', line 114

def edges
  @edges ||= nodes.map { |n| self.class.edge_class.new(n, self) }
end

#end_cursorString

Returns The cursor of the last item in #nodes.

Returns:

  • (String)

    The cursor of the last item in #nodes



150
151
152
# File 'lib/graphql/pagination/connection.rb', line 150

def end_cursor
  nodes.last && cursor_for(nodes.last)
end

#has_max_page_size_override?Boolean

Returns:

  • (Boolean)


88
89
90
# File 'lib/graphql/pagination/connection.rb', line 88

def has_max_page_size_override?
  @has_max_page_size_override
end

#has_next_pageBoolean

Returns True if there are more items after this page.

Returns:

  • (Boolean)

    True if there are more items after this page

Raises:



135
136
137
# File 'lib/graphql/pagination/connection.rb', line 135

def has_next_page
  raise PaginationImplementationMissingError, "Implement #{self.class}#has_next_page to return the next-page check"
end

#has_previous_pageBoolean

Returns True if there were items before these items.

Returns:

  • (Boolean)

    True if there were items before these items

Raises:



140
141
142
# File 'lib/graphql/pagination/connection.rb', line 140

def has_previous_page
  raise PaginationImplementationMissingError, "Implement #{self.class}#has_previous_page to return the previous-page check"
end

#max_page_sizeObject



80
81
82
83
84
85
86
# File 'lib/graphql/pagination/connection.rb', line 80

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

#max_page_size=(new_value) ⇒ Object



75
76
77
78
# File 'lib/graphql/pagination/connection.rb', line 75

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

#nodesArray<Object>

Returns A slice of #items, constrained by @first_value/@after_value/@last_value/@before_value.

Returns:

  • (Array<Object>)

    A slice of #items, constrained by @first_value/@after_value/@last_value/@before_value

Raises:



119
120
121
# File 'lib/graphql/pagination/connection.rb', line 119

def nodes
  raise PaginationImplementationMissingError, "Implement #{self.class}#nodes to paginate `@items`"
end

#page_infoObject

The connection object itself implements PageInfo fields



130
131
132
# File 'lib/graphql/pagination/connection.rb', line 130

def page_info
  self
end

#start_cursorString

Returns The cursor of the first item in #nodes.

Returns:

  • (String)

    The cursor of the first item in #nodes



145
146
147
# File 'lib/graphql/pagination/connection.rb', line 145

def start_cursor
  nodes.first && cursor_for(nodes.first)
end