Skip to content
This repository
Browse code

Ensure :include checks joins when determining if it can preload [#528

…state:resolved]
  • Loading branch information...
commit c9ab7098be7bdd748c0f4a49c8ef015b4aad3108 1 parent 9cf6b1b
Frederick Cheung authored December 18, 2008 lifo committed December 18, 2008
43  activerecord/lib/active_record/associations.rb
@@ -1731,6 +1731,11 @@ def construct_finder_sql_for_association_limiting(options, join_dependency)
1731 1731
           return sanitize_sql(sql)
1732 1732
         end
1733 1733
 
  1734
+        def tables_in_string(string)
  1735
+          return [] if string.blank?
  1736
+          string.scan(/([\.a-zA-Z_]+).?\./).flatten
  1737
+        end
  1738
+
1734 1739
         def conditions_tables(options)
1735 1740
           # look in both sets of conditions
1736 1741
           conditions = [scope(:find, :conditions), options[:conditions]].inject([]) do |all, cond|
@@ -1741,37 +1746,55 @@ def conditions_tables(options)
1741 1746
               else            all << cond
1742 1747
             end
1743 1748
           end
1744  
-          conditions.join(' ').scan(/([\.a-zA-Z_]+).?\./).flatten
  1749
+          tables_in_string(conditions.join(' '))
1745 1750
         end
1746 1751
 
1747 1752
         def order_tables(options)
1748 1753
           order = [options[:order], scope(:find, :order) ].join(", ")
1749 1754
           return [] unless order && order.is_a?(String)
1750  
-          order.scan(/([\.a-zA-Z_]+).?\./).flatten
  1755
+          tables_in_string(order)
1751 1756
         end
1752 1757
 
1753 1758
         def selects_tables(options)
1754 1759
           select = options[:select]
1755 1760
           return [] unless select && select.is_a?(String)
1756  
-          select.scan(/"?([\.a-zA-Z_]+)"?.?\./).flatten
  1761
+          tables_in_string(select)
  1762
+        end
  1763
+
  1764
+        def joined_tables(options)
  1765
+          scope = scope(:find)
  1766
+          joins = options[:joins]
  1767
+          merged_joins = scope && scope[:joins] && joins ? merge_joins(scope[:joins], joins) : (joins || scope && scope[:joins])
  1768
+          [table_name] + case merged_joins
  1769
+          when Symbol, Hash, Array
  1770
+            if array_of_strings?(merged_joins)
  1771
+              tables_in_string(merged_joins.join(' '))
  1772
+            else
  1773
+              join_dependency = ActiveRecord::Associations::ClassMethods::InnerJoinDependency.new(self, merged_joins, nil)
  1774
+              [table_name] + join_dependency.join_associations.collect {|join_association| [join_association.aliased_join_table_name, join_association.aliased_table_name]}.flatten.compact
  1775
+            end
  1776
+          else
  1777
+            tables_in_string(merged_joins)
  1778
+          end
1757 1779
         end
1758 1780
 
1759 1781
         # Checks if the conditions reference a table other than the current model table
1760  
-        def include_eager_conditions?(options, tables = nil)
1761  
-          ((tables || conditions_tables(options)) - [table_name]).any?
  1782
+        def include_eager_conditions?(options, tables = nil, joined_tables = nil)
  1783
+          ((tables || conditions_tables(options)) - (joined_tables || joined_tables(options))).any?
1762 1784
         end
1763 1785
 
1764 1786
         # Checks if the query order references a table other than the current model's table.
1765  
-        def include_eager_order?(options, tables = nil)
1766  
-          ((tables || order_tables(options)) - [table_name]).any?
  1787
+        def include_eager_order?(options, tables = nil, joined_tables = nil)
  1788
+          ((tables || order_tables(options)) - (joined_tables || joined_tables(options))).any?
1767 1789
         end
1768 1790
 
1769  
-        def include_eager_select?(options)
1770  
-          (selects_tables(options) - [table_name]).any?
  1791
+        def include_eager_select?(options, joined_tables = nil)
  1792
+          (selects_tables(options) - (joined_tables || joined_tables(options))).any?
1771 1793
         end
1772 1794
 
1773 1795
         def references_eager_loaded_tables?(options)
1774  
-          include_eager_order?(options) || include_eager_conditions?(options) || include_eager_select?(options)
  1796
+          joined_tables = joined_tables(options)
  1797
