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

Instance Method Summary collapse

Constructor Details

#initialize(items, parent: nil, field: nil, context: nil, first: nil, after: nil, max_page_size: NOT_CONFIGURED, default_page_size: NOT_CONFIGURED, last: nil, before: nil, edge_class: nil, arguments: nil) ⇒ Connection



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/graphql/pagination/connection.rb', line 69

def initialize(items, parent: nil, field: nil, context: nil, first: nil, after: nil, max_page_size: NOT_CONFIGURED, default_page_size: NOT_CONFIGURED, 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_CONFIGURED
  @max_page_size = if max_page_size == NOT_CONFIGURED
    nil
  else
    max_page_size
  end
  @has_default_page_size_override = default_page_size != NOT_CONFIGURED
  @default_page_size = if default_page_size == NOT_CONFIGURED
    nil
  else
    default_page_size
  end
  @was_authorized_by_scope_items = detect_was_authorized_by_scope_items
end

Instance Attribute Details

#after_valueObject

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



36
37
38
# File 'lib/graphql/pagination/connection.rb', line 36

def after_value
  @after_value
end

#argumentsHash<Symbol => Object>



57
58
59
# File 'lib/graphql/pagination/connection.rb', line 57

def arguments
  @arguments
end

#before_valueObject

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



36
37
38
# File 'lib/graphql/pagination/connection.rb', line 36

def before_value
  @before_value
end

#contextGraphQL::Query::Context



22
23
24
# File 'lib/graphql/pagination/connection.rb', line 22

def context
  @context
end

#edge_classClass



174
175
176
# File 'lib/graphql/pagination/connection.rb', line 174

def edge_class
  @edge_class
end

#fieldGraphQL::Schema::Field



177
178
179
# File 'lib/graphql/pagination/connection.rb', line 177

def field
  @field
end

#firstInteger?



143
144
145
146
147
148
149
150
151
# File 'lib/graphql/pagination/connection.rb', line 143

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

#first_valueObject

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



36
37
38
# File 'lib/graphql/pagination/connection.rb', line 36

def first_value
  @first_value
end

#itemsObject (readonly)



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

def items
  @items
end

#lastInteger?



164
165
166
# File 'lib/graphql/pagination/connection.rb', line 164

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



36
37
38
# File 'lib/graphql/pagination/connection.rb', line 36

def last_value
  @last_value
end

#parentObject



33
34
35
# File 'lib/graphql/pagination/connection.rb', line 33

def parent
  @parent
end

Instance Method Details

#afterString?



48
49
50
51
52
53
54
# File 'lib/graphql/pagination/connection.rb', line 48

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

#beforeString?



39
40
41
42
43
44
45
# File 'lib/graphql/pagination/connection.rb', line 39

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.



218
219
220
# File 'lib/graphql/pagination/connection.rb', line 218

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

#default_page_sizeObject



123
124
125
126
127
128
129
# File 'lib/graphql/pagination/connection.rb', line 123

def default_page_size
  if @has_default_page_size_override
    @default_page_size
  else
    context.schema.default_page_size
  end
end

#default_page_size=(new_value) ⇒ Object



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

def default_page_size=(new_value)
  @has_default_page_size_override = true
  @default_page_size = new_value
end

#edge_nodesObject

Deprecated.

use #nodes instead

A dynamic alias for compatibility with Relay::BaseConnection.



186
187
188
# File 'lib/graphql/pagination/connection.rb', line 186

def edge_nodes
  nodes
end

#edgesArray<Edge>



169
170
171
# File 'lib/graphql/pagination/connection.rb', line 169

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

#end_cursorString



211
212
213
# File 'lib/graphql/pagination/connection.rb', line 211

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

#has_default_page_size_override?Boolean



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

def has_default_page_size_override?
  @has_default_page_size_override
end

#has_max_page_size_override?Boolean



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

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.



196
197
198
# File 'lib/graphql/pagination/connection.rb', line 196

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.



201
202
203
# File 'lib/graphql/pagination/connection.rb', line 201

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

#max_page_sizeObject



106
107
108
109
110
111
112
# File 'lib/graphql/pagination/connection.rb', line 106

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



101
102
103
104
# File 'lib/graphql/pagination/connection.rb', line 101

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.



180
181
182
# File 'lib/graphql/pagination/connection.rb', line 180

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

#page_infoObject

The connection object itself implements PageInfo fields



191
192
193
# File 'lib/graphql/pagination/connection.rb', line 191

def page_info
  self
end

#range_add_edge(item) ⇒ Edge

This is called by Relay::RangeAdd -- it can be overridden when item needs some modifications based on this connection's state.



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

def range_add_edge(item)
  edge_class.new(item, self)
end

#start_cursorString



206
207
208
# File 'lib/graphql/pagination/connection.rb', line 206

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

#was_authorized_by_scope_items?Boolean



97
98
99
# File 'lib/graphql/pagination/connection.rb', line 97

def was_authorized_by_scope_items?
  @was_authorized_by_scope_items
end