require 'itrigga/core_ext/string' module Trigga module ParamFu def self.included(base) base.extend(AllMethods) base.send(:include, AllMethods) end module AllMethods def require_obj_or_id(opts, key) obj_or_id(opts,key) raise ArgumentError.new("#{key} or #{key_with_id(key)} are required") unless opts[key_with_id(key)] opts end def require_param(opts, *keys) keys.to_a.each do |k| raise ArgumentError.new("#{k} is required") unless opts[k] end opts end def obj_or_id(opts, key) opts[key_with_id(key)] ||= opts[key].id if opts[key] end def key_with_id(key) (key.to_s + '_id').to_sym end def require_one_of( opts, *keys ) present = (opts.keys & keys) raise ArgumentError.new( "at least one of the arguments #{keys.inspect} is required" ) if present.empty? return present end def id_or_name_condition(table, val) condition = {:where => nil, :values=>nil} unless val.to_s.empty? unless val.to_s.match(/[^0-9]/) condition[:where] = "#{table}.id = ?" condition[:values] = val.to_i else condition[:where] = "#{table}.name LIKE ?" condition[:values] = "#{'%' + val.gsub(/\s*\(\d+\)/,"") + '%'}" end end condition end # fallback when we don't have ActiveSupport's pluralize method available def to_plural(s) (s.match(/[aeiou]$/i) ? s + 's' : s + 'es' ) end # Give this a hash per model in the format: # Model class => { param_name => { :operator=>(db operator - defaults to '='), # => :field_name=>(field_name in the database - defaults to param_name) # => } # => } # and it will return an ActiveRecord finder :conditions clause using any params which are present in the given :params # e.g. if you have params = { :created_date_from=>'2011-10-09 00:01:02', :status=>'A', :click_url=>'items.html' } # then calling: # # params_to_conditions( :params=>params, :models=>{ # Click => {:click_url=>{ :operator=>"like", :field_name=>'request_path' }, # :status => {}, # :http_referer=>{:operator=>'like'}, # :created_date_from => {:operator=> ">=", :field_name=>'timestamp'} # } # }) # # # will generate: # # [ 'clicks.request_path like (?) AND clicks.status = ? AND clicks.created_date_from >= ?', '%items.html%', 'A', '2011-10-09 00:01:02' ] # # It will ignore any criteria given which are NOT in the given :params hash # def params_to_conditions( opts={} ) require_param(opts, :params, :models) conds = { :where=>[], :values=>[] } opts[:models].each { |model_class, field_defs| parsed_model_conditions = model_conditions( opts[:params], model_class, field_defs ) conds[:where] += parsed_model_conditions[:where] conds[:values] += parsed_model_conditions[:values] } [ conds[:where].join(" AND ") ] + conds[:values] end def model_conditions( opts, model_class, field_defs ) h = {:where=>[], :values=>[]} field_defs.each{ |field_name, definition| parsed_field_def = parse_field_definition( opts, model_class, field_name, definition ) h[:where] += parsed_field_def[:where] h[:values] += parsed_field_def[:values] } h end def parse_field_definition( opts, model_class, param_name, definition ) c = {:where=>[], :values=>[]} if opts[param_name] unless opts[param_name].to_s.empty? c[:where] << "( #{model_class.table_name}.#{definition[:field_name] || param_name.to_s} #{definition[:operator] || '='} (?) )" c[:values] << ( definition[:operator] =~ /\blike\b/i ? opts[param_name].to_active_record_condition : opts[param_name] ) end end c end end end end