diff options
author | Sean Griffin <sean@thoughtbot.com> | 2014-12-26 16:51:01 -0700 |
---|---|---|
committer | Sean Griffin <sean@thoughtbot.com> | 2014-12-26 16:54:12 -0700 |
commit | a11a8ff7840cd5c5ebb881aac61be9771b07b3ba (patch) | |
tree | 1c9fe6fbeb46649ebcb079649163f510d71c52ca /activerecord | |
parent | 5f521cbff3c8a46cfc8e16b234294a20c285d00d (diff) | |
download | rails-a11a8ff7840cd5c5ebb881aac61be9771b07b3ba.tar.gz rails-a11a8ff7840cd5c5ebb881aac61be9771b07b3ba.tar.bz2 rails-a11a8ff7840cd5c5ebb881aac61be9771b07b3ba.zip |
Fall back to type casting from the connection adapter
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
Diffstat (limited to 'activerecord')
-rw-r--r-- | activerecord/lib/active_record/table_metadata.rb | 72 |
1 files changed, 70 insertions, 2 deletions
diff --git a/activerecord/lib/active_record/table_metadata.rb b/activerecord/lib/active_record/table_metadata.rb index 811e6964a9..e60bf55021 100644 --- a/activerecord/lib/active_record/table_metadata.rb +++ b/activerecord/lib/active_record/table_metadata.rb @@ -33,12 +33,19 @@ module ActiveRecord 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? @@ -49,4 +56,65 @@ module ActiveRecord 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 |