class Praxis::Extensions::Pagination::OrderingParams

Attributes

enforce_all[RW]
fields_allowed[RW]
media_type[R]
items[R]

Private Class Methods

construct(pagination_definition, **options) click to toggle source
# File lib/praxis/extensions/pagination/ordering_params.rb, line 126
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/ordering_params.rb, line 122
def self.constructable?
  true
end
describe(_root = false, example: nil) click to toggle source
Calls superclass method
# File lib/praxis/extensions/pagination/ordering_params.rb, line 184
def self.describe(_root = false, example: nil)
  hash = super

  if fields_allowed
    hash[:fields_allowed] = fields_allowed
    hash[:enforced_for] = enforce_all ? :all : :first
  end

  hash
end
display_name() click to toggle source
# File lib/praxis/extensions/pagination/ordering_params.rb, line 114
def self.display_name
  'Ordering'
end
dump(value, **_opts) click to toggle source
# File lib/praxis/extensions/pagination/ordering_params.rb, line 180
def self.dump(value, **_opts)
  load(value).dump
end
enforce_all_fields(newval = nil) click to toggle source
# File lib/praxis/extensions/pagination/ordering_params.rb, line 66
def self.enforce_all_fields(newval = nil)
  newval ? @enforce_all_fields = newval : @enforce_all_fields
end
example(_context = Attributor::DEFAULT_ROOT_CONTEXT, **_options) click to toggle source
# File lib/praxis/extensions/pagination/ordering_params.rb, line 133
def self.example(_context = Attributor::DEFAULT_ROOT_CONTEXT, **_options)
  fields = if media_type
             chosen_set = if enforce_all
                            fields_allowed.sample(2)
                          else
                            starting_set = fields_allowed.sample(1)
                            simple_attrs = media_type.attributes.select do |_k, attr|
                              attr.type == Attributor::String || attr.type < Attributor::Numeric || attr.type < Attributor::Temporal
                            end.keys
                            starting_set + simple_attrs.reject { |attr| attr == starting_set.first }.sample(1)
                          end
             chosen_set.each_with_object([]) do |chosen, arr|
               sign = rand(10) < 5 ? '-' : ''
               arr << "#{sign}#{chosen}"
             end.join(',')
           else
             'name,last_name,-birth_date'
           end
  load(fields)
end
family() click to toggle source
# File lib/praxis/extensions/pagination/ordering_params.rb, line 118
def self.family
  'string'
end
for(media_type, **_opts) click to toggle source
# File lib/praxis/extensions/pagination/ordering_params.rb, line 86
def for(media_type, **_opts)
  unless media_type < Praxis::MediaType
    raise ArgumentError, "Invalid type: #{media_type.name} for Ordering. " \
      'Must be a subclass of MediaType'
  end

  ::Class.new(self) do
    @media_type = media_type
    # Default is to only enforce the allowed fields in the first ordering position (the one typicall uses an index if there)
    @enforce_all = OrderingParams.enforce_all_fields
  end
end
json_schema_type() click to toggle source
# File lib/praxis/extensions/pagination/ordering_params.rb, line 102
def self.json_schema_type
  :string
end
load(order, _context = Attributor::DEFAULT_ROOT_CONTEXT, **_options) click to toggle source
# File lib/praxis/extensions/pagination/ordering_params.rb, line 159
def self.load(order, _context = Attributor::DEFAULT_ROOT_CONTEXT, **_options)
  return order if order.is_a?(native_type)

  parsed_order = {}
  unless order.nil?
    parsed_order = order.split(',').each_with_object([]) do |order_string, arr|
      item = case order_string[0]
             when '-'
               { desc: order_string[1..].to_s }
             when '+'
               { asc: order_string[1..].to_s }
             else
               { asc: order_string.to_s }
             end
      arr.push item
    end
  end

  new(parsed_order)
end
name() click to toggle source
# File lib/praxis/extensions/pagination/ordering_params.rb, line 110
def self.name
  'Praxis::Types::OrderingParams'
end
native_type() click to toggle source
# File lib/praxis/extensions/pagination/ordering_params.rb, line 106
def self.native_type
  self
end
new(parsed) click to toggle source
# File lib/praxis/extensions/pagination/ordering_params.rb, line 195
def initialize(parsed)
  @items = parsed
end
validate(value, context = Attributor::DEFAULT_ROOT_CONTEXT, _attribute = nil) click to toggle source
# File lib/praxis/extensions/pagination/ordering_params.rb, line 154
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
# File lib/praxis/extensions/pagination/ordering_params.rb, line 226
def dump
  items.each_with_object([]) do |spec, arr|
    dir, field = spec.first
    arr << if dir == :desc
             "-#{field}"
           else
             field
           end
  end.join(',')
end
each(&block) click to toggle source
# File lib/praxis/extensions/pagination/ordering_params.rb, line 237
def each(&block)
  items.each(&block)
end
valid_attribute_path?(media_type, path) click to toggle source

Looks up if the given path (with symbol attribute names at each component) is actually a valid path from the given mediatype

# File lib/praxis/extensions/pagination/ordering_params.rb, line 243
def valid_attribute_path?(media_type, path)
  first, *rest = path
  # Get the member type if this is a collection
  media_type = media_type.member_type if media_type.respond_to?(:member_attribute)
  if (attribute = media_type.attributes[first])
    rest.empty? ? true : valid_attribute_path?(attribute.type, rest)
  else
    false
  end
end
validate(_context = Attributor::DEFAULT_ROOT_CONTEXT) click to toggle source
# File lib/praxis/extensions/pagination/ordering_params.rb, line 199
def validate(_context = Attributor::DEFAULT_ROOT_CONTEXT)
  return [] if items.blank?

  errors = []
  if self.class.fields_allowed
    # Validate against the enforced components (either all, or just the first one)
    enforceable_items = self.class.enforce_all ? items : [items.first]

    enforceable_items.each do |spec|
      _dir, field = spec.first
      field = field.to_sym
      next if self.class.fields_allowed.include?(field)

      field_path = field.to_s.split('.').map(&:to_sym)
      errors << if valid_attribute_path?(self.class.media_type, field_path)
                  "Ordering by field \'#{field}\' in media type #{self.class.media_type.name} is disallowed. Ordering is only allowed using the following fields: " +
                  self.class.fields_allowed.map { |f| "\'#{f}\'" }.join(', ').to_s
                else
                  "Ordering by field \'#{field}\' is not possible as this field is not reachable from " \
                  "media type #{self.class.media_type.name}"
                end
    end
  end

  errors
end