class Praxis::Extensions::Pagination::PaginationParams

Constants

CLAUSE_REGEX

Attributes

defaults[R]
fields_allowed[RW]
media_type[R]
by[R]
from[R]
items[R]
page[R]
total_count[R]

Private Class Methods

coerce_field(name, value) click to toggle source

Silently ignore if the fiels does not exist…let’s let the validation check it instead

# File lib/praxis/extensions/pagination/pagination_params.rb, line 293
def self.coerce_field(name, value)
  if media_type&.attributes
    attrs = media_type&.attributes || {}
    attribute = attrs[name.to_sym]
    attribute&.type&.load(value)
  else
    value
  end
end
construct(pagination_definition, **options) click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 194
def self.construct(pagination_definition, **options)
  return self if pagination_definition.nil?

  DSLCompiler.new(self, **options).parse(*pagination_definition)
  self
end
constructable?() click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 190
def self.constructable?
  true
end
default_page_size(newval = nil) click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 124
def self.default_page_size(newval = nil)
  newval ? @default_page_size = newval : @default_page_size
end
describe(_root = false, example: nil) click to toggle source
Calls superclass method
# File lib/praxis/extensions/pagination/pagination_params.rb, line 274
def self.describe(_root = false, example: nil)
  hash = super

  hash[:fields_allowed] = fields_allowed if fields_allowed
  if defaults
    hash[:max_items]    = defaults[:max_items]
    hash[:page_size]    = defaults[:page_size]
    hash[:default_mode] = defaults[:default_mode]

    disallowed = []
    disallowed << :paging if defaults[:disallow_paging] == true
    disallowed << :cursor if defaults[:disallow_cursor] == true
    hash[:disallowed] = disallowed unless disallowed.empty?
  end

  hash
end
disallow_cursor_by_default(newval = nil) click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 132
def self.disallow_cursor_by_default(newval = nil)
  newval ? @disallow_cursor_by_default = newval : @disallow_cursor_by_default
end
disallow_paging_by_default(newval = nil) click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 128
def self.disallow_paging_by_default(newval = nil)
  newval ? @disallow_paging_by_default = newval : @disallow_paging_by_default
end
display_name() click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 182
def self.display_name
  'Paginator'
end
dump(value, **_opts) click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 270
def self.dump(value, **_opts)
  load(value).dump
end
example(_context = Attributor::DEFAULT_ROOT_CONTEXT, **_options) click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 203
def self.example(_context = Attributor::DEFAULT_ROOT_CONTEXT, **_options)
  fields = if media_type
             mt_example = media_type.example
             simple_attrs = media_type.attributes.select do |_k, attr|
               attr.type == Attributor::String || attr.type == Attributor::Integer
             end

             selectable = mt_example.object.keys & simple_attrs.keys
             by = selectable.sample(1).first
             from = media_type.attributes[by].example(parent: mt_example).to_s
             # Make sure to encode the value of the from, as it can contain commas and such
             # Only add the from parameter if it's not empty (an empty from is not allowed and it's gonna blow up in load)
             optional_from_component = from && !from.empty? ? ",from=#{CGI.escape(from)}" : ''
             "by=#{by}#{optional_from_component},items=#{defaults[:page_size]}"
           else
             'by=id,from=20,items=100'
           end
  load(fields)
end
family() click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 186
def self.family
  'string'
end
for(media_type, **_opts) click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 151
def for(media_type, **_opts)
  unless media_type < Praxis::MediaType
    raise ArgumentError, "Invalid type: #{media_type.name} for Paginator. " \
      'Must be a subclass of MediaType'
  end

  ::Class.new(self) do
    @media_type = media_type
    @defaults = {
      page_size: PaginationParams.default_page_size,
      max_items: PaginationParams.max_items,
      disallow_paging: PaginationParams.disallow_paging_by_default,
      disallow_cursor: PaginationParams.disallow_cursor_by_default,
      default_mode: PaginationParams.paging_default_mode
    }
  end
end
json_schema_type() click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 170
def self.json_schema_type
  :string
