class Para::Search::Distinct

Attributes

Public Class Methods

new(search) click to toggle source
# File lib/para/search/distinct.rb, line 13
def initialize(search)
  @search = search
  @sort_index ||= 0
end

Public Instance Methods

result() click to toggle source
# File lib/para/search/distinct.rb, line 18
def result
  selects = build_selects
  search.result.select(selects).distinct
end

Private Instance Methods

build_alias(sql, index) click to toggle source
# File lib/para/search/distinct.rb, line 78
def build_alias(sql, index)
  Arel::Nodes::InfixOperation.new(
    'AS',
    format_string(sql),
    Arel::Nodes::SqlLiteral.new(index)
  ).to_sql
end
build_selects() click to toggle source
# File lib/para/search/distinct.rb, line 25
def build_selects
  ([table_wildcard_select] + sort_selects).join(', ')
end
format_string(sql) click to toggle source
# File lib/para/search/distinct.rb, line 86
def format_string(sql)
  sql_lower(sql_unaccent(sql_stringify(sql)))
end
next_sort_index() click to toggle source
# File lib/para/search/distinct.rb, line 70
def next_sort_index
  ['sort', @sort_index += 1].join('_')
end
process_attribute(sort) click to toggle source
# File lib/para/search/distinct.rb, line 50
def process_attribute(sort)
  sort_index = next_sort_index
  sql = [sort.attr.relation.name, sort.attr.name].join('.')

  replace_sort(sort, sort_index)
  build_alias(sql, sort_index)
end
process_sql_literal(sort) click to toggle source

When given an SQL literal, we store the sql expression in a named SELECT variable, and replace the expression by its variable name inside of the ransack sort instance

# File lib/para/search/distinct.rb, line 62
def process_sql_literal(sort)
  sort_index = next_sort_index
  sql = sort.attr.to_s

  replace_sort(sort, sort_index)
  build_alias(sql, sort_index)
end
replace_sort(sort, sort_index) click to toggle source
# File lib/para/search/distinct.rb, line 74
def replace_sort(sort, sort_index)
  sort.instance_variable_set(:@attr, Arel::Nodes::SqlLiteral.new(sort_index))
end
sort_selects() click to toggle source
# File lib/para/search/distinct.rb, line 33
def sort_selects
  return [] unless search

  search.sorts.map do |sort|
    case sort.attr
    when Arel::Attributes::Attribute then process_attribute(sort)
    when Arel::Nodes::SqlLiteral then process_sql_literal(sort)
    #
    # Explicitly raise here to avoid the system to swallow sorting errors,
    # since any unsupported class must have been explicitly used by the
    # developer, and debugging it would be hard without an exception
    #
    else raise "Unsupported sort attribute class : #{ sort.attr.class.name }"
    end
  end
end
sql_lower(sql) click to toggle source
# File lib/para/search/distinct.rb, line 90
def sql_lower(sql)
  Arel::Nodes::NamedFunction.new('LOWER', [sql])
end
sql_stringify(sql) click to toggle source
# File lib/para/search/distinct.rb, line 98
def sql_stringify(sql)
  Arel::Nodes::NamedFunction.new(
    'CAST', [
      Arel::Nodes::InfixOperation.new(
        'AS',
        Arel::Nodes::SqlLiteral.new(sql),
        Arel::Nodes::SqlLiteral.new('text')
      )
    ]
  )
end
sql_unaccent(sql) click to toggle source
# File lib/para/search/distinct.rb, line 94
def sql_unaccent(sql)
  Arel::Nodes::NamedFunction.new('UNACCENT', [sql])
end
table_wildcard_select() click to toggle source
# File lib/para/search/distinct.rb, line 29
def table_wildcard_select
  [search.klass.table_name, '*'].join('.')
end