diff options
author | Pratik Naik <pratiknaik@gmail.com> | 2010-01-01 22:54:23 +0530 |
---|---|---|
committer | Pratik Naik <pratiknaik@gmail.com> | 2010-01-01 22:54:26 +0530 |
commit | 752813016ed227ecfbe0bf69c92de2e2c3e7a988 (patch) | |
tree | 8253ea85ddd044bfdd3107257308bfd486aa89f8 | |
parent | c836c3ed10110d0446c4fce87d36c3f6c39b3cda (diff) | |
download | rails-752813016ed227ecfbe0bf69c92de2e2c3e7a988.tar.gz rails-752813016ed227ecfbe0bf69c92de2e2c3e7a988.tar.bz2 rails-752813016ed227ecfbe0bf69c92de2e2c3e7a988.zip |
Add support for table aliasing
Example :
users = Table(:users, :as => :accounts)
users.to_sql
=> SELECT `accounts`.`id`, `accounts`.`name` FROM `users` AS `accounts`
-rw-r--r-- | lib/arel/algebra/relations/utilities/compound.rb | 2 | ||||
-rw-r--r-- | lib/arel/engines/sql/christener.rb | 3 | ||||
-rw-r--r-- | lib/arel/engines/sql/relations/table.rb | 18 | ||||
-rw-r--r-- | spec/arel/engines/sql/unit/relations/join_spec.rb | 56 | ||||
-rw-r--r-- | spec/arel/engines/sql/unit/relations/table_spec.rb | 20 |
5 files changed, 92 insertions, 7 deletions
diff --git a/lib/arel/algebra/relations/utilities/compound.rb b/lib/arel/algebra/relations/utilities/compound.rb index 1acf92fef8..9eca02c8c4 100644 --- a/lib/arel/algebra/relations/utilities/compound.rb +++ b/lib/arel/algebra/relations/utilities/compound.rb @@ -2,7 +2,7 @@ module Arel class Compound < Relation attr_reader :relation delegate :joins, :join?, :inserts, :taken, :skipped, :name, :externalizable?, - :column_for, :engine, :sources, :locked, + :column_for, :engine, :sources, :locked, :table_alias, :to => :relation [:attributes, :wheres, :groupings, :orders, :havings].each do |operation_name| diff --git a/lib/arel/engines/sql/christener.rb b/lib/arel/engines/sql/christener.rb index c1c9325208..a2a2da799a 100644 --- a/lib/arel/engines/sql/christener.rb +++ b/lib/arel/engines/sql/christener.rb @@ -4,7 +4,8 @@ module Arel def name_for(relation) @used_names ||= Hash.new(0) (@relation_names ||= Hash.new do |hash, relation| - @used_names[name = relation.name] += 1 + name = relation.table_alias ? relation.table_alias : relation.name + @used_names[name] += 1 hash[relation] = name + (@used_names[name] > 1 ? "_#{@used_names[name]}" : '') end)[relation.table] end diff --git a/lib/arel/engines/sql/relations/table.rb b/lib/arel/engines/sql/relations/table.rb index dd22f44226..6ad294dc6c 100644 --- a/lib/arel/engines/sql/relations/table.rb +++ b/lib/arel/engines/sql/relations/table.rb @@ -3,10 +3,22 @@ module Arel include Recursion::BaseCase cattr_accessor :engine - attr_reader :name, :engine + attr_reader :name, :engine, :table_alias, :options - def initialize(name, engine = Table.engine) - @name, @engine = name.to_s, engine + def initialize(name, options = {}) + @name = name.to_s + + if options.is_a?(Hash) + @options = options + @engine = options[:engine] || Table.engine + @table_alias = options[:as].to_s if options[:as].present? + else + @engine = options # Table.new('foo', engine) + end + end + + def as(table_alias) + Table.new(name, options.merge(:as => table_alias)) end def attributes diff --git a/spec/arel/engines/sql/unit/relations/join_spec.rb b/spec/arel/engines/sql/unit/relations/join_spec.rb index 2820763a66..e2fc4bab3d 100644 --- a/spec/arel/engines/sql/unit/relations/join_spec.rb +++ b/spec/arel/engines/sql/unit/relations/join_spec.rb @@ -5,13 +5,20 @@ module Arel before do @relation1 = Table.new(:users) @relation2 = Table.new(:photos) - @predicate = @relation1[:id].eq(@relation2[:user_id]) + @predicate1 = @relation1[:id].eq(@relation2[:user_id]) + + @relation3 = Table.new(:users, :as => :super_users) + @relation4 = Table.new(:photos, :as => :super_photos) + + @predicate2 = @relation3[:id].eq(@relation2[:user_id]) + @predicate3 = @relation3[:id].eq(@relation4[:user_id]) end describe '#to_sql' do + describe 'when joining with another relation' do it 'manufactures sql joining the two tables on the predicate' do - sql = InnerJoin.new(@relation1, @relation2, @predicate).to_sql + sql = InnerJoin.new(@relation1, @relation2, @predicate1).to_sql adapter_is :mysql do sql.should be_like(%Q{ @@ -29,6 +36,51 @@ module Arel }) end end + + describe 'when joining with another relation with an aliased table' do + it 'manufactures sql joining the two tables on the predicate respecting table aliasing' do + sql = InnerJoin.new(@relation3, @relation2, @predicate2).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `super_users`.`id`, `super_users`.`name`, `photos`.`id`, `photos`.`user_id`, `photos`.`camera_id` + FROM `users` AS `super_users` + INNER JOIN `photos` ON `super_users`.`id` = `photos`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "super_users"."id", "super_users"."name", "photos"."id", "photos"."user_id", "photos"."camera_id" + FROM "users" AS "super_users" + INNER JOIN "photos" ON "super_users"."id" = "photos"."user_id" + }) + end + end + end + + describe 'when joining with two relations with aliased tables' do + it 'manufactures sql joining the two tables on the predicate respecting table aliasing' do + sql = InnerJoin.new(@relation3, @relation4, @predicate3).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `super_users`.`id`, `super_users`.`name`, `super_photos`.`id`, `super_photos`.`user_id`, `super_photos`.`camera_id` + FROM `users` AS `super_users` + INNER JOIN `photos` AS `super_photos` ON `super_users`.`id` = `super_photos`.`user_id` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "super_users"."id", "super_users"."name", "super_photos"."id", "super_photos"."user_id", "super_photos"."camera_id" + FROM "users" AS "super_users" + INNER JOIN "photos" AS "super_photos" ON "super_users"."id" = "super_photos"."user_id" + }) + end + end + end + end describe 'when joining with a string' do diff --git a/spec/arel/engines/sql/unit/relations/table_spec.rb b/spec/arel/engines/sql/unit/relations/table_spec.rb index 92e4549028..977eb343e3 100644 --- a/spec/arel/engines/sql/unit/relations/table_spec.rb +++ b/spec/arel/engines/sql/unit/relations/table_spec.rb @@ -26,6 +26,26 @@ module Arel end end + describe '#as' do + it "manufactures a simple select query using aliases" do + sql = @relation.as(:super_users).to_sql + + adapter_is :mysql do + sql.should be_like(%Q{ + SELECT `super_users`.`id`, `super_users`.`name` + FROM `users` AS `super_users` + }) + end + + adapter_is_not :mysql do + sql.should be_like(%Q{ + SELECT "super_users"."id", "super_users"."name" + FROM "users" AS "super_users" + }) + end + end + end + describe '#column_for' do it "returns the column corresponding to the attribute" do @relation.column_for(@relation[:id]).should == @relation.columns.detect { |c| c.name == 'id' } |