datacite/lupo

View on GitHub
app/controllers/concerns/paginatable.rb

Summary

Maintainability
A
2 hrs
Test Coverage
F
26%
# frozen_string_literal: true

module Paginatable
  extend ActiveSupport::Concern

  included do
    # make sure page parameter is a hash with keys size, number and/or cursor
    def page_from_params(params)
      p = params.to_unsafe_h.dig(:page)

      page = p.is_a?(Hash) ? p.symbolize_keys : {}

      # Use scroll API for large number of results, e.g. to generate sitemaps
      # Alternatively use cursor
      # All cursors will need to be decoded from the param
      # Check for presence of :cursor key, value can be empty
      if page.has_key?(:cursor) && !page.has_key?(:scroll)
        begin
          # When we decode and split, we'll always end up with an array
          # use urlsafe_decode to not worry about url-unsafe characters + and /
          # split into two strings so that DOIs with comma in them are left intact
          page[:cursor] =
            Base64.urlsafe_decode64(page[:cursor].to_s).split(",", 2)
        rescue ArgumentError
          # If we fail to decode we'll just default back to an empty cursor
          page[:cursor] = []
        end
      end

      # Elasticsearch is limited to 10000 results per query, so we liit with max_number
      # max number of results per page is 1000
      if page[:size].present?
        page[:size] = [page[:size].to_i, 1_000].min
        max_number = page[:size] > 0 ? 10_000 / page[:size] : 1
      else
        page[:size] = 25
        max_number = 10_000 / page[:size]
      end
      page[:number] =
        page[:number].to_i > 0 ? [page[:number].to_i, max_number].min : 1

      page
    end

    def make_cursor(results)
      # Base64-encode cursor
      Base64.urlsafe_encode64(
        results.to_a.last[:sort].join(","),
        padding: false,
      )
    end
  end
end