module Collate::ActiveRecordExtension
Attributes
collate_field_groups[RW]
collate_filters[RW]
collate_sorters[RW]
default_field_group[RW]
default_group[RW]
field_group_options[RW]
group_options[RW]
Public Instance Methods
collate(params)
click to toggle source
# File lib/collate/active_record_extension.rb, line 50 def collate params initialize_collate ar_rel = self.all self.collate_filters.each do |group_key, group| group[:filters].each do |filter| if params[filter.param_key].present? || params["#{filter.param_key}[]"].present? ar_rel = apply_filter(ar_rel, filter, params[filter.param_key] || params["#{filter.param_key}[]"]) end end end self.collate_sorters.each do |sorter| sort_field, _, sort_direction = params[:order].to_s.partition(' ') if(sort_field == sorter.field && ['ASC','DESC'].include?(sort_direction)) ar_rel = apply_sorter ar_rel, sorter, params[:order] end end default_sort = self.collate_sorters.select { |s| s.default }.first if default_sort.present? ar_rel = apply_sorter ar_rel, default_sort, "#{default_sort.field} #{default_sort.default.upcase}", 'order' params[:order] ||= "#{default_sort.field} #{default_sort.default.upcase}" end ar_rel end
collate_filter_group(group_name, **opts, &blk)
click to toggle source
# File lib/collate/active_record_extension.rb, line 38 def collate_filter_group group_name, **opts, &blk initialize_collate opts[:label] ||= group_name.to_s.titleize self.field_group_options = opts self.default_field_group = group_name blk.call self.default_field_group = nil end
collate_group(name, **opts, &blk)
click to toggle source
# File lib/collate/active_record_extension.rb, line 29 def collate_group name, **opts, &blk initialize_collate opts[:label] ||= name.to_s.titleize self.group_options = opts self.default_group = name blk.call end
collate_on(field, opts={})
click to toggle source
# File lib/collate/active_record_extension.rb, line 13 def collate_on field, opts={} initialize_collate new_filter = Collate::Filter.new(field, opts.merge({base_model_table_name: self.table_name})) self.collate_filters[self.default_group] ||= {filters: []}.merge(self.group_options) self.collate_filters[self.default_group][:filters] << new_filter if self.default_field_group self.collate_field_groups[self.default_group] ||= {filter_groups: {}}.merge(self.group_options) self.collate_field_groups[self.default_group][:filter_groups][self.default_field_group] ||= {filters: {}}.merge(self.field_group_options) self.collate_field_groups[self.default_group][:filter_groups][self.default_field_group][:filters][new_filter.field_group_type] = new_filter end end
collate_sort(field, opts={})
click to toggle source
# File lib/collate/active_record_extension.rb, line 7 def collate_sort field, opts={} initialize_collate self.collate_sorters << Collate::Sorter.new(field, opts.merge({base_model_table_name: self.table_name})) end
Private Instance Methods
apply_filter(ar_rel, filter, param_value)
click to toggle source
# File lib/collate/active_record_extension.rb, line 120 def apply_filter ar_rel, filter, param_value ar_rel, ar_method, query_string, filter_value = if filter.field.is_a?(Array) full_query_strings = [] full_filter_values = [] filter.field.each do |filter_field| ar_rel, ar_method, query_string, filter_value = get_filter_data ar_rel, filter_field, filter, param_value full_query_strings << query_string full_filter_values << filter_value end [ar_rel, ar_method, full_query_strings.join(' OR '), full_filter_values.flatten] else get_filter_data ar_rel, filter.field.dup, filter, param_value end ar_rel = if query_string.include?('?') if filter.or || filter.field.is_a?(Array) ar_rel.send(ar_method, query_string, *filter_value) else ar_rel.send(ar_method, query_string, filter_value) end else ar_rel.send(ar_method, query_string) end end
apply_sorter(ar_rel, sorter, param_value, sorting_method = 'reorder')
click to toggle source
# File lib/collate/active_record_extension.rb, line 98 def apply_sorter ar_rel, sorter, param_value, sorting_method = 'reorder' if sorter.joins sorter.joins.each do |join| ar_rel = ar_rel.joins(join) end end ar_rel = ar_rel.select("#{ar_rel.table_name}.*") sorter.field_select = sorter.field unless sorter.field_select ar_rel = ar_rel.select(sorter.field_select) ar_rel = if sorter.nulls_first ar_rel.send(sorting_method, "#{param_value} NULLS FIRST") elsif sorter.nulls_last ar_rel.send(sorting_method, "#{param_value} NULLS LAST") else ar_rel.send(sorting_method, param_value) end end
get_filter_data(ar_rel, filter_field, filter, param_value)
click to toggle source
# File lib/collate/active_record_extension.rb, line 148 def get_filter_data ar_rel, filter_field, filter, param_value filter_value = if param_value.duplicable? param_value.dup else param_value end if filter.joins filter.joins.each do |join| ar_rel = if filter.joins_prefix prefix_index = 0 original_query = ar_rel.model.unscoped.joins(join).to_sql previous_replacements = {} new_query = original_query.split('INNER JOIN').drop(1).map do |chunk| table_name = /([\"'])(?:\\\1|.)*?\1/.match(chunk)[0].gsub('"','') if previous_replacements.has_key?("\"#{table_name}\"") previous_replacements.delete("\"#{table_name}\"") prefix_index += 1 check_alias_match = /(?<="#{table_name}" ")[^"]*(?=")/.match(chunk) if check_alias_match chunk = chunk.partition(check_alias_match[0]).drop(1).join('').prepend('"').gsub(check_alias_match[0], "#{table_name}") end end previous_replacements.each do |the_match, replacement| chunk = chunk.gsub(the_match, replacement) end replaced = chunk.gsub("\"#{table_name}\"", "\"#{filter.joins_prefix[prefix_index]}#{table_name}\"") previous_replacements["\"#{table_name}\""] = "\"#{filter.joins_prefix[prefix_index]}#{table_name}\"" "\"#{table_name}\" AS #{replaced}" end.join(' INNER JOIN ').prepend('INNER JOIN ') ar_rel.joins(new_query) else ar_rel.joins(join) end end end ar_rel = ar_rel.group(filter.grouping) if filter.grouping field_query = filter_field filter.field_transformations.each do |ft| transformation = ft transformation = ft[0] if !transformation.is_a? Symbol field_query = case transformation when :date_difference "age(#{ft[1]}, #{field_query})" when :date_part "date_part('#{ft[1]}', #{field_query})" when :array_agg "array_agg(#{field_query})" when :downcase "lower(#{field_query})" when :split "string_to_array(#{field_query}, '#{ft[1]}')" when :array_length "array_length(#{field_query}, '#{ft[1]}')" else field_query end end if filter.component[:load_records] results = filter.component[:load_record_model].constantize.where("#{filter.component[:load_record_field]} IN (?)", filter_value) filter.component[:values] = results.map{ |r| {id: r.id, text: r.public_send(filter.component[:load_record_text_method])} } end if filter.component[:tags] filter.component[:values] = filter_value.map { |v| {id: v, text: v} } end filter.value_transformations.each do |vt| transformation = vt transformation = vt[0] if !transformation.is_a? Symbol filter_value = [filter_value] unless filter.or filter_value.each_with_index do |f, i| filter_value[i] = case transformation when :join "#{f.join(vt[1])}" when :as_array "{#{f}}" when :downcase f.downcase when :string_part if vt.is_a? Symbol "%#{f}%" else sprintf vt[1], f end when :to_json "{\"#{vt[1]}\": \"#{f}\"}" else f end end filter_value = filter_value[0] unless filter.or end ar_method = filter.having ? "having" : "where" query_string = case filter.operator when :eq "#{field_query} = ?" when :ilike "#{field_query} ILIKE ?" when :in "#{field_query} IN (?)" when :le "#{field_query} <= ?" when :ge "#{field_query} >= ?" when :null "#{field_query} IS NULL" when :contains "#{field_query} @> ?" when :present? "#{field_query} = true" when :& "#{field_query} && ?" else "" end query_string = filter_value.length.times.collect{query_string}.join(' OR ') if filter.or query_string = "NOT(#{query_string})" if filter.not [ar_rel, ar_method, query_string, filter_value] end
initialize_collate()
click to toggle source
# File lib/collate/active_record_extension.rb, line 82 def initialize_collate if !self.respond_to? :collate_filters class << self attr_accessor :collate_filters, :collate_sorters, :default_group, :group_options, :default_field_group, :collate_field_groups, :field_group_options end self.collate_filters ||= {} self.collate_sorters ||= [] self.default_group ||= :main self.group_options ||= {} self.collate_field_groups ||= {} end end