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=>[] }
puts "
opts = #{opts.inspect}
"
opts[:models].each { |model_class, field_defs|
puts "model_class = #{model_class.inspect}"
parsed_model_conditions = model_conditions( opts[:params], model_class, field_defs )
puts "parsed_model_conditions = #{parsed_model_conditions.inspect}"
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]
c[:where] << "( #{model_class.table_name}.#{definition[:field_name] || param_name.to_s} #{definition[:operator] || '='} (?) )"
c[:values] << opts[param_name]
end
c
end
end
end
end