end
load(paginator, _context = Attributor::DEFAULT_ROOT_CONTEXT, **_options) click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 229
def self.load(paginator, _context = Attributor::DEFAULT_ROOT_CONTEXT, **_options)
  return paginator if paginator.is_a?(native_type) || paginator.nil?

  parsed = {}
  unless paginator.nil?
    parsed = paginator.split(',').each_with_object({}) do |paginator_string, hash|
      match = CLAUSE_REGEX.match(paginator_string)
      case match[:type].to_sym
      when :page
        hash[:page] = Integer(match[:value])
      when :by
        hash[:by] = match[:value]
      when :from
        hash[:from] = match[:value]
      when :total_count
        hash[:total_count] = (match[:value] != 'false') # unless explicitly set to false, we'll take it as true...
      when :items
        hash[:items] = Integer(match[:value])
      else
        raise "Error loading pagination parameters: unknown parameter with name '#{match[:type]}' found"
      end
    end
  end

  parsed[:items] = defaults[:page_size] unless parsed.key?(:items)
  parsed[:from] = coerce_field(parsed[:by], parsed[:from]) if parsed.key?(:from)

  # If no by/from or page specified, we're gonna apply the defaults
  unless parsed.key?(:by) || parsed.key?(:from) || parsed.key?(:page)
    mode, value = defaults[:default_mode].first
    case mode
    when :by
      parsed[:by] = value
    when :page
      parsed[:page] = value
    end
  end

  new(parsed)
end
max_items(newval = nil) click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 120
def self.max_items(newval = nil)
  newval ? @max_items = newval : @max_items
end
name() click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 178
def self.name
  'Extensions::Pagination::PaginationParams'
end
native_type() click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 174
def self.native_type
  self
end
new(parsed) click to toggle source

Instance methods

# File lib/praxis/extensions/pagination/pagination_params.rb, line 304
def initialize(parsed)
  @by = parsed[:by]
  @from = parsed[:from]
  @items = parsed[:items]
  @page = parsed[:page]
  @total_count = parsed[:total_count]
end
paging_default_mode(newval = nil) click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 136
def self.paging_default_mode(newval = nil)
  if newval
    raise 'Error setting paging_default_mode, value must be a hash with :by or :page keys' unless newval.respond_to?(:keys) && newval.keys.size == 1 && %i[by page].include?(newval.keys.first)

    @paging_default_mode = newval
  end
  @paging_default_mode
end
validate(value, context = Attributor::DEFAULT_ROOT_CONTEXT, _attribute = nil) click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 223
def self.validate(value, context = Attributor::DEFAULT_ROOT_CONTEXT, _attribute = nil)
  instance = load(value, context)
  instance.validate(context)
end

Private Instance Methods

dump() click to toggle source

Dump back string parseable form

# File lib/praxis/extensions/pagination/pagination_params.rb, line 339
def dump
  str = if @page
          "page=#{@page}"
        else
          s = "by=#{@by}"
          s += ",from=#{@from}" if @from
          s
        end
  str += ",items=#{items}" if @items
  str += ',total_count=true' if @total_count
  str
end
validate(_context = Attributor::DEFAULT_ROOT_CONTEXT) click to toggle source
# File lib/praxis/extensions/pagination/pagination_params.rb, line 312
def validate(_context = Attributor::DEFAULT_ROOT_CONTEXT)
  errors = []

  if page
    errors << "Page-based pagination is disallowed (i.e., using 'page=' parameter)" if self.class.defaults[:disallow_paging]
  elsif self.class.defaults[:disallow_cursor]
    errors << "Cursor-based pagination is disallowed (i.e., using 'by=' or 'from=' parameter)"
  end

  errors << "Page parameter cannot be zero or negative! (got: #{parsed.page})" if page && page <= 0

  errors << "Value of 'items' is invalid (got: #{items}). It must be positive, and smaller than the maximum amount of items per request (set to #{self.class.defaults[:max_items]})" if items && (items <= 0 || (self.class.defaults[:max_items] && items > self.class.defaults[:max_items]))

  errors << 'Cannot specify the field to use and its start value to paginate from when using a fix pager (i.e., `by` and/or `from` params are not compabible with `page`)' if page && (by || from)

  if by && self.class.fields_allowed && !self.class.fields_allowed.include?(by.to_sym)
    errors << if self.class.media_type.attributes.key?(by.to_sym)
                "Paginating by field \'#{by}\' is disallowed"
              else
                "Paginating by field \'#{by}\' is not possible as this field does not exist in "\
                "media type #{self.class.media_type.name}"
              end
  end
  errors
end