module ActiveScaffold::Finder::ClassMethods

Public Instance Methods

condition_for_column(column, value, text_search = :full) click to toggle source

Generates an SQL condition for the given ActiveScaffold column based on that column’s database type (or form_ui … for virtual columns?). TODO: this should reside on the column, not the controller

# File lib/active_scaffold/finder.rb, line 35
def condition_for_column(column, value, text_search = :full)
  like_pattern = like_pattern(text_search)
  return unless column and column.search_sql and not value.blank?
  search_ui = column.search_ui || column.column.type
  begin
    if self.respond_to?("condition_for_#{column.name}_column")
      self.send("condition_for_#{column.name}_column", column, value, like_pattern)
    elsif self.respond_to?("condition_for_#{search_ui}_type")
      self.send("condition_for_#{search_ui}_type", column, value, like_pattern)
    else
      unless column.search_sql.instance_of? Proc
        case search_ui
          when :boolean, :checkbox
            ["#{column.search_sql} = ?", column.column.type_cast(value)]
          when :integer, :decimal, :float
            condition_for_numeric(column, value)
          when :string, :range
            condition_for_range(column, value, like_pattern)
          when :date, :time, :datetime, :timestamp
            condition_for_datetime(column, value)
          when :select, :multi_select, :country, :usa_state
          ["#{column.search_sql} in (?)", Array(value)]
          else
            if column.column.nil? || column.column.text?
              ["#{column.search_sql} #{ActiveScaffold::Finder.like_operator} ?", like_pattern.sub('?', value)]
            else
              ["#{column.search_sql} = ?", column.column.type_cast(value)]
            end
        end
      else
        column.search_sql.call(value)
      end
    end
  rescue Exception => e
    logger.error Time.now.to_s + "#{e.inspect} -- on the ActiveScaffold column :#{column.name}, search_ui = #{search_ui} in #{@controller.class}"
    raise e
  end
end
condition_for_datetime(column, value, like_pattern = nil) click to toggle source
# File lib/active_scaffold/finder.rb, line 140
def condition_for_datetime(column, value, like_pattern = nil)
  conversion = column.column.type == :date ? :to_date : :to_time
  from_value = condition_value_for_datetime(value[:from], conversion)
  to_value = condition_value_for_datetime(value[:to], conversion)

  if from_value.nil? and to_value.nil?
    nil
  elsif !from_value
    ["#{column.search_sql} <= ?", to_value.to_s(:db)]
  elsif !to_value
    ["#{column.search_sql} >= ?", from_value.to_s(:db)]
  else
    ["#{column.search_sql} BETWEEN ? AND ?", from_value.to_s(:db), to_value.to_s(:db)]
  end
end
condition_for_null_type(column, value, like_pattern = nil) click to toggle source
# File lib/active_scaffold/finder.rb, line 164
def condition_for_null_type(column, value, like_pattern = nil)
  case value.to_sym
  when :null
    ["#{column.search_sql} is null"]
  when :not_null
    ["#{column.search_sql} is not null"]
  else
    nil
  end
end
condition_for_numeric(column, value) click to toggle source
# File lib/active_scaffold/finder.rb, line 74
def condition_for_numeric(column, value)
  if !value.is_a?(Hash)
    ["#{column.search_sql} = ?", condition_value_for_numeric(column, value)]
  elsif value[:from].blank? or not ActiveScaffold::Finder::NumericComparators.include?(value[:opt])
    nil
  elsif value[:opt] == 'BETWEEN'
    ["#{column.search_sql} BETWEEN ? AND ?", condition_value_for_numeric(column, value[:from]), condition_value_for_numeric(column, value[:to])]
   else
    ["#{column.search_sql} #{value[:opt]} ?", condition_value_for_numeric(column, value[:from])]
  end
