Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add :from option to calculations. [#397 state:resolved]

  • Loading branch information...
commit 67e8ec0e07314d367b1dc19ed3a1edf05105f8ce 1 parent 4689496
@yukster yukster authored jeremy committed
View
2  activerecord/CHANGELOG
@@ -1,5 +1,7 @@
*Edge*
+* Add :from option to calculations. #397 [Ben Munat]
+
* Add :validate option to associations to enable/disable the automatic validation of associated models. Resolves #301. [Jan De Poorter]
* PostgreSQL: use 'INSERT ... RETURNING id' for 8.2 and later. [Jeremy Kemper]
View
12 activerecord/lib/active_record/calculations.rb
@@ -1,6 +1,6 @@
module ActiveRecord
module Calculations #:nodoc:
- CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include]
+ CALCULATIONS_OPTIONS = [:conditions, :joins, :order, :select, :group, :having, :distinct, :limit, :offset, :include, :from]
def self.included(base)
base.extend(ClassMethods)
end
@@ -27,6 +27,8 @@ module ClassMethods
# * <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
# include the joined columns.
# * <tt>:distinct</tt>: Set this to true to make this a distinct calculation, such as SELECT COUNT(DISTINCT posts.id) ...
+ # * <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
+ # of a database view).
#
# Examples for counting all:
# Person.count # returns the total count of all people
@@ -178,8 +180,12 @@ def construct_calculation_sql(operation, column_name, options) #:nodoc:
sql = "SELECT COUNT(*) AS #{aggregate_alias}" if use_workaround
sql << ", #{options[:group_field]} AS #{options[:group_alias]}" if options[:group]
- sql << " FROM (SELECT #{distinct}#{column_name}" if use_workaround
- sql << " FROM #{connection.quote_table_name(table_name)} "
+ if options[:from]
+ sql << " FROM #{options[:from]} "
+ else
+ sql << " FROM (SELECT #{distinct}#{column_name}" if use_workaround
+ sql << " FROM #{connection.quote_table_name(table_name)} "
+ end
if merged_includes.any?
join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, merged_includes, options[:joins])
sql << join_dependency.join_associations.collect{|join| join.association_join }.join
View
46 activerecord/test/cases/calculations_test.rb
@@ -1,6 +1,7 @@
require "cases/helper"
require 'models/company'
require 'models/topic'
+require 'models/edge'
Company.has_many :accounts
@@ -274,4 +275,49 @@ def test_count_with_too_many_parameters_raises
def test_should_sum_expression
assert_equal 636, Account.sum("2 * credit_limit")
end
+
+ def test_count_with_from_option
+ assert_equal Company.count(:all), Company.count(:all, :from => 'companies')
+ assert_equal Account.count(:all, :conditions => "credit_limit = 50"),
+ Account.count(:all, :from => 'accounts', :conditions => "credit_limit = 50")
+ assert_equal Company.count(:type, :conditions => {:type => "Firm"}),
+ Company.count(:type, :conditions => {:type => "Firm"}, :from => 'companies')
+ end
+
+ def test_sum_with_from_option
+ assert_equal Account.sum(:credit_limit), Account.sum(:credit_limit, :from => 'accounts')
+ assert_equal Account.sum(:credit_limit, :conditions => "credit_limit > 50"),
+ Account.sum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
+ end
+
+ def test_average_with_from_option
+ assert_equal Account.average(:credit_limit), Account.average(:credit_limit, :from => 'accounts')
+ assert_equal Account.average(:credit_limit, :conditions => "credit_limit > 50"),
+ Account.average(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
+ end
+
+ def test_minimum_with_from_option
+ assert_equal Account.minimum(:credit_limit), Account.minimum(:credit_limit, :from => 'accounts')
+ assert_equal Account.minimum(:credit_limit, :conditions => "credit_limit > 50"),
+ Account.minimum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
+ end
+
+ def test_maximum_with_from_option
+ assert_equal Account.maximum(:credit_limit), Account.maximum(:credit_limit, :from => 'accounts')
+ assert_equal Account.maximum(:credit_limit, :conditions => "credit_limit > 50"),
+ Account.maximum(:credit_limit, :from => 'accounts', :conditions => "credit_limit > 50")
+ end
+
+ def test_from_option_with_specified_index
+ if Edge.connection.adapter_name == 'MySQL'
+ assert_equal Edge.count(:all), Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)')
+ assert_equal Edge.count(:all, :conditions => 'sink_id < 5'),
+ Edge.count(:all, :from => 'edges USE INDEX(unique_edge_index)', :conditions => 'sink_id < 5')
+ end
+ end
+
+ def test_from_option_with_table_different_than_class
+ assert_equal Account.count(:all), Company.count(:all, :from => 'accounts')
+ end
+
end
Please sign in to comment.
Something went wrong with that request. Please try again.