lib/pagy/extras/jsonapi.rb



# See the Pagy documentation: https://ddnexus.github.io/pagy/docs/extras/jsonapi
# frozen_string_literal: true

require_relative '../url_helpers'

class Pagy # :nodoc:
  DEFAULT[:jsonapi] = true

  # Add a specialized backend method compliant with JSON:API
  module JsonApiExtra
    # JsonApi :page param error
    class ReservedParamError < StandardError
      # Inform about the actual value
      def initialize(value)
        super("expected reserved :page param to be nil or Hash-like; got #{value.inspect}")
      end
    end

    # Module overriding Backend
    module BackendOverride
      private

      include UrlHelpers

      # Return the jsonapi links
      def pagy_jsonapi_links(pagy, **opts)
        if defined?(Pagy::Keyset) && pagy.is_a?(Pagy::Keyset)
          { first: pagy_url_for(pagy, nil, **opts),
            last: nil,
            prev: nil,
            next:  pagy.next ? pagy_url_for(pagy, pagy.next, **opts) : nil }
        else
          { first: pagy_url_for(pagy, 1, **opts),
            last:  pagy_url_for(pagy, pagy.last, **opts),
            prev:  pagy.prev ? pagy_url_for(pagy, pagy.prev, **opts) : nil,
            next:  pagy.next ? pagy_url_for(pagy, pagy.next, **opts) : nil }
        end
      end

      # Should skip the jsonapi
      def pagy_skip_jsonapi?(vars)
        return true if vars[:jsonapi] == false || (vars[:jsonapi].nil? && DEFAULT[:jsonapi] == false)
        # check the reserved :page param
        raise ReservedParamError, params[:page] unless params[:page].respond_to?(:fetch) || params[:page].nil?
      end

      # Override the Backend method
      def pagy_get_page(vars)
        return super if pagy_skip_jsonapi?(vars)
        return if params[:page].nil?

        params[:page][vars[:page_param] || DEFAULT[:page_param]]
      end
    end
    Backend.prepend BackendOverride

    # Module overriding LimitExtra
    module LimitExtraOverride
      private

      # Override the LimitExtra::Backend method
      def pagy_get_limit_param(vars)
        return super if pagy_skip_jsonapi?(vars)
        return if params[:page].nil?

        params[:page][vars[:limit_param] || DEFAULT[:limit_param]]
      end
    end
    # :nocov:
    LimitExtra::BackendAddOn.prepend LimitExtraOverride if defined?(LimitExtra::BackendAddOn)
    # :nocov:

    # Module overriding UrlHelper
    module UrlHelperOverride
      # Override UrlHelper method
      def pagy_set_query_params(page, vars, query_params)
        return super unless vars[:jsonapi]

        query_params['page'] ||= {}
        query_params['page'][vars[:page_param].to_s]  = page if page
        query_params['page'][vars[:limit_param].to_s] = vars[:limit] if vars[:limit_extra]
        # :nocov:
        query_params.delete(:page) if query_params['page'].empty?
        # :nocov:
      end
    end
    UrlHelpers.prepend UrlHelperOverride
  end
end