aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/associations/alias_tracker.rb
diff options
context:
space:
mode:
authorJon Leighton <j@jonathanleighton.com>2010-10-12 19:49:32 +0100
committerJon Leighton <j@jonathanleighton.com>2010-10-12 19:49:32 +0100
commite8874318b7a025ffd30df1a53c403eb9d8912c9f (patch)
tree337ff7ffb85aea9ad805b0cff6128e6c2f87827c /activerecord/lib/active_record/associations/alias_tracker.rb
parentc37a5e7acde436b359043a67b7daace8be6f08c6 (diff)
downloadrails-e8874318b7a025ffd30df1a53c403eb9d8912c9f.tar.gz
rails-e8874318b7a025ffd30df1a53c403eb9d8912c9f.tar.bz2
rails-e8874318b7a025ffd30df1a53c403eb9d8912c9f.zip
Extract aliasing code from JoinDependency and JoinAssociation into a separate AliasTracker class. This can then be used by ThroughAssociationScope as well.
Diffstat (limited to 'activerecord/lib/active_record/associations/alias_tracker.rb')
-rw-r--r--activerecord/lib/active_record/associations/alias_tracker.rb68
1 files changed, 68 insertions, 0 deletions
diff --git a/activerecord/lib/active_record/associations/alias_tracker.rb b/activerecord/lib/active_record/associations/alias_tracker.rb
new file mode 100644
index 0000000000..f48efabec2
--- /dev/null
+++ b/activerecord/lib/active_record/associations/alias_tracker.rb
@@ -0,0 +1,68 @@
+require 'active_support/core_ext/string/conversions'
+
+module ActiveRecord
+ module Associations
+ # Keeps track of table aliases for ActiveRecord::Associations::ClassMethods::JoinDependency
+ class AliasTracker # :nodoc:
+ # other_sql is some other sql which might conflict with the aliases we assign here. Therefore
+ # we store other_sql so that we can scan it before assigning a specific name.
+ def initialize(other_sql)
+ @aliases = Hash.new
+ @other_sql = other_sql.to_s.downcase
+ end
+
+ def aliased_name_for(table_name, aliased_name = nil)
+ aliased_name ||= table_name
+
+ initialize_count_for(table_name) if @aliases[table_name].nil?
+
+ if @aliases[table_name].zero?
+ # If it's zero, we can have our table_name
+ @aliases[table_name] = 1
+ table_name
+ else
+ # Otherwise, we need to use an alias
+ aliased_name = connection.table_alias_for(aliased_name)
+
+ initialize_count_for(aliased_name) if @aliases[aliased_name].nil?
+
+ # Update the count
+ @aliases[aliased_name] += 1
+
+ if @aliases[aliased_name] > 1
+ "#{truncate(aliased_name)}_#{@aliases[aliased_name]}"
+ else
+ aliased_name
+ end
+ end
+ end
+
+ private
+
+ def initialize_count_for(name)
+ @aliases[name] = 0
+
+ unless @other_sql.blank?
+ # quoted_name should be downcased as some database adapters (Oracle) return quoted name in uppercase
+ quoted_name = connection.quote_table_name(name.downcase).downcase
+
+ # Table names
+ @aliases[name] += @other_sql.scan(/join(?:\s+\w+)?\s+#{quoted_name}\son/).size
+
+ # Table aliases
+ @aliases[name] += @other_sql.scan(/join(?:\s+\w+)?\s+\S+\s+#{quoted_name}\son/).size
+ end
+
+ @aliases[name]
+ end
+
+ def truncate(name)
+ name[0..connection.table_alias_length-3]
+ end
+
+ def connection
+ ActiveRecord::Base.connection
+ end
+ end
+ end
+end