1 # Mixin module providing a method to convert filters into a list of SQL
2 # fragments suitable to be fed to ActiveRecord #where.
11 # +filters+ array of conditions, each being [column, operator, operand]
12 # +ar_table_name+ name of SQL table
16 # :cond_out array of SQL fragments for each filter expression
17 # :param_out array of values for parameter substitution in cond_out
18 def record_filters filters, ar_table_name
22 filters.each do |filter|
23 attr, operator, operand = filter
24 if !filter.is_a? Array
25 raise ArgumentError.new("Invalid element in filters array: #{filter.inspect} is not an array")
26 elsif !operator.is_a? String
27 raise ArgumentError.new("Invalid operator '#{operator}' (#{operator.class}) in filter")
28 elsif !model_class.searchable_columns(operator).index attr.to_s
29 raise ArgumentError.new("Invalid attribute '#{attr}' in filter")
31 case operator.downcase
32 when '=', '<', '<=', '>', '>=', '!=', 'like'
33 if operand.is_a? String
37 cond_out << "#{ar_table_name}.#{attr} #{operator} ?"
38 if (# any operator that operates on value rather than
40 operator.match(/[<=>]/) and
41 model_class.attribute_column(attr).type == :datetime)
42 operand = Time.parse operand
45 elsif operand.nil? and operator == '='
46 cond_out << "#{ar_table_name}.#{attr} is null"
47 elsif operand.nil? and operator == '!='
48 cond_out << "#{ar_table_name}.#{attr} is not null"
50 raise ArgumentError.new("Invalid operand type '#{operand.class}' "\
51 "for '#{operator}' operator in filters")
54 if operand.is_a? Array
55 cond_out << "#{ar_table_name}.#{attr} #{operator} (?)"
58 raise ArgumentError.new("Invalid operand type '#{operand.class}' "\
59 "for '#{operator}' operator in filters")
62 operand = [operand] unless operand.is_a? Array
65 cl = ArvadosModel::kind_class op
67 cond << "#{ar_table_name}.#{attr} like ?"
68 param_out << cl.uuid_like_pattern
73 cond_out << cond.join(' OR ')
77 {:cond_out => cond_out, :param_out => param_out}