diff options
Diffstat (limited to 'activerecord/lib/active_record/relation')
5 files changed, 47 insertions, 30 deletions
diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb index d52b84179f..46ab67d1cf 100644 --- a/activerecord/lib/active_record/relation/batches.rb +++ b/activerecord/lib/active_record/relation/batches.rb @@ -20,8 +20,6 @@ module ActiveRecord find_in_batches(options) do |records| records.each { |record| yield record } end - - self end # Yields each batch of records that was found by the find +options+ as diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 0fcae92d51..0ac821b2d7 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -66,7 +66,7 @@ module ActiveRecord calculate(:average, column_name, options) end - # Calculates the minimum value on a given column. The value is returned + # Calculates the minimum value on a given column. The value is returned # with the same data type of the column, or +nil+ if there's no row. See # +calculate+ for examples with options. # @@ -89,11 +89,15 @@ module ActiveRecord # +calculate+ for examples with options. # # Person.sum('age') # => 4562 - def sum(column_name, options = {}) - calculate(:sum, column_name, options) + def sum(*args) + if block_given? + self.to_a.sum(*args) {|*block_args| yield(*block_args)} + else + calculate(:sum, *args) + end end - # This calculates aggregate values in the given column. Methods for count, sum, average, + # This calculates aggregate values in the given column. Methods for count, sum, average, # minimum, and maximum have been added as shortcuts. Options such as <tt>:conditions</tt>, # <tt>:order</tt>, <tt>:group</tt>, <tt>:having</tt>, and <tt>:joins</tt> can be passed to customize the query. # @@ -101,7 +105,7 @@ module ActiveRecord # * Single aggregate value: The single value is type cast to Fixnum for COUNT, Float # for AVG, and the given column's type for everything else. # * Grouped values: This returns an ordered hash of the values and groups them by the - # <tt>:group</tt> option. It takes either a column name, or the name of a belongs_to association. + # <tt>:group</tt> option. It takes either a column name, or the name of a belongs_to association. # # values = Person.maximum(:age, :group => 'last_name') # puts values["Drake"] @@ -119,7 +123,7 @@ module ActiveRecord # Options: # * <tt>:conditions</tt> - An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. # See conditions in the intro to ActiveRecord::Base. - # * <tt>:include</tt>: Eager loading, see Associations for details. Since calculations don't load anything, + # * <tt>:include</tt>: Eager loading, see Associations for details. Since calculations don't load anything, # the purpose of this is to access fields on joined tables in your conditions, order, or group clauses. # * <tt>:joins</tt> - An SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id". # (Rarely needed). @@ -146,10 +150,16 @@ module ActiveRecord if options.except(:distinct).present? apply_finder_options(options.except(:distinct)).calculate(operation, column_name, :distinct => options[:distinct]) else - if eager_loading? || (includes_values.present? && references_eager_loaded_tables?) - construct_relation_for_association_calculations.calculate(operation, column_name, options) + relation = with_default_scope + + if relation.equal?(self) + if eager_loading? || (includes_values.present? && references_eager_loaded_tables?) + construct_relation_for_association_calculations.calculate(operation, column_name, options) + else + perform_calculation(operation, column_name, options) + end else - perform_calculation(operation, column_name, options) + relation.calculate(operation, column_name, options) end end rescue ThrowResult diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 4659563f33..283115a448 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -83,7 +83,7 @@ module ActiveRecord # # Example for find with a lock: Imagine two concurrent transactions: # each will read <tt>person.visits == 2</tt>, add 1 to it, and save, resulting - # in two saves of <tt>person.visits = 3</tt>. By locking the row, the second + # in two saves of <tt>person.visits = 3</tt>. By locking the row, the second # transaction has to wait until the first is finished; we get the # expected <tt>person.visits == 4</tt>. # @@ -193,8 +193,8 @@ module ActiveRecord else relation = relation.where(table[primary_key].eq(id)) if id end - - connection.select_value(relation.to_sql) ? true : false + + connection.select_value(relation.to_sql, "#{name} Exists") ? true : false end protected @@ -259,6 +259,7 @@ module ActiveRecord if match.bang? && result.blank? raise RecordNotFound, "Couldn't find #{@klass.name} with #{conditions.to_a.collect {|p| p.join(' = ')}.join(', ')}" else + yield(result) if block_given? result end end diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb index 94aa999715..8bd4732c0c 100644 --- a/activerecord/lib/active_record/relation/query_methods.rb +++ b/activerecord/lib/active_record/relation/query_methods.rb @@ -9,7 +9,7 @@ module ActiveRecord :select_values, :group_values, :order_values, :joins_values, :where_values, :having_values, :bind_values, :limit_value, :offset_value, :lock_value, :readonly_value, :create_with_value, - :from_value, :reorder_value + :from_value, :reorder_value, :reverse_order_value def includes(*args) args.reject! {|a| a.blank? } @@ -96,11 +96,11 @@ module ActiveRecord relation end - def having(*args) - return self if args.blank? + def having(opts, *rest) + return self if opts.blank? relation = clone - relation.having_values += build_where(*args) + relation.having_values += build_where(opts, rest) relation end @@ -137,7 +137,7 @@ module ActiveRecord def create_with(value) relation = clone - relation.create_with_value = value && (@create_with_value || {}).merge(value) + relation.create_with_value = value ? create_with_value.merge(value) : {} relation end @@ -158,13 +158,9 @@ module ActiveRecord end def reverse_order - order_clause = arel.order_clauses - - order = order_clause.empty? ? - "#{table_name}.#{primary_key} DESC" : - reverse_sql_order(order_clause).join(', ') - - except(:order).order(Arel.sql(order)) + relation = clone + relation.reverse_order_value = !relation.reverse_order_value + relation end def arel @@ -186,6 +182,7 @@ module ActiveRecord arel.group(*@group_values.uniq.reject{|g| g.blank?}) unless @group_values.empty? order = @reorder_value ? @reorder_value : @order_values + order = reverse_sql_order(order) if @reverse_order_value arel.order(*order.uniq.reject{|o| o.blank?}) unless order.empty? build_select(arel, @select_values.uniq) @@ -306,9 +303,20 @@ module ActiveRecord end def reverse_sql_order(order_query) - order_query.join(', ').split(',').collect do |s| - s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC') - end + order_query = ["#{quoted_table_name}.#{quoted_primary_key} ASC"] if order_query.empty? + + order_query.map do |o| + case o + when Arel::Nodes::Ordering + o.reverse + when String, Symbol + o.to_s.split(',').collect do |s| + s.gsub!(/\sasc\Z/i, ' DESC') || s.gsub!(/\sdesc\Z/i, ' ASC') || s.concat(' DESC') + end + else + o + end + end.flatten end def array_of_strings?(o) diff --git a/activerecord/lib/active_record/relation/spawn_methods.rb b/activerecord/lib/active_record/relation/spawn_methods.rb index 69706b5ead..ba882beca9 100644 --- a/activerecord/lib/active_record/relation/spawn_methods.rb +++ b/activerecord/lib/active_record/relation/spawn_methods.rb @@ -55,7 +55,7 @@ module ActiveRecord merged_relation.lock_value = r.lock_value unless merged_relation.lock_value - merged_relation = merged_relation.create_with(r.create_with_value) if r.create_with_value + merged_relation = merged_relation.create_with(r.create_with_value) unless r.create_with_value.empty? # Apply scope extension modules merged_relation.send :apply_modules, r.extensions |