class TheGrid::Api::Command::Search

Public Instance Methods

configure(relation, params) click to toggle source
# File lib/the_grid/api/command/search.rb, line 3
def configure(relation, params)
  {}.tap do |o|
    o[:query] = params.fetch(:query, '').strip
    o[:searchable_columns] = params[:searchable_columns]
    o[:search_over] = params[:search_over]
    o[:search_over] = Hash[o[:search_over].zip] if o[:search_over].kind_of?(Array)
  end
end
run_on(relation, params) click to toggle source
# File lib/the_grid/api/command/search.rb, line 12
def run_on(relation, params)
  if params[:query].blank?
    relation
  elsif params[:search_over].present?
    search_over(relation, params)
  else
    relation.where build_conditions_for(relation, params)
  end
end

Private Instance Methods

build_conditions_for(relation, params) click to toggle source
# File lib/the_grid/api/command/search.rb, line 30
def build_conditions_for(relation, params)
  query = "%#{params[:query]}%"
  (params[:searchable_columns] || searchable_columns_of(relation)).map do |column|
    relation.table[column].matches(query)
  end.inject(:or)
end
build_conditions_for_associations_of(relation, params) click to toggle source
# File lib/the_grid/api/command/search.rb, line 37
def build_conditions_for_associations_of(relation, params)
  params[:search_over].each_with_object({}) do |options, conditions|
    assoc_name, assoc_fields = options
    assoc = relation.reflections[assoc_name.to_sym]
    assoc_condition = build_conditions_for(assoc.klass.scoped, params.merge(:searchable_columns => assoc_fields))
    conditions[assoc] = assoc_condition unless assoc_condition.blank?
  end
end
join_relations_with(condition, relation, assoc) click to toggle source
# File lib/the_grid/api/command/search.rb, line 63
def join_relations_with(condition, relation, assoc)
  primary_key, foreign_key = relationship_between(relation, assoc)

  relation.select(relation.table.primary_key).
    where(assoc.klass.arel_table.primary_key.eq(nil)).
    joins("LEFT OUTER JOIN #{assoc.table_name} ON #{primary_key.eq(foreign_key).and(condition).to_sql}")
end
relationship_between(relation, assoc) click to toggle source
# File lib/the_grid/api/command/search.rb, line 71
def relationship_between(relation, assoc)
  case assoc.macro
  when :belongs_to, :has_one
    primary_key = assoc.klass.arel_table.primary_key
    foreign_key = relation.table[assoc.foreign_key]
  when :has_many
    primary_key = relation.table.primary_key
    foreign_key = assoc.klass.arel_table[assoc.foreign_key]
  else
    raise ArgumentError, "Unable to search over #{assoc.macro}"
  end
  [ primary_key, foreign_key ]
end
row_ids_matched_for(relation, conditions) click to toggle source
# File lib/the_grid/api/command/search.rb, line 56
def row_ids_matched_for(relation, conditions)
  conditions.flat_map do |assoc, condition|
    query = join_relations_with(condition, relation, assoc).to_sql
    relation.connection.select_all(query).map(&:values)
  end.uniq
end
search_over(relation, params) click to toggle source
# File lib/the_grid/api/command/search.rb, line 46
def search_over(relation, params)
  search_relation = relation.where(build_conditions_for(relation, params))
  assoc_conditions = build_conditions_for_associations_of(relation, params.except(:searchable_columns))
  matched_row_ids = row_ids_matched_for(search_relation, assoc_conditions)

  conditions = assoc_conditions.values
  conditions << relation.table.primary_key.in(matched_row_ids) unless matched_row_ids.blank?
  relation.where(conditions.inject(:or))
end
searchable_columns_of(relation) click to toggle source
# File lib/the_grid/api/command/search.rb, line 24
def searchable_columns_of(relation)
  relation.column_names.select do |column_name|
    relation.columns_hash[column_name].type == :string
  end
end