Skip to content

Commit

Permalink
Add :from option to calculations. [#397 state:resolved]
Browse files Browse the repository at this point in the history
  • Loading branch information
yukster authored and jeremy committed Jun 12, 2008
1 parent 4689496 commit 67e8ec0
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 3 deletions.
2 changes: 2 additions & 0 deletions 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]
Expand Down
12 changes: 9 additions & 3 deletions 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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
46 changes: 46 additions & 0 deletions 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

Expand Down Expand Up @@ -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

0 comments on commit 67e8ec0

Please sign in to comment.