module SimpleSearch OP_MAP = { :gt=>">", :ge=>">=", :lt=>"<", :le=>"<=", :eq=>"=", :ne=>"<>", :in=>"IN", :bt=>"BETWEEN", :between => "BETWEEN", :sw=>"LIKE", :startswith => "LIKE", :ew=>"LIKE", :endswith => "LIKE", :ct=>"LIKE", :contains => "LIKE", :like => "LIKE", :nc=>"NOT LIKE", :notcontains => "NOT LIKE", :notlike=>"NOT LIKE", :is=>"IS", :it=> 'IS NOT', :isnot => "IS NOT" } class Error < Exception; end module ActiveRecord def self.included(base) base.extend ClassMethods end module ClassMethods def simplesearch(params={}) arel = self.scoped unless self.is_a?(::ActiveRecord::Relation) other_params, where_params=filtered_params(params) # validate params arel = with_ss_where(arel,where_params) arel = with_ss_group(arel,other_params['group_by']) arel = with_ss_order(arel,other_params['order_by']) arel = with_ss_limit_offset(arel,other_params) arel end alias_method :ss, :simplesearch unless respond_to?(:ss) def filtered_params(params) where_params = {} other_params = {} params.each do |key,value| if ["group_by","page_by","page", "order_by"].include?(key) other_params[key]=value else matches = /(.*)_([a-z]+)$/.match(key) if matches.length==3 all, col, op = matches.to_a operands = SimpleSearch::OP_MAP.keys if operands.include?(op.to_sym) where_params[key]=value else logger.warning("SimpleSearch ignored #{key}. operand must be one of #{operands}") unless logger.nil? end else logger.warning("SimpleSearch ignored #{key}. it requires to end with _") unless logger.nil? end end end [other_params, where_params] end def with_ss_where(arel,params={}) params.each do |key,value| matches = /(.*)_([a-z]+)$/.match(key) all, col, op = matches.to_a where_col = col =~ /\./ ? col : "#{arel.table_name}.#{col}" #if no table name, the add it where_value = case op.to_sym when :gt,:ge,:lt,:le,:eq,:ne then value when :sw then "#{value}%" # LIKE when :ew then "%#{value}" # LIKE when :ct,:contains,:like then "%#{value}%" # LIKE when :nc,:notcontains,:notlike then "%#{value}%" # NOT LIKE when :is, :isnot, :it if ["NULL","null"].include?(value) then nil elsif ["TRUE","true"].include?(value) then true elsif ["FALSE","false"].include?(value) then false end end if op.to_sym==:in arel = arel.where("#{where_col}"=>value.split(',')) elsif [:bt, :between].include? op.to_sym first,second = value.split('..') arel = arel.where("#{where_col}"=>Range.new(first,second)) else arel = arel.where("#{where_col} #{SimpleSearch::OP_MAP[op.to_sym]} ?", where_value) end end arel end def with_ss_group(arel,group_by) arel= arel.group(group_by) if group_by arel end def with_ss_order(arel,order_by) arel= arel.order(order_by) if order_by arel end def with_ss_limit_offset(arel,params) page_num = (params['page'] || 1).to_i page_by = (params['page_by'] || 50).to_i arel = arel.limit(page_by).offset( (page_num-1)*page_by ) arel end end # end class methods end # end module ActiveRecord end # end module SimpleSearch