+          include_eager_order?(options, nil, joined_tables) || include_eager_conditions?(options, nil, joined_tables) || include_eager_select?(options, joined_tables)
1775 1798
         end
1776 1799
 
1777 1800
         def using_limitable_reflections?(reflections)
65  activerecord/test/cases/associations/eager_test.rb
... ...
@@ -1,6 +1,7 @@
1 1
 require "cases/helper"
2 2
 require 'models/post'
3 3
 require 'models/tagging'
  4
+require 'models/tag'
4 5
 require 'models/comment'
5 6
 require 'models/author'
6 7
 require 'models/category'
@@ -706,4 +707,68 @@ def test_order_on_join_table_with_include_and_limit
706 707
     assert_equal 5, Developer.find(:all, :include => 'projects', :order => 'developers_projects.joined_on DESC', :limit => 5).size
707 708
   end
708 709
 
  710
+  def test_eager_loading_with_order_on_joined_table_preloads
  711
+    posts = assert_queries(2) do
  712
+      Post.find(:all, :joins => :comments, :include => :author, :order => 'comments.id DESC')
  713
+    end
  714
+    assert_equal posts(:eager_other), posts[0]
  715
+    assert_equal authors(:mary), assert_no_queries { posts[0].author}
  716
+  end
  717
+
  718
+  def test_eager_loading_with_conditions_on_joined_table_preloads
  719
+    posts = assert_queries(2) do
  720
+      Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => [:comments], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
  721
+    end
  722
+    assert_equal [posts(:welcome)], posts
  723
+    assert_equal authors(:david), assert_no_queries { posts[0].author}
  724
+
  725
+    posts = assert_queries(2) do
  726
+      Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => [:comments], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
  727
+    end
  728
+    assert_equal [posts(:welcome)], posts
  729
+    assert_equal authors(:david), assert_no_queries { posts[0].author}
  730
+
  731
+    posts = assert_queries(2) do
  732
+      Post.find(:all, :include => :author, :joins => {:taggings => :tag}, :conditions => "tags.name = 'General'")
  733
+    end
  734
+    assert_equal posts(:welcome, :thinking), posts
  735
+
  736
+    posts = assert_queries(2) do
  737
+      Post.find(:all, :include => :author, :joins => {:taggings => {:tag => :taggings}}, :conditions => "taggings_tags.super_tag_id=2")
  738
+    end
  739
+    assert_equal posts(:welcome, :thinking), posts
  740
+
  741
+  end
  742
+
  743
+  def test_eager_loading_with_conditions_on_string_joined_table_preloads
  744
+    posts = assert_queries(2) do
  745
+      Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => "INNER JOIN comments on comments.post_id = posts.id", :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
  746
+    end
  747
+    assert_equal [posts(:welcome)], posts
  748
+    assert_equal authors(:david), assert_no_queries { posts[0].author}
  749
+
  750
+    posts = assert_queries(2) do
  751
+      Post.find(:all, :select => 'distinct posts.*', :include => :author, :joins => ["INNER JOIN comments on comments.post_id = posts.id"], :conditions => "comments.body like 'Thank you%'", :order => 'posts.id')
  752
+    end
  753
+    assert_equal [posts(:welcome)], posts
  754
+    assert_equal authors(:david), assert_no_queries { posts[0].author}
  755
+
  756
+  end
  757
+
  758
+  def test_eager_loading_with_select_on_joined_table_preloads
  759
+    posts = assert_queries(2) do
  760
+      Post.find(:all, :select => 'posts.*, authors.name as author_name', :include => :comments, :joins => :author, :order => 'posts.id')
  761
+    end
  762
+    assert_equal 'David', posts[0].author_name
  763
+    assert_equal posts(:welcome).comments, assert_no_queries { posts[0].comments}
  764
+  end
  765
+
  766
+  def test_eager_loading_with_conditions_on_join_model_preloads
  767
+    authors = assert_queries(2) do
  768
+      Author.find(:all, :include => :author_address, :joins => :comments, :conditions => "posts.title like 'Welcome%'")
  769
+    end
  770
+    assert_equal authors(:david), authors[0]
  771
+    assert_equal author_addresses(:david_address), authors[0].author_address
  772
+  end
  773
+
709 774
 end

0 notes on commit c9ab709

Please sign in to comment.
Something went wrong with that request. Please try again.