Method: NoBrainer::Criteria::Where::IndexFinder#find_strategy_compound_partial

Defined in:
lib/no_brainer/criteria/where.rb

#find_strategy_compound_partialObject



450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
# File 'lib/no_brainer/criteria/where.rb', line 450

def find_strategy_compound_partial
  clauses = get_candidate_clauses(:eq, :between).map { |c| [c.key_path, c] }.to_h
  return nil unless clauses.present?

  get_usable_indexes(:kind => :compound, :geo => false, :multi => false).each do |index|
    indexed_clauses = index.what.map { |field| clauses[[field]] }
    partial_clauses = indexed_clauses.compact
    pad = indexed_clauses.length - partial_clauses.length
    if partial_clauses.any? && partial_clauses.all? { |c| c.try(:compatible_with_index?, index) }
      # can only use partial compound index if:
      #   * index contains all clause fields
      next unless (clauses.values & partial_clauses) == clauses.values
      #   * all clause fields come first in the indexed clauses (unused indexed fields are at the end)
      next unless indexed_clauses.last(pad).all?(&:nil?)
      #   * all clause fields are :eq, except the last (which may be :between)
      next unless partial_clauses[0..-2].all? { |c|  c.op == :eq }

      # use range query to cover unused index fields
      left_bound  = partial_clauses.map(&:value)
      right_bound = partial_clauses.map(&:value)
      if (clause = partial_clauses[-1]).op == :between
        left_bound[-1] = clause.value.min
        right_bound[-1] = clause.value.max
      end
      if pad > 0
        left_bound.append *Array.new(pad, RethinkDB::RQL.new.minval)
        right_bound.append *Array.new(pad, RethinkDB::RQL.new.maxval)
      end
      return IndexStrategy.new(self, ast, partial_clauses, index, :between, [left_bound, right_bound], :left_bound => :closed, :right_bound => :closed)
    end
  end
  nil
end