module DynamicQuery::CombinedQuery

Public Instance Methods

combine_query(query, relations, opts = {}) click to toggle source
# File lib/dynamic_query/combined_query.rb, line 37
def combine_query(query, relations, opts = {})
  conds = conditions(query).first || {}
  models = relations.each_slice(3).map { |sec| sec.first }
  foreign_keys = relations - models
  
  selected_records = filter_conditioned_records(models, foreign_keys, conds)
  selected_records = remove_unlinked_records(selected_records, foreign_keys)
  result = join(selected_records, foreign_keys)
  
  result.delete_if { |row| row.include? nil } unless opts[:accept_null]
  result.map { |row| row.map { |rec| rec.attributes.keep_if { |k, _| k.to_s !~ /id$/ } } } unless opts[:reveal_id]
  
  result
end
conditions(query, table = nil) click to toggle source
# File lib/dynamic_query/combined_query.rb, line 8
def conditions(query, table = nil)
  query ||= {}
  query = query.clone
  query = filter_valid_info(query)
  
  conditions = []
  query.each do |_, ands|
    conditions << ands.map { |_, v| condition_to_pair v }
  end
  
  cond = []
  conditions.each do |condition|
    c = {}
    condition.each do |pair|
      pair.each do |k, v|
        c[k] ||= []
        c[k].concat v
      end
    end
    c.keys.each { |k| c[k] = Hash[ c[k].each_slice(2).to_a ] }
    cond << c
  end 
  if table
    cond.map! { |c| c[table.to_s] }
    cond.delete nil
  end
  cond
end

Private Instance Methods

condition_to_pair(cond) click to toggle source
# File lib/dynamic_query/combined_query.rb, line 94
def condition_to_pair(cond)
  table, column = cond[:column].split(/\./)
  { table => ["#{column}.#{convert_op cond[:operator]}", convert_val(cond[:operator], cond[:value1], cond[:value2])] }
end
convert_op(op) click to toggle source
# File lib/dynamic_query/combined_query.rb, line 112
def convert_op(op)
  case op
  when '='
    'eq'
  when '>'
    'gt'
  when '>='
    'ge'
  when '<'
    'lt'
  when '<='
    'le'
  when '!='
    'not_eq'
  when 'LIKE'
    'like'
  when 'NOT LIKE'
    'not_like'
  when 'IN'
    'in'
  when 'NOT IN'
    'not_in'
  when 'BETWEEN'
    'btw'
  when 'NOT BETWEEN'
    'not_btw'
  when 'IS NULL'
    'is'
  when 'IS NOT NULL'
    'is_not'
  else
    'eq'
  end
end
convert_val(op, val1, val2) click to toggle source
# File lib/dynamic_query/combined_query.rb, line 99
def convert_val(op, val1, val2)
  case op
  when 'IN', 'NOT IN'
    val1.split(/,/).delete_if { |word| word.blank? }.map { |word| word.strip }
  when 'BETWEEN', 'NOT BETWEEN'
    [val1, val2]
  when 'IS NULL', 'IS NOT NULL'
    nil
  else
    val1
  end
end
delete_unlinked_records(tgt, fks1, ref, fks2) click to toggle source
# File lib/dynamic_query/combined_query.rb, line 65
def delete_unlinked_records(tgt, fks1, ref, fks2)
  ref_val = ref.map { |r| fks2.map { |fk| r.send(fk) } }
  tgt.keep_if { |t| ref_val.include?(fks1.map { |fk| t.send(fk) }) }
end
filter_conditioned_records(models, foreign_keys, conds) click to toggle source
# File lib/dynamic_query/combined_query.rb, line 70
def filter_conditioned_records(models, foreign_keys, conds)
  foreign_keys = foreign_keys.clone
  
  selected_records = []
  determinate_values = nil
  models.each do |m|
    selected_records << m.where(conds[m.table_name]).all
    if determinate_values
      trim_records(selected_records.last, determinate_values, foreign_keys.shift)
    end
    if foreign_keys.empty?
      determinate_values = nil
    else
      fks = foreign_keys.shift
      determinate_values = selected_records.last.map { |r| fks.map { |fk| r.send(fk) } }
    end
  end
  selected_records
end
remove_unlinked_records(selected_records, foreign_keys) click to toggle source
# File lib/dynamic_query/combined_query.rb, line 53
def remove_unlinked_records(selected_records, foreign_keys)
  foreign_keys = foreign_keys.clone
  
  selected_records.each_with_index do |records, idx|
    unless foreign_keys.empty?
      delete_unlinked_records(records, foreign_keys.shift, selected_records[idx + 1], foreign_keys.shift)
    end
  end
  
  selected_records
end
trim_records(records, det_val, fks) click to toggle source
# File lib/dynamic_query/combined_query.rb, line 90
def trim_records(records, det_val, fks)
  records.keep_if { |r| det_val.include?(fks.map { |fk| r[fk] }) }
end