module ActiveRecordExtended::QueryMethods::AnyOf

Public Instance Methods

any_of(*queries) click to toggle source
# File lib/active_record_extended/query_methods/any_of.rb, line 6
def any_of(*queries)
  queries = hash_map_queries(queries)
  build_query(queries) do |arel_query, binds|
    if binds.any?
      @scope.where(unprepared_query(arel_query.to_sql), *binds)
    else
      @scope.where(arel_query)
    end
  end
end
none_of(*queries) click to toggle source
# File lib/active_record_extended/query_methods/any_of.rb, line 17
def none_of(*queries)
  queries = hash_map_queries(queries)
  build_query(queries) do |arel_query, binds|
    if binds.any?
      @scope.where.not(unprepared_query(arel_query.to_sql), *binds)
    else
      @scope.where.not(arel_query)
    end
  end
end

Private Instance Methods

bind_attributes(query) click to toggle source

Rails 5.1 fix In Rails 5.2 the arel table maintains attribute binds

# File lib/active_record_extended/query_methods/any_of.rb, line 62
def bind_attributes(query)
  return [] unless query.respond_to?(:bound_attributes)

  query.bound_attributes.map(&:value)
end
build_query(queries) { |query_map, query_map| ... } click to toggle source
# File lib/active_record_extended/query_methods/any_of.rb, line 38
def build_query(queries)
  query_map = construct_query_mappings(queries)
  query     = yield(query_map[:arel_query], query_map[:binds])
  query
    .joins(query_map[:joins].to_a)
    .includes(query_map[:includes].to_a)
    .references(query_map[:references].to_a)
end
construct_query_mappings(queries) click to toggle source
# File lib/active_record_extended/query_methods/any_of.rb, line 47
def construct_query_mappings(queries) # rubocop:disable Metrics/AbcSize
  { joins: Set.new, references: Set.new, includes: Set.new, arel_query: nil, binds: [] }.tap do |query_map|
    query_map[:arel_query] = queries.map do |raw_query|
      query = generate_where_clause(raw_query)
      query_map[:joins]      << translate_reference(query.joins_values)      if query.joins_values.any?
      query_map[:includes]   << translate_reference(query.includes_values)   if query.includes_values.any?
      query_map[:references] << translate_reference(query.references_values) if query.references_values.any?
      query_map[:binds] += bind_attributes(query)
      query.arel.constraints.reduce(:and)
    end.reduce(:or)
  end
end
generate_where_clause(query) click to toggle source
# File lib/active_record_extended/query_methods/any_of.rb, line 79
def generate_where_clause(query)
  case query
  when String, Hash
    @scope.unscoped.where(query)
  when Array
    @scope.unscoped.where(*query)
  else
    query
  end
end
hash_map_queries(queries) click to toggle source
# File lib/active_record_extended/query_methods/any_of.rb, line 30
def hash_map_queries(queries)
  if queries.size == 1 && queries.first.is_a?(Hash)
    queries.first.each_pair.map { |attr, predicate| Hash[attr, predicate] }
  else
    queries
  end
end
translate_reference(reference) click to toggle source
# File lib/active_record_extended/query_methods/any_of.rb, line 75
def translate_reference(reference)
  reference.map { |ref| ref.try(:to_sql) || ref }.compact
end
unprepared_query(query) click to toggle source

Rails 5.1 fix

# File lib/active_record_extended/query_methods/any_of.rb, line 69
def unprepared_query(query)
  query.gsub(/((?<!\\)'.*?(?<!\\)'|(?<!\\)".*?(?<!\\)")|(=\ \$\d+)/) do |match|
    Regexp.last_match(2)&.gsub(/=\ \$\d+/, "= ?") || match
  end
end