Module: PageCursor::ActionControllerExtension
- Defined in:
- lib/page_cursor/cursor.rb
Instance Method Summary collapse
-
#paginate(c, direction = nil, **opts) ⇒ Object
paginate returns a cursor-enabled pagination.
Instance Method Details
#paginate(c, direction = nil, **opts) ⇒ Object
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 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 68 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 96 97 98 99 100 101 |
# File 'lib/page_cursor/cursor.rb', line 9 def paginate(c, direction = nil, **opts) opts.symbolize_keys! limit = opts[:limit]&.to_i || 10 raise ArgumentError, "direction must be either nil, :asc or :desc" unless [nil, :asc, :desc].include?(direction) raise ArgumentError, "limit must be >= 1" unless limit >= 1 raise ArgumentError, "only provide one, either params[:after] or params[:before]" if params[:after].present? && params[:before].present? # make sure we have a primary key pk_name = (opts[:primary_key] || c.primary_key).to_s if !c.column_names.include?(pk_name) if opts[:primary_key].present? raise ArgumentError, "column '#{opts[:primary_key]}' does not exist in table '#{c.table_name}'" else raise "table '#{c.table_name}' has no primary key" end end # reference the table's primary key pk = c.arel_table[pk_name] raise ArgumentError, "expect primary key to be Arel::Attributes:Attribute instead of #{pk.class}" unless pk.is_a?(Arel::Attributes::Attribute) # set cursor to :after/:before and the according pk_value from the params cursor = nil pk_value = nil if params[:after].present? cursor = :after pk_value = params[:after] elsif params[:before].present? cursor = :before pk_value = params[:before] end # always fetch limit + 1 to see if there are more records c = c.limit(limit + 1) all = [] # check if c already has one or more order directives set unless already_has_order?(c) # easy, no existing order directives, we'll just order by our primary key comparison, order, reverse = ordering(direction || :asc, cursor) c = c.where(pk.send(comparison, pk_value)) if comparison c = c.reorder(pk.send(order)).all c = c.reverse if reverse all = c.to_a else # collection has order directives, we need to do a bit more work ... # replace existing order with new one c = reorder(c, cursor, pk, direction || :asc) # if a cursor is given, we need to fetch its row from the database # so that we can use the row's values for our where conditions. unless cursor.nil? row = find!(c, pk_name, pk_value) c = where(c, cursor, row) end all = c.all.to_a all = all.reverse if cursor == :before end has_more = all.size <= limit ? false : true # return new after/before cursor and all results if there are no more results to expect after this unless has_more if cursor.nil? return { :after => nil, :before => nil }, all # first and only page, no afters/befores elsif cursor == :after return { :after => nil, :before => all.first&.read_attribute(pk_name) }, all # last page, no afters elsif cursor == :before return { :after => all.last&.read_attribute(pk_name), :before => nil }, all # last page, no befores end end # return new after/before cursors and all results if there are more results to expect if cursor == :before all = all.last(all.size - 1) else all = all.first(all.size - 1) end if cursor.nil? return { :after => all.last&.read_attribute(pk_name), :before => nil }, all # first page, continue after elsif cursor == :after return { :after => all.last&.read_attribute(pk_name), :before => all.first&.read_attribute(pk_name) }, all elsif cursor == :before return { :after => all.last&.read_attribute(pk_name), :before => all.first&.read_attribute(pk_name) }, all end fail "never" # safeguard if cursor has a weird value end |