module GenericSearch::BuildMethods
def self.custom_config
{ :transitions => { :script_status => { :field => :script_status_id, :lambda => lambda do |operator, value| Status.where("name #{operator} ?", value).collect(&:id) end } } }
end
Public Instance Methods
build_group(group)
click to toggle source
# File lib/generic_search/build_methods.rb, line 183 def build_group(group) if group.blank? return end group_entities = group.scan(/\w+\(.*?\)/) @joins ||= [] group_table_fields_map = {} @group = [] @group_object_access = [] group_entities.each do |group_entity| match, table, select_fields = *group_entity.match(/(\w+)\(*([\s\w,]*)\)*/) table.strip! fields = select_fields.split(/\s*,\s*/) group_table_fields_map[table] = fields #@joins << @base_class._table_relation[table.strip] if table != @base_class.table_name table.strip! if table != @base_table relation_name = (@base_class._table_relation[table] || (@base_class._relation_table[table.intern] ? table.intern : nil)) table_name = @base_class._table_relation[table] ? table : @base_class._relation_table[table.intern] @joins << relation_name if relation_name else table_name = table end fields.each do |field| @group << "#{table_name}.#{field}" #@group_object_access << (@base_table == table ? field : "#{@base_class._table_relation[table]}.#{field}") @group_object_access << (@base_table == table_name ? field : "#{relation_name}.#{field}") end end group_table_fields_map.each do |table, column_names| validate_columns(table, column_names, :group) end end
build_having(having)
click to toggle source
# File lib/generic_search/build_methods.rb, line 227 def build_having(having) if having.blank? return end self.having = having.gsub(/(^"|"$)/, '').strip end
build_limit(limit)
click to toggle source
# File lib/generic_search/build_methods.rb, line 245 def build_limit(limit) #TODO: Test required for group.blank? if self.options[:no_results] or !self.group.blank? self.limit = nil else self.limit = limit.blank? ? GenericSearch::DEFAULT_LIMIT : limit end end
build_options(options)
click to toggle source
options = no_results, no_limit_count
# File lib/generic_search/build_methods.rb, line 265 def build_options(options) self.options = {} return if options.blank? if options.include? 'no_results' self.options[:no_results] = true end if options.include? 'no_limit_count' self.options[:no_limit_count] = true end if options.include? 'distinct' self.options[:distinct] = true end if options.include? 'no_grouped_results' self.options[:no_grouped_results] = true end end
build_response()
click to toggle source
# File lib/generic_search/build_methods.rb, line 289 def build_response self.response = { :success => self.status == :ok ? true : false, :code => self.status == :ok ? 200 : 400, :status => self.status, :message => self.messages, :client_IP => nil, :controller => nil, :server => Socket.gethostname, :where_clause => self.where, :no_limit_result_count => self.no_limit_count, :limit_result_count => self.limit_result_count, :timestamp => Time.now, :groups => self.grouped_results #"groups" => params.has_key?(:no_results) ? [] : @grouped_results } end
build_results(results)
click to toggle source
# File lib/generic_search/build_methods.rb, line 153 def build_results(results) table_selected_fields = {} selects = if results.blank? [self.base_class.table_name] else selects = results.scan(/\w+\(.*?\)/) results_clone = results.clone selects.each do |select| results_clone.gsub!(select, '') end selects += results_clone.split(/,/).delete_if(&:blank?) selects end selects.each do |select| match, table, select_fields = *select.match(/(\w+)\(*([\s\w,]*)\)*/) table_selected_fields[table] = select_fields.blank? ? nil : select_fields.strip.split(/\s*,\s*/) end table_selected_fields.each do |table_name, column_names| validate_columns(table_name, column_names, :results) end #TODO: self.select = table_selected_fields.clone self.select = table_selected_fields end
build_sort_order(sort_order)
click to toggle source
# File lib/generic_search/build_methods.rb, line 235 def build_sort_order(sort_order) self.sort_order = if sort_order.nil? "\"#{self.base_table}\".\"id\" ASC" elsif sort_order.strip == "\"\"" || sort_order.strip == "\'\'" || sort_order.strip == '' nil else sort_order.strip end end
build_start(start)
click to toggle source
# File lib/generic_search/build_methods.rb, line 255 def build_start(start) #TODO: Test required for group.blank? self.start = if self.options[:no_results] or !self.group.blank? nil else start.blank? ? 0 : start end end
build_where(query)
click to toggle source
# File lib/generic_search/build_methods.rb, line 18 def build_where(query) if query.blank? return end query_table_list = [] query.each_line('),') do |segment| segment.gsub!(/,$/, "") query_table_list << segment end query_per_table = Array.new @joins = [] query_table_list.each do |query_item| table, search_params = query_item.to_s.split('(', 2) table.strip! column_names = [] if table.strip != @base_table relation_name = @base_class._table_relation[table.strip] @joins << relation_name if relation_name end search_params ||= '' search_params.gsub!(/\)$/, "") single_param_array = search_params.strip.split(/\s*,\s*/) single_param_array_length = single_param_array.length column_values = [] current_value = single_param_array[0] i=0 until i >= single_param_array_length next_value = single_param_array[i + 1] if next_value.nil? or next_value.match(/([<>=!~]|between)/) column_values << current_value current_value = next_value else current_value << (',' + next_value) end i = i + 1 end column_values.each do |search_param| search_param.gsub!(/,$/, "") if search_param.match(/(\w+)\s+between\s+(\*?.*)and(\*?.*)/i) key, from, to = $1.strip, $2.strip, $3.strip single_search_param = if from.match(/^\d+$/) and to.match(/^\d+$/) "\"#{table}\".\"#{key}\" between #{from} and #{to}" else "\"#{table}\".\"#{key}\" between '#{from.to_time.to_s(:db)}' and '#{to.to_time.to_s(:db)}'" end else search_param.match(/(\w+)(\s*[<>=!~]*\s*)(\*?.*)/) key, operator, value = $1.strip, $2.strip, $3.strip if operator == '=' if value.include? '*' value.gsub!('*', '%') value = "#{value}" operator = 'ILIKE' #elsif value.include? '/' # value = "(#{value})" # operator = 'in' #elsif value.include? '|' # value = "(#{value})" # operator = 'in' #else # value = "'#{value}'" end else value = "#{value}" end config = GenericSearch.config[table.intern] config = (config and config[:for_where]) key_intern = key.intern #TODO: Test Requires single_search_param = if config and config.has_key?(key_intern) config = config[key_intern] value = config[:lambda].call(operator, value) #subQuery = value.is_a?(Array) ? "in (#{value.blank? ? 'NULL' : value.join(',')})" : "= '#{value}'" subQuery = if value.is_a?(Array) if value.blank? "in (NULL)" else "in (#{value.join(',')})" end else "= '#{value}'" end "\"#{table}\".\"#{config[:field]}\" #{subQuery}" elsif operator == '=' and value.include?('|') value = value.gsub(/\s*\|\s*/, ' OR ').split(/(AND|OR)/) .collect do |val| val.match(/(AND|OR)/) ? val : "\"#{table}\".\"#{key}\" #{operator} '#{val.strip}'" end.join(' ') "(#{value})" elsif operator == '=' and value.include?(',') # AND Support should be handled in a different way # using group=user.id, having='ARRAY_AGG(users.id) @> ARRAY[23, 34, 45]::integer[]' else "\"#{table}\".\"#{key}\" #{operator} '#{value}'" end column_names << key end query_per_table << single_search_param if single_search_param end self.validate_columns(table, column_names, :query) end self.where = query_per_table.join(' AND ') end