Class: ActiveRecord::CursorPaginator
- Inherits:
-
Object
- Object
- ActiveRecord::CursorPaginator
- Defined in:
- lib/active_record/cursor_paginator.rb,
lib/active_record/cursor_paginator/version.rb
Defined Under Namespace
Classes: InvalidCursorError, InvalidOrderError, ParameterError
Constant Summary collapse
- DIRECTIONS =
[ DIRECTION_FORWARD = :forward, DIRECTION_BACKWARD = :backward, ].freeze
- VERSION =
'0.2.0'
Instance Method Summary collapse
-
#end_cursor ⇒ String?
Cursor of the last record on the current page.
-
#extract_order_fields(relation) ⇒ Array
extract order parameter from relation as the format : [ { field1 => :asc}, { field2 => :desc}, …].
-
#initialize(relation, per_page: nil, cursor: nil, direction: DIRECTION_FORWARD) ⇒ CursorPaginator
constructor
A new instance of CursorPaginator.
-
#next_page? ⇒ TrueClass, FalseClass
Check if there is another page after the current one.
-
#paginate_forward? ⇒ TrueClass, FalseClass
Check if the pagination direction is forward.
-
#previous_page? ⇒ TrueClass, FalseClass
Check if there is a page before the current one.
-
#records ⇒ Array<ActiveRecord>
Load the correct records and return them in the right order.
-
#start_cursor ⇒ String?
Cursor of the first record on the current page.
-
#total ⇒ Integer
Get the total number of records in the given relation.
Constructor Details
#initialize(relation, per_page: nil, cursor: nil, direction: DIRECTION_FORWARD) ⇒ CursorPaginator
Returns a new instance of CursorPaginator.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/active_record/cursor_paginator.rb', line 25 def initialize(relation, per_page: nil, cursor: nil, direction: DIRECTION_FORWARD) @is_forward_pagination = direction == DIRECTION_FORWARD relation = relation.order(:id) if relation.order_values.empty? relation = relation.reverse_order unless @is_forward_pagination @fields = extract_order_fields(relation) @fields.push({ 'id' => :asc }) if @fields.last.keys.first != 'id' @relation = relation.reorder(@fields) @cursor = cursor @page_size = per_page aliases = parse_aliases aliases[:id] ||= "#{relation.table_name}.id" @aliases = aliases.with_indifferent_access @memos = {} end |
Instance Method Details
#end_cursor ⇒ String?
Cursor of the last record on the current page
81 82 83 84 85 |
# File 'lib/active_record/cursor_paginator.rb', line 81 def end_cursor return if records.empty? cursor_for_record(records.last) end |
#extract_order_fields(relation) ⇒ Array
extract order parameter from relation as the format : [ { field1 => :asc}, { field2 => :desc}, …]
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/active_record/cursor_paginator.rb', line 43 def extract_order_fields(relation) orders = relation.order_values fields = orders.flat_map do |o| case o when Arel::Attribute # .order(arel_table[:id]) { o.name => :asc } when Arel::Nodes::Ascending, # .order(id: :asc), .order(:id) Arel::Nodes::Descending # .order(id: :desc) key = o.expr.is_a?(Arel::Attributes::Attribute) ? o.expr.name : trim_quote(o.expr) dir = o.direction { key => dir } when String # .order('id desc') o.split(',').map! do |s| s.strip! matches = s.match(/\A(\w+)(?:\s+(asc|desc))?\Z/i) raise InvalidOrderError, 'relation has an unsupported order.' if matches.nil? || matches.length < 3 { matches[1] => (matches[2] || 'asc').downcase.to_sym } end else # complex arel expression raise InvalidOrderError, 'relation has an unsupported order.' end end fields.flatten end |
#next_page? ⇒ TrueClass, FalseClass
Check if there is another page after the current one.
112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/active_record/cursor_paginator.rb', line 112 def next_page? if paginate_forward? # When paginating forward, if we managed to load one more record than # requested, this record will be available on the next page. records_plus_one.size > @page_size else # When paginating backward, in most cases, # we have the next page, because specified cursor may be the start cursor of a page true end end |
#paginate_forward? ⇒ TrueClass, FalseClass
Check if the pagination direction is forward
135 136 137 |
# File 'lib/active_record/cursor_paginator.rb', line 135 def paginate_forward? @is_forward_pagination end |
#previous_page? ⇒ TrueClass, FalseClass
Check if there is a page before the current one.
97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/active_record/cursor_paginator.rb', line 97 def previous_page? if paginate_forward? # When paginating forwards and cursor is specified, # we have the previous page, because specified cursor may be the end cursor of a page @cursor.present? else # When paginating backwards, if we managed to load one more record than # requested, this record will be available on the previous page. records_plus_one.size > @page_size end end |
#records ⇒ Array<ActiveRecord>
Load the correct records and return them in the right order
127 128 129 130 |
# File 'lib/active_record/cursor_paginator.rb', line 127 def records records = records_plus_one.first(@page_size) paginate_forward? ? records : records.reverse end |
#start_cursor ⇒ String?
Cursor of the first record on the current page
72 73 74 75 76 |
# File 'lib/active_record/cursor_paginator.rb', line 72 def start_cursor return if records.empty? cursor_for_record(records.first) end |
#total ⇒ Integer
Get the total number of records in the given relation
90 91 92 |
# File 'lib/active_record/cursor_paginator.rb', line 90 def total memoize(:total) { @relation.reorder('').size } end |