public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Add :from option to calculations.  [#397 state:resolved]
yukster (author)
Wed Jun 11 16:26:35 -0700 2008
jeremy (committer)
Wed Jun 11 18:07:57 -0700 2008
commit  ddab9d7fdf49eb064f3f669bbf6ebb41e75e9fb5
tree    9fd10026edaf41bb723f8fa06c3ee0c880d2c212
parent  e170d34a634c93efef471f9c0c1dac7377f1fc40
...
1
2
 
 
3
4
5
...
1
2
3
4
5
6
7
0
@@ -1,5 +1,7 @@
0
 *Edge*
0
 
0
+* Add :from option to calculations.  #397 [Ben Munat]
0
+
0
 * Add :validate option to associations to enable/disable the automatic validation of associated models. Resolves #301. [Jan De Poorter]
0
 
0
 * PostgreSQL: use 'INSERT ... RETURNING id' for 8.2 and later.  [Jeremy Kemper]
...
1
2
3
 
4
5
6
...
27
28
29
 
 
30
31
32
...
178
179
180
181
182
 
 
 
 
 
 
183
184
185
...
1
2
 
3
4
5
6
...
27
28
29
30
31
32
33
34
...
180
181
182
 
 
183
184
185
186
187
188
189
190
191
0
@@ -1,6 +1,6 @@
0
 module ActiveRecord
0
   module Calculations #:nodoc:
0
-    CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include]
0
+    CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include, :from]
0
     def self.included(base)
0
       base.extend(ClassMethods)
0
     end
0
@@ -27,6 +27,8 @@ module ActiveRecord
0
       # * <tt>:select</tt>: By default, this is * as in SELECT * FROM, but can be changed if you, for example, want to do a join but not
0
       #   include the joined columns.
0
       # * <tt>:distinct</tt>: Set this to true to make this a distinct calculation, such as SELECT COUNT(DISTINCT posts.id) ...
0
+      # * <tt>:from</tt> - By default, this is the table name of the class, but can be changed to an alternate table name (or even the name
0
+      #   of a database view).
0
       #
0
       # Examples for counting all:
0
       #   Person.count         # returns the total count of all people
0
@@ -178,8 +180,12 @@ module ActiveRecord
0
           sql = "SELECT COUNT(*) AS #{aggregate_alias}" if use_workaround
0
 
0
           sql << ", #{options[:group_field]} AS #{options[:group_alias]}" if options[:group]
0
-          sql << " FROM (SELECT #{distinct}#{column_name}" if use_workaround
0
-          sql << " FROM #{connection.quote_table_name(table_name)} "
0
+          if options[:from]
0
+            sql << " FROM #{options[:from]} "
0
+          else
0
+            sql << " FROM (SELECT #{distinct}#{column_name}" if use_workaround
0
+            sql << " FROM #{connection.quote_table_name(table_name)} "
0
+          end
0
           if merged_includes.any?
0
             join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, merged_includes, options[:joins])
0
             sql << join_dependency.join_associations.collect{|join| join.association_join }.join
...
1
2
3
 
4
5
6
...
274
275
276
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
...
1
2
3
4
5
6
7
...
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
0
@@ -1,6 +1,7 @@
0
 require "cases/helper"
0
 require 'models/company'
0
 require 'models/topic'
0
+require 'models/edge'
0
 
0
 Company.has_many :accounts
0
 
0
@@ -274,4 +275,49 @@ class CalculationsTest < ActiveRecord::TestCase
0
   def test_should_sum_expression
0
     assert_equal 636, Account.sum("2 * credit_limit")
0
   end
0
+
0
+  def test_count_with_from_option
0
+    assert_equal Company.count(:all), Company.count(:all, :from => 'companies')
0
+    assert_equal Account.count(:all, :conditions => "credit_limit = 50"),
0
+        Account.count(:all, :from => 'accounts', :conditions => "credit_limit = 50")
0
+    assert_equal Company.count(:type, :conditions => {:type => "Firm"}),
0
+        Company.count(:type, :conditions => {:type => "Firm"}, :from => 'companies')
0
+  end
0
+
0
+  def test_sum_with_from_option
0
+    assert_equal Account.sum(:credit_limit), Account.sum(:credit_limit, :from => 'accounts')
0
+    assert_equal Account.sum(:credit_limit, :conditions => "credit_limit > 50"),
0
+        Account.sum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
0
+  end
0
+
0
+  def test_average_with_from_option
0
+    assert_equal Account.average(:credit_limit), Account.average(:credit_limit, :from => 'accounts')
0
+    assert_equal Account.average(:credit_limit, :conditions => "credit_limit > 50"),
0
+        Account.average(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
0
+  end
0
+
0
+  def test_minimum_with_from_option
0
+    assert_equal Account.minimum(:credit_limit), Account.minimum(:credit_limit, :from => 'accounts')
0
+    assert_equal Account.minimum(:credit_limit, :conditions => "credit_limit > 50"),
0
+        Account.minimum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
0
+  end
0
+
0
+  def test_maximum_with_from_option
0
+    assert_equal Account.maximum(:credit_limit), Account.maximum(:credit_limit, :from => 'accounts')
0
+    assert_equal Account.maximum(:credit_limit, :conditions => "credit_limit > 50"),
0
+        Account.maximum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
0
+  end
0
+
0
+  def test_from_option_with_specified_index
0
+    if Edge.connection.adapter_name == 'MySQL'
0
+      assert_equal Edge.count(:all), Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)')
0
+      assert_equal Edge.count(:all, :conditions => 'sink_id < 5'),
0
+          Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)', :conditions => 'sink_id < 5')
0
+    end
0
+  end
0
+
0
+  def test_from_option_with_table_different_than_class
0
+    assert_equal Account.count(:all), Company.count(:all, :from => 'accounts')
0
+  end
0
+
0
 end

Comments