class ArelHash::Optimizer
Public Class Methods
new(predicates = [])
click to toggle source
# File lib/arel_hash/optimizer.rb, line 3 def initialize(predicates = []) @predicates = predicates end
Public Instance Methods
optimize(arel_hash)
click to toggle source
# File lib/arel_hash/optimizer.rb, line 7 def optimize(arel_hash) operator, value = ArelHash.singleton_tuple!(arel_hash) (%i(and or).include?(operator)) ? optimize_collection_node(operator, value) : arel_hash end
Private Instance Methods
optimize_and_nodes(nodes)
click to toggle source
# File lib/arel_hash/optimizer.rb, line 35 def optimize_and_nodes(nodes) nodes.delete_if { |n| n == ArelHash::NO_FILTER_HASH && nodes.length > 1 } nodes = optimize_duplicate_eqs(nodes) nodes.include?(ArelHash::ZERO_RESULTS_HASH) ? [ArelHash::ZERO_RESULTS_HASH] : nodes end
optimize_collection_node(operator, children)
click to toggle source
# File lib/arel_hash/optimizer.rb, line 14 def optimize_collection_node(operator, children) children = children.map { |h| optimize(h) }.uniq arel_hash = shallow_optimize_collection_node(operator, children) children = ArelHash.singleton_tuple!(arel_hash).last (children.length == 1) ? children.first : arel_hash end
optimize_duplicate_eqs(nodes)
click to toggle source
# File lib/arel_hash/optimizer.rb, line 41 def optimize_duplicate_eqs(nodes) eqs, other = partition_by_keys(nodes, 'eq') values_per_attribute(eqs).map do |attr_name, values| (values.length > 1) ? ArelHash::ZERO_RESULTS_HASH : { eq: Hash[attr_name, values.first] } end.concat(other) end
optimize_eqs_and_ins(nodes)
click to toggle source
@return [Array<Hash>] an array of predicate arelHashes
# File lib/arel_hash/optimizer.rb, line 49 def optimize_eqs_and_ins(nodes) ins_or_eqs, other = partition_by_keys(nodes, *%w(eq in)) values_per_attribute(ins_or_eqs).map do |attr_name, value| (value.length > 1) ? { in: Hash[attr_name, value] } : { eq: Hash[attr_name, value.first] } end.concat(other) end
optimize_or_nodes(nodes)
click to toggle source
# File lib/arel_hash/optimizer.rb, line 29 def optimize_or_nodes(nodes) nodes.delete_if { |n| n == ArelHash::ZERO_RESULTS_HASH && nodes.length > 1 } nodes = optimize_eqs_and_ins(nodes) if @predicates.include?('in') && @predicates.include?('eq') nodes.include?(ArelHash::NO_FILTER_HASH) ? [ArelHash::NO_FILTER_HASH] : nodes end
partition_by_keys(hash_collection, *keys)
click to toggle source
# File lib/arel_hash/optimizer.rb, line 66 def partition_by_keys(hash_collection, *keys) hash_collection.partition do |h| keys.include?(ArelHash.singleton_tuple!(h).first.to_s) end end
shallow_optimize_collection_node(operator, children)
click to toggle source
# File lib/arel_hash/optimizer.rb, line 21 def shallow_optimize_collection_node(operator, children) if operator == :or Hash[operator, optimize_or_nodes(children)] elsif operator == :and Hash[operator, optimize_and_nodes(children)] end end
values_per_attribute(nodes)
click to toggle source
@param [Array<Hash<Symbol, Hash<Symbol, Object>>>] nodes @return [Hash<Symbol, Array<String>>] attribute_name/value pair, with value being an Array
# File lib/arel_hash/optimizer.rb, line 58 def values_per_attribute(nodes) nodes.each_with_object({}) do |arel_hash, m| name_value_pair = ArelHash.singleton_tuple!(arel_hash).last attr_name, value = ArelHash.singleton_tuple!(name_value_pair) m[attr_name] = (m[attr_name]||[]).concat(Array(value)).uniq end end