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 41 def condition_for_column(column, value, text_search = :full) like_pattern = like_pattern(text_search) if self.respond_to?("condition_for_#{column.name}_column") return self.send("condition_for_#{column.name}_column", column, value, like_pattern) end return unless column and column.search_sql and not value.blank? search_ui = column.search_ui || (column.column and column.column[:type]) begin if search_ui && 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 => active_scaffold_config.model.db.send(:typecast_value_boolean, 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 => Array(value)} else if column.column.nil? || column.column[:type] == :string column.search_sql.ilike(like_pattern.sub('?', value)) else {column.search_sql => active_scaffold_config.model.new.send(:typecast_value, column.name, 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 #{self.name}" raise e end end
condition_for_datetime(column, value, like_pattern = nil)
click to toggle source
# File lib/active_scaffold/finder.rb, line 156 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.sql_expr <= to_value.to_s(:db) elsif !to_value column.search_sql.sql_expr >= from_value.to_s(:db) else {column.search_sql => 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 176 def condition_for_null_type(column, value, like_pattern = nil) case value.to_sym when :null {column.search_sql => nil} when :not_null ~{column.search_sql => nil} else nil end end
condition_for_numeric(column, value)
click to toggle source
# File lib/active_scaffold/finder.rb, line 81 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 => condition_value_for_numeric(column, value[:from])..condition_value_for_numeric(column, value[:to])} else Sequel::SQL::PlaceholderLiteralString.new("? #{value[:opt]} ?", [column.search_sql, 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 93 def condition_for_range(column, value, like_pattern = nil) if !value.is_a?(Hash) if column.column.nil? || column.column[:type] == :string column.search_sql.ilike(like_pattern.sub('?', value)) else {column.search_sql => active_scaffold_config.model.new.send(:typecast_value, column.name, value)} end elsif ActiveScaffold::Finder::NullComparators.include?(value[:opt]) condition_for_null_type(column, value[:opt], like_pattern) elsif value[:from].blank? nil elsif ActiveScaffold::Finder::StringComparators.values.include?(value[:opt]) column.search_sql.ilike(value[:opt].sub('?', value[:from])) elsif value[:opt] == 'BETWEEN' {column.search_sql => value[:from]..value[:to]} elsif ActiveScaffold::Finder::NumericComparators.include?(value[:opt]) Sequel::SQL::PlaceholderLiteralString.new("? #{value[:opt]} ?", [column.search_sql, 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 172 def condition_for_record_select_type(column, value, like_pattern = nil) {column.search_sql => value} end
condition_value_for_datetime(value, conversion = :to_time)
click to toggle source
# File lib/active_scaffold/finder.rb, line 115 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[part].to_i}) rescue nil elsif value.respond_to?(:strftime) value.send(conversion) elsif conversion == :to_date Date.strptime(value, I18n.t('date.formats.default')) rescue nil else parts = Date._parse(value) time_parts = [[:hour, '%H'], [:min, '%M'], [:sec, '%S']].collect {|part, format_part| format_part if parts[part].present?}.compact format = "#{I18n.t('date.formats.default')} #{time_parts.join(':')} #{'%z' if parts[:offset].present?}" time = DateTime.strptime(value, format) time = Time.zone.local_to_utc(time) unless parts[:offset] time.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 132 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 active_scaffold_config.model.db.send(:typecast_value_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 7 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 # for typecasting purposes obj = active_scaffold_config.model.new orig_raise_on_typecast_failure = active_scaffold_config.model.raise_on_typecast_failure active_scaffold_config.model.raise_on_typecast_failure = true result = tokens.collect do |token| pattern = like_pattern.sub('?', token) columns.collect do |column| if column.column.nil? or column.column[:type] == :string column.search_sql.ilike(pattern) else begin {column.search_sql => obj.send(:typecast_value, column.name, token)} rescue Sequel::InvalidValue end end end.compact.inject {|a,b| (a | b)} end.inject {|a,b| (a & b)} # restore original setting active_scaffold_config.model.raise_on_typecast_failure = orig_raise_on_typecast_failure result end
i18n_number_to_native_format(value)
click to toggle source
# File lib/active_scaffold/finder.rb, line 144 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 187 def like_pattern(text_search) case text_search when :full then '%?%' when :start then '?%' when :end then '%?' else '?' end end