class ActiveSet::Sorting::ActiveRecordStrategy

Public Class Methods

new(set, attribute_instructions) click to toggle source
# File lib/active_set/sorting/active_record_strategy.rb, line 6
def initialize(set, attribute_instructions)
  @set = set
  @attribute_instructions = attribute_instructions
end

Public Instance Methods

executable_instructions() click to toggle source
# File lib/active_set/sorting/active_record_strategy.rb, line 24
def executable_instructions
  return {} unless @set.respond_to? :to_sql

  @attribute_instructions.select do |attribute_instruction|
    attribute_model = attribute_model_for(attribute_instruction)
    next false unless attribute_model
    next false unless attribute_model.respond_to?(:attribute_names)
    next false unless attribute_model.attribute_names.include?(attribute_instruction.attribute)

    true
  end
end
execute() click to toggle source
# File lib/active_set/sorting/active_record_strategy.rb, line 11
def execute
  return false unless @set.respond_to? :to_sql

  executable_instructions.reduce(set_with_eager_loaded_associations) do |set, attribute_instruction|
    statement = set.merge(order_operation_for(attribute_instruction))

    return false if throws?(ActiveRecord::StatementInvalid) { statement.load }

    attribute_instruction.processed = true
    statement
  end
end

Private Instance Methods

attribute_model_for(attribute_instruction) click to toggle source
# File lib/active_set/sorting/active_record_strategy.rb, line 59
def attribute_model_for(attribute_instruction)
  return @set.klass if attribute_instruction.associations_array.empty?

  attribute_instruction
    .associations_array
    .reduce(@set) do |obj, assoc|
      obj.reflections[assoc.to_s]&.klass
    end
end
case_insensitive?(attribute_instruction) click to toggle source
# File lib/active_set/sorting/active_record_strategy.rb, line 69
def case_insensitive?(attribute_instruction)
  attribute_instruction.operator.to_s.casecmp('i').zero?
end
direction_operator(direction) click to toggle source
# File lib/active_set/sorting/active_record_strategy.rb, line 73
def direction_operator(direction)
  return :desc if direction.to_s.downcase.start_with? 'desc'

  :asc
end
order_operation_for(attribute_instruction) click to toggle source

stackoverflow.com/a/44912964/2884386 Force null values to be sorted as if larger than any non-null value ASC => [-2, -1, 1, 2, nil] DESC => [nil, 2, 1, -1, -2]

# File lib/active_set/sorting/active_record_strategy.rb, line 48
def order_operation_for(attribute_instruction)
  attribute_model = attribute_model_for(attribute_instruction)

  arel_column = Arel::Table.new(attribute_model.table_name)[attribute_instruction.attribute]
  arel_column = case_insensitive?(attribute_instruction) ? arel_column.lower : arel_column
  arel_direction = direction_operator(attribute_instruction.value)
  nil_sorter = arel_column.send(arel_direction == :asc ? :eq : :not_eq, nil)

  attribute_model.order(nil_sorter).order(arel_column.send(arel_direction))
end
set_with_eager_loaded_associations() click to toggle source
# File lib/active_set/sorting/active_record_strategy.rb, line 39
def set_with_eager_loaded_associations
  associations_hash = @attribute_instructions.reduce({}) { |h, i| h.merge(i.associations_hash) }
  @set.eager_load(associations_hash)
end