Skip to content

Commit

Permalink
Fall back to type casting from the connection adapter
Browse files Browse the repository at this point in the history
There are several valid cases where right now we can't determine the
association's class in a call to `where`. In these cases, we can fall
back to casting by looking up the column from the connection adapter
(which is what happens right now when we fall through to Arel)

This is ugly, and since we're trying to separate the concept of a type
from a column, I'd like to remove it in the future. The problem
basically comes down to this:

    Liquid.joins(molecules: :electrons)
      .where("molecules.name" => "something", "electrons.name" => "something")

The hash in this case will turn into:

    {
      molecules: { name: "something" },
      electrons: { name: "something" },
    }

What we actually need is:

    {
      molecules: {
        name: "something",
        electrons: { name: "something" },
      }
    }

/cc @mrgilman
  • Loading branch information
sgrif committed Dec 26, 2014
1 parent 5f521cb commit a11a8ff
Showing 1 changed file with 70 additions and 2 deletions.
72 changes: 70 additions & 2 deletions activerecord/lib/active_record/table_metadata.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,19 @@ def associated_with?(association_name)
end

def associated_table(table_name)
return self if table_name == arel_table.name

arel_table = Arel::Table.new(table_name)
association = klass._reflect_on_association(table_name)
if association && !association.polymorphic?
klass = association.klass
association_klass = association.klass
end

if association
TableMetadata.new(association_klass, arel_table, association)
else
ConnectionAdapterTable.new(klass.connection, arel_table)
end
TableMetadata.new(klass, arel_table, association)
end

def polymorphic_association?
Expand All @@ -49,4 +56,65 @@ def polymorphic_association?

attr_reader :klass, :arel_table, :association
end

# FIXME: We want to get rid of this class. The connection adapter does not
# have sufficient knowledge about types, as they could be provided by or
# overriden by the ActiveRecord::Base subclass. The case where you reach this
# class is if you do a query like:
#
# Liquid.joins(molecules: :electrons)
# .where("molecules.name" => "something", "electrons.name" => "something")
#
# Since we don't know that we can get to electrons through molecules
class ConnectionAdapterTable # :nodoc:
def initialize(connection, arel_table)
@connection = connection
@arel_table = arel_table
end

def type_cast_for_database(attribute_name, value)
return value if value.is_a?(Arel::Nodes::BindParam)
type = type_for(attribute_name)
Arel::Nodes::Quoted.new(type.type_cast_for_database(value))
end

def resolve_column_aliases(hash)
hash
end

def arel_attribute(column_name)
arel_table[column_name]
end

def associated_with?(*)
false
end

def associated_table(table_name)
arel_table = Arel::Table.new(table_name)
ConnectionAdapterTable.new(klass.connection, arel_table)
end

def polymorphic_association?
false
end

protected

attr_reader :connection, :arel_table

private

def type_for(attribute_name)
if connection.schema_cache.table_exists?(arel_table.name)
column_for(attribute_name).cast_type
else
Type::Value.new
end
end

def column_for(attribute_name)
connection.schema_cache.columns_hash(arel_table.name)[attribute_name.to_s]
end
end
end

0 comments on commit a11a8ff

Please sign in to comment.