end
condition_for_range(column, value, like_pattern = nil) click to toggle source
# File lib/active_scaffold/finder.rb, line 86
def condition_for_range(column, value, like_pattern = nil)
  if !value.is_a?(Hash)
    if column.column.nil? || column.column.text?
      ["#{column.search_sql} #{ActiveScaffold::Finder.like_operator} ?", like_pattern.sub('?', value)]
    else
      ["#{column.search_sql} = ?", column.column.type_cast(value)]
    end
  elsif value[:from].blank?
    nil
  elsif ActiveScaffold::Finder::StringComparators.values.include?(value[:opt])
    ["#{column.search_sql} LIKE ?", value[:opt].sub('?', value[:from])]
  elsif value[:opt] == 'BETWEEN'
    ["#{column.search_sql} BETWEEN ? AND ?", value[:from], value[:to]]
  elsif ActiveScaffold::Finder::NumericComparators.include?(value[:opt])
    ["#{column.search_sql} #{value[:opt]} ?", value[:from]]
  else
    nil
  end
end
condition_for_record_select_type(column, value, like_pattern = nil) click to toggle source
# File lib/active_scaffold/finder.rb, line 156
def condition_for_record_select_type(column, value, like_pattern = nil)
  if value.is_a?(Array)
    ["#{column.search_sql} IN (?)", value]
  else
    ["#{column.search_sql} = ?", value]
  end
end
condition_value_for_datetime(value, conversion = :to_time) click to toggle source
# File lib/active_scaffold/finder.rb, line 106
def condition_value_for_datetime(value, conversion = :to_time)
  if value.is_a? Hash
    Time.zone.local(*[:year, :month, :day, :hour, :minute, :second].collect {|part| value[field][part].to_i}) rescue nil
  elsif value.respond_to?(:strftime)
    value.send(conversion)
  else
    Time.zone.parse(value).in_time_zone.send(conversion) rescue nil
  end unless value.nil? || value.blank?
end
condition_value_for_numeric(column, value) click to toggle source
# File lib/active_scaffold/finder.rb, line 116
def condition_value_for_numeric(column, value)
  return value if value.nil?
  value = i18n_number_to_native_format(value) if [:i18n_number, :currency].include?(column.options[:format])
  case (column.search_ui || column.column.type)
  when :integer   then value.to_i rescue value ? 1 : 0
  when :float     then value.to_f
  when :decimal   then ActiveRecord::ConnectionAdapters::Column.value_to_decimal(value)
  else
    value
  end
end
create_conditions_for_columns(tokens, columns, text_search = :full) click to toggle source

Takes a collection of search terms (the tokens) and creates SQL that searches all specified ActiveScaffold columns. A row will match if each token is found in at least one of the columns.

# File lib/active_scaffold/finder.rb, line 11
def create_conditions_for_columns(tokens, columns, text_search = :full)
  # if there aren't any columns, then just return a nil condition
  return unless columns.length > 0
  like_pattern = like_pattern(text_search)

  tokens = [tokens] if tokens.is_a? String

  where_clauses = []
  columns.each do |column|
    where_clauses << ((column.column.nil? || column.column.text?) ? "#{column.search_sql} #{ActiveScaffold::Finder.like_operator} ?" : "#{column.search_sql} = ?")
  end
  phrase = "(#{where_clauses.join(' OR ')})"

  sql = ([phrase] * tokens.length).join(' AND ')
  tokens = tokens.collect do |value|
    columns.collect {|column| (column.column.nil? || column.column.text?) ? like_pattern.sub('?', value) : column.column.type_cast(value)}
  end.flatten

  [sql, *tokens]
end
i18n_number_to_native_format(value) click to toggle source
# File lib/active_scaffold/finder.rb, line 128
def i18n_number_to_native_format(value)
  native = '.'
  delimiter = I18n.t('number.format.delimiter')
  separator = I18n.t('number.format.separator')
  return value if value.blank? || !value.is_a?(String)
  unless delimiter == native && !value.include?(separator) && value !~ /\.\d{3}$/
    value.gsub(/[^0-9\-#{I18n.t('number.format.separator')}]/, '').gsub(I18n.t('number.format.separator'), native)
  else
    value
  end
end
like_pattern(text_search) click to toggle source
# File lib/active_scaffold/finder.rb, line 175
def like_pattern(text_search)
  case text_search
    when :full then '%?%'
    when :start then '?%'
    when :end then '%?'
    else '?'
  end
end