activerecord 4.1.1 → 4.1.2.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +312 -0
  3. data/lib/active_record/association_relation.rb +4 -0
  4. data/lib/active_record/associations.rb +24 -3
  5. data/lib/active_record/associations/association.rb +1 -1
  6. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +10 -4
  7. data/lib/active_record/associations/builder/has_many.rb +1 -1
  8. data/lib/active_record/associations/collection_association.rb +5 -5
  9. data/lib/active_record/associations/collection_proxy.rb +4 -0
  10. data/lib/active_record/associations/has_many_association.rb +6 -5
  11. data/lib/active_record/associations/has_many_through_association.rb +6 -2
  12. data/lib/active_record/associations/join_dependency.rb +1 -1
  13. data/lib/active_record/associations/join_dependency/join_association.rb +1 -1
  14. data/lib/active_record/associations/preloader.rb +14 -35
  15. data/lib/active_record/associations/preloader/association.rb +26 -5
  16. data/lib/active_record/associations/singular_association.rb +3 -3
  17. data/lib/active_record/associations/through_association.rb +4 -2
  18. data/lib/active_record/attribute_methods.rb +2 -0
  19. data/lib/active_record/attribute_methods/dirty.rb +2 -2
  20. data/lib/active_record/attribute_methods/serialization.rb +24 -5
  21. data/lib/active_record/attribute_methods/write.rb +22 -14
  22. data/lib/active_record/autosave_association.rb +40 -35
  23. data/lib/active_record/base.rb +2 -2
  24. data/lib/active_record/callbacks.rb +2 -2
  25. data/lib/active_record/connection_adapters/abstract/database_statements.rb +10 -13
  26. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -0
  27. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +7 -1
  28. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
  29. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +8 -6
  30. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +1 -4
  31. data/lib/active_record/connection_adapters/postgresql/oid.rb +10 -5
  32. data/lib/active_record/connection_adapters/postgresql/quoting.rb +9 -0
  33. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +11 -6
  34. data/lib/active_record/connection_adapters/postgresql_adapter.rb +7 -0
  35. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +6 -3
  36. data/lib/active_record/connection_handling.rb +2 -2
  37. data/lib/active_record/core.rb +3 -0
  38. data/lib/active_record/counter_cache.rb +2 -3
  39. data/lib/active_record/fixtures.rb +1 -1
  40. data/lib/active_record/gem_version.rb +2 -2
  41. data/lib/active_record/locking/optimistic.rb +1 -1
  42. data/lib/active_record/log_subscriber.rb +1 -1
  43. data/lib/active_record/migration.rb +1 -1
  44. data/lib/active_record/nested_attributes.rb +2 -2
  45. data/lib/active_record/null_relation.rb +19 -5
  46. data/lib/active_record/persistence.rb +8 -8
  47. data/lib/active_record/railties/databases.rake +3 -2
  48. data/lib/active_record/reflection.rb +45 -13
  49. data/lib/active_record/relation.rb +7 -6
  50. data/lib/active_record/relation/calculations.rb +10 -2
  51. data/lib/active_record/relation/delegation.rb +2 -2
  52. data/lib/active_record/relation/finder_methods.rb +1 -1
  53. data/lib/active_record/relation/merger.rb +10 -2
  54. data/lib/active_record/relation/predicate_builder.rb +2 -2
  55. data/lib/active_record/relation/query_methods.rb +2 -2
  56. data/lib/active_record/scoping/default.rb +3 -3
  57. data/lib/active_record/store.rb +14 -5
  58. data/lib/active_record/timestamp.rb +2 -2
  59. data/lib/active_record/transactions.rb +1 -1
  60. data/lib/active_record/validations/presence.rb +1 -1
  61. data/lib/active_record/validations/uniqueness.rb +2 -2
  62. metadata +27 -35
@@ -296,7 +296,6 @@ module ActiveRecord #:nodoc:
296
296
 
297
297
  include Core
298
298
  include Persistence
299
- include NoTouching
300
299
  include ReadonlyAttributes
301
300
  include ModelSchema
302
301
  include Inheritance
@@ -310,14 +309,15 @@ module ActiveRecord #:nodoc:
310
309
  include Locking::Optimistic
311
310
  include Locking::Pessimistic
312
311
  include AttributeMethods
313
- include Callbacks
314
312
  include Timestamp
313
+ include Callbacks
315
314
  include Associations
316
315
  include ActiveModel::SecurePassword
317
316
  include AutosaveAssociation
318
317
  include NestedAttributes
319
318
  include Aggregations
320
319
  include Transactions
320
+ include NoTouching
321
321
  include Reflection
322
322
  include Serialization
323
323
  include Store
@@ -302,11 +302,11 @@ module ActiveRecord
302
302
  run_callbacks(:save) { super }
303
303
  end
304
304
 
305
- def create_record #:nodoc:
305
+ def _create_record #:nodoc:
306
306
  run_callbacks(:create) { super }
307
307
  end
308
308
 
309
- def update_record(*) #:nodoc:
309
+ def _update_record(*) #:nodoc:
310
310
  run_callbacks(:update) { super }
311
311
  end
312
312
  end
@@ -20,14 +20,7 @@ module ActiveRecord
20
20
 
21
21
  # Returns an ActiveRecord::Result instance.
22
22
  def select_all(arel, name = nil, binds = [])
23
- if arel.is_a?(Relation)
24
- relation = arel
25
- arel = relation.arel
26
- if !binds || binds.empty?
27
- binds = relation.bind_values
28
- end
29
- end
30
-
23
+ arel, binds = binds_from_relation arel, binds
31
24
  select(to_sql(arel, binds), name, binds)
32
25
  end
33
26
 
@@ -47,10 +40,7 @@ module ActiveRecord
47
40
  # Returns an array of the values of the first column in a select:
48
41
  # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
49
42
  def select_values(arel, name = nil)
50
- binds = []
51
- if arel.is_a?(Relation)
52
- arel, binds = arel.arel, arel.bind_values
53
- end
43
+ arel, binds = binds_from_relation arel, []
54
44
  select_rows(to_sql(arel, binds), name, binds).map(&:first)
55
45
  end
56
46
 
@@ -328,7 +318,7 @@ module ActiveRecord
328
318
  def sanitize_limit(limit)
329
319
  if limit.is_a?(Integer) || limit.is_a?(Arel::Nodes::SqlLiteral)
330
320
  limit
331
- elsif limit.to_s =~ /,/
321
+ elsif limit.to_s.include?(',')
332
322
  Arel.sql limit.to_s.split(',').map{ |i| Integer(i) }.join(',')
333
323
  else
334
324
  Integer(limit)
@@ -389,6 +379,13 @@ module ActiveRecord
389
379
  row = result.rows.first
390
380
  row && row.first
391
381
  end
382
+
383
+ def binds_from_relation(relation, binds)
384
+ if relation.is_a?(Relation) && binds.blank?
385
+ relation, binds = relation.arel, relation.bind_values
386
+ end
387
+ [relation, binds]
388
+ end
392
389
  end
393
390
  end
394
391
  end
@@ -63,6 +63,7 @@ module ActiveRecord
63
63
 
64
64
  def select_all(arel, name = nil, binds = [])
65
65
  if @query_cache_enabled && !locked?(arel)
66
+ arel, binds = binds_from_relation arel, binds
66
67
  sql = to_sql(arel, binds)
67
68
  cache_sql(sql, binds) { super(sql, name, binds) }
68
69
  else
@@ -64,7 +64,7 @@ module ActiveRecord
64
64
  end
65
65
 
66
66
  def add_column_options!(sql, options)
67
- sql << " DEFAULT #{@conn.quote(options[:default], options[:column])}" if options_include_default?(options)
67
+ sql << " DEFAULT #{quote_value(options[:default], options[:column])}" if options_include_default?(options)
68
68
  # must explicitly check for :null to allow change_column to work on migrations
69
69
  if options[:null] == false
70
70
  sql << " NOT NULL"
@@ -75,6 +75,12 @@ module ActiveRecord
75
75
  sql
76
76
  end
77
77
 
78
+ def quote_value(value, column)
79
+ column.sql_type ||= type_to_sql(column.type, column.limit, column.precision, column.scale)
80
+
81
+ @conn.quote(value, column)
82
+ end
83
+
78
84
  def options_include_default?(options)
79
85
  options.include?(:default) && !(options[:null] == false && options[:default].nil?)
80
86
  end
@@ -15,7 +15,7 @@ module ActiveRecord
15
15
  # are typically created by methods in TableDefinition, and added to the
16
16
  # +columns+ attribute of said TableDefinition object, in order to be used
17
17
  # for generating a number of table creation or table changing SQL statements.
18
- class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key) #:nodoc:
18
+ class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key, :sql_type) #:nodoc:
19
19
 
20
20
  def primary_key?
21
21
  primary_key || type.to_sym == :primary_key
@@ -17,7 +17,7 @@ module ActiveRecord
17
17
  options = o.options
18
18
  sql_type = type_to_sql(o.type, options[:limit], options[:precision], options[:scale])
19
19
  change_column_sql = "CHANGE #{quote_column_name(column.name)} #{quote_column_name(options[:name])} #{sql_type}"
20
- add_column_options!(change_column_sql, options)
20
+ add_column_options!(change_column_sql, options.merge(column: column))
21
21
  add_column_position!(change_column_sql, options)
22
22
  end
23
23
 
@@ -111,6 +111,8 @@ module ActiveRecord
111
111
  when /^mediumint/i; 3
112
112
  when /^smallint/i; 2
113
113
  when /^tinyint/i; 1
114
+ when /^float/i; 24
115
+ when /^double/i; 53
114
116
  else
115
117
  super
116
118
  end
@@ -737,22 +739,22 @@ module ActiveRecord
737
739
  end
738
740
 
739
741
  def configure_connection
740
- variables = @config[:variables] || {}
742
+ variables = @config.fetch(:variables, {}).stringify_keys
741
743
 
742
744
  # By default, MySQL 'where id is null' selects the last inserted id.
743
745
  # Turn this off. http://dev.rubyonrails.org/ticket/6778
744
- variables[:sql_auto_is_null] = 0
746
+ variables['sql_auto_is_null'] = 0
745
747
 
746
748
  # Increase timeout so the server doesn't disconnect us.
747
749
  wait_timeout = @config[:wait_timeout]
748
750
  wait_timeout = 2147483 unless wait_timeout.is_a?(Fixnum)
749
- variables[:wait_timeout] = self.class.type_cast_config_to_integer(wait_timeout)
751
+ variables['wait_timeout'] = self.class.type_cast_config_to_integer(wait_timeout)
750
752
 
751
753
  # Make MySQL reject illegal values rather than truncating or blanking them, see
752
754
  # http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html#sqlmode_strict_all_tables
753
755
  # If the user has provided another value for sql_mode, don't replace it.
754
- if strict_mode? && !variables.has_key?(:sql_mode)
755
- variables[:sql_mode] = 'STRICT_ALL_TABLES'
756
+ if strict_mode? && !variables.has_key?('sql_mode')
757
+ variables['sql_mode'] = 'STRICT_ALL_TABLES'
756
758
  end
757
759
 
758
760
  # NAMES does not have an equals sign, see
@@ -142,10 +142,7 @@ module ActiveRecord
142
142
  fields.each_with_index do |fname, i|
143
143
  ftype = result.ftype i
144
144
  fmod = result.fmod i
145
- types[fname] = type_map.fetch(ftype, fmod) { |oid, mod|
146
- warn "unknown OID: #{fname}(#{oid}) (#{sql})"
147
- OID::Identity.new
148
- }
145
+ types[fname] = get_oid_type(ftype, fmod, fname)
149
146
  end
150
147
 
151
148
  ret = ActiveRecord::Result.new(fields, result.values, types)
@@ -137,7 +137,7 @@ module ActiveRecord
137
137
  case @subtype
138
138
  when :date
139
139
  from = ConnectionAdapters::Column.value_to_date(extracted[:from])
140
- from -= 1.day if extracted[:exclude_start]
140
+ from += 1.day if extracted[:exclude_start]
141
141
  to = ConnectionAdapters::Column.value_to_date(extracted[:to])
142
142
  when :decimal
143
143
  from = BigDecimal.new(extracted[:from].to_s)
@@ -148,7 +148,7 @@ module ActiveRecord
148
148
  to = ConnectionAdapters::Column.string_to_time(extracted[:to])
149
149
  when :integer
150
150
  from = to_integer(extracted[:from]) rescue value ? 1 : 0
151
- from -= 1 if extracted[:exclude_start]
151
+ from += 1 if extracted[:exclude_start]
152
152
  to = to_integer(extracted[:to]) rescue value ? 1 : 0
153
153
  else
154
154
  return value
@@ -210,9 +210,14 @@ module ActiveRecord
210
210
 
211
211
  class Float < Type
212
212
  def type_cast(value)
213
- return if value.nil?
214
-
215
- value.to_f
213
+ case value
214
+ when nil; nil
215
+ when 'Infinity'; ::Float::INFINITY
216
+ when '-Infinity'; -::Float::INFINITY
217
+ when 'NaN'; ::Float::NAN
218
+ else
219
+ value.to_f
220
+ end
216
221
  end
217
222
  end
218
223
 
@@ -182,6 +182,15 @@ module ActiveRecord
182
182
  end
183
183
  result
184
184
  end
185
+
186
+ # Does not quote function default values for UUID columns
187
+ def quote_default_value(value, column) #:nodoc:
188
+ if column.type == :uuid && value =~ /\(\)/
189
+ value
190
+ else
191
+ quote(value, column)
192
+ end
193
+ end
185
194
  end
186
195
  end
187
196
  end
@@ -12,7 +12,7 @@ module ActiveRecord
12
12
 
13
13
  def visit_ColumnDefinition(o)
14
14
  sql = super
15
- if o.primary_key? && o.type == :uuid
15
+ if o.primary_key? && o.type != :primary_key
16
16
  sql << " PRIMARY KEY "
17
17
  add_column_options!(sql, column_options(o))
18
18
  end
@@ -185,13 +185,15 @@ module ActiveRecord
185
185
  def columns(table_name)
186
186
  # Limit, precision, and scale are all handled by the superclass.
187
187
  column_definitions(table_name).map do |column_name, type, default, notnull, oid, fmod|
188
- oid = type_map.fetch(oid.to_i, fmod.to_i) {
189
- OID::Identity.new
190
- }
188
+ oid = get_oid_type(oid.to_i, fmod.to_i, column_name)
191
189
  PostgreSQLColumn.new(column_name, default, oid, type, notnull == 'f')
192
190
  end
193
191
  end
194
192
 
193
+ def column_for(table_name, column_name) #:nodoc:
194
+ columns(table_name).detect { |c| c.name == column_name.to_s }
195
+ end
196
+
195
197
  # Returns the current database name.
196
198
  def current_database
197
199
  query('select current_database()', 'SCHEMA')[0][0]
@@ -408,13 +410,16 @@ module ActiveRecord
408
410
  # Changes the default value of a table column.
409
411
  def change_column_default(table_name, column_name, default)
410
412
  clear_cache!
411
- execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{quote(default)}"
413
+ column = column_for(table_name, column_name)
414
+
415
+ execute "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} SET DEFAULT #{quote_default_value(default, column)}" if column
412
416
  end
413
417
 
414
418
  def change_column_null(table_name, column_name, null, default = nil)
415
419
  clear_cache!
416
420
  unless null || default.nil?
417
- execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
421
+ column = column_for(table_name, column_name)
422
+ execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote_default_value(default, column)} WHERE #{quote_column_name(column_name)} IS NULL") if column
418
423
  end
419
424
  execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
420
425
  end
@@ -760,6 +760,13 @@ module ActiveRecord
760
760
  @type_map
761
761
  end
762
762
 
763
+ def get_oid_type(oid, fmod, column_name)
764
+ type_map.fetch(oid, fmod) {
765
+ warn "unknown OID #{oid}: failed to recognize type of '#{column_name}'. It will be treated as String."
766
+ type_map[oid] = OID::Identity.new
767
+ }
768
+ end
769
+
763
770
  def reload_type_map
764
771
  type_map.clear
765
772
  initialize_type_map(type_map)
@@ -299,9 +299,12 @@ module ActiveRecord
299
299
  # Don't cache statements if they are not prepared
300
300
  if without_prepared_statement?(binds)
301
301
  stmt = @connection.prepare(sql)
302
- cols = stmt.columns
303
- records = stmt.to_a
304
- stmt.close
302
+ begin
303
+ cols = stmt.columns
304
+ records = stmt.to_a
305
+ ensure
306
+ stmt.close
307
+ end
305
308
  stmt = records
306
309
  else
307
310
  cache = @statements[sql] ||= {
@@ -18,14 +18,14 @@ module ActiveRecord
18
18
  # Example for SQLite database:
19
19
  #
20
20
  # ActiveRecord::Base.establish_connection(
21
- # adapter: "sqlite",
21
+ # adapter: "sqlite3",
22
22
  # database: "path/to/dbfile"
23
23
  # )
24
24
  #
25
25
  # Also accepts keys as strings (for parsing from YAML for example):
26
26
  #
27
27
  # ActiveRecord::Base.establish_connection(
28
- # "adapter" => "sqlite",
28
+ # "adapter" => "sqlite3",
29
29
  # "database" => "path/to/dbfile"
30
30
  # )
31
31
  #
@@ -220,6 +220,8 @@ module ActiveRecord
220
220
 
221
221
  @new_record = false
222
222
 
223
+ self.class.define_attribute_methods
224
+
223
225
  run_callbacks :find
224
226
  run_callbacks :initialize
225
227
 
@@ -267,6 +269,7 @@ module ActiveRecord
267
269
  @attributes_cache = {}
268
270
 
269
271
  @new_record = true
272
+ @destroyed = false
270
273
 
271
274
  super
272
275
  end
@@ -20,7 +20,7 @@ module ActiveRecord
20
20
  def reset_counters(id, *counters)
21
21
  object = find(id)
22
22
  counters.each do |association|
23
- has_many_association = reflect_on_association(association.to_sym)
23
+ has_many_association = _reflect_on_association(association.to_sym)
24
24
  raise ArgumentError, "'#{self.name}' has no association called '#{association}'" unless has_many_association
25
25
 
26
26
  if has_many_association.is_a? ActiveRecord::Reflection::ThroughReflection
@@ -29,8 +29,7 @@ module ActiveRecord
29
29
 
30
30
  foreign_key = has_many_association.foreign_key.to_s
31
31
  child_class = has_many_association.klass
32
- belongs_to = child_class.reflect_on_all_associations(:belongs_to)
33
- reflection = belongs_to.find { |e| e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
32
+ reflection = child_class._reflections.values.find { |e| :belongs_to == e.macro && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
34
33
  counter_name = reflection.counter_cache_column
35
34
 
36
35
  stmt = unscoped.where(arel_table[primary_key].eq(object.id)).arel.compile_update({
@@ -643,7 +643,7 @@ module ActiveRecord
643
643
  model_class
644
644
  end
645
645
 
646
- reflection_class.reflect_on_all_associations.each do |association|
646
+ reflection_class._reflections.values.each do |association|
647
647
  case association.macro
648
648
  when :belongs_to
649
649
  # Do not replace association name with association foreign key if they are named the same
@@ -7,8 +7,8 @@ module ActiveRecord
7
7
  module VERSION
8
8
  MAJOR = 4
9
9
  MINOR = 1
10
- TINY = 1
11
- PRE = nil
10
+ TINY = 2
11
+ PRE = "rc1"
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
14
14
  end
@@ -66,7 +66,7 @@ module ActiveRecord
66
66
  send(lock_col + '=', previous_lock_value + 1)
67
67
  end
68
68
 
69
- def update_record(attribute_names = @attributes.keys) #:nodoc:
69
+ def _update_record(attribute_names = @attributes.keys) #:nodoc:
70
70
  return super unless locking_enabled?
71
71
  return 0 if attribute_names.empty?
72
72
 
@@ -25,7 +25,7 @@ module ActiveRecord
25
25
  if column.binary?
26
26
  # This specifically deals with the PG adapter that casts bytea columns into a Hash.
27
27
  value = value[:value] if value.is_a?(Hash)
28
- value = "<#{value.bytesize} bytes of binary data>"
28
+ value = value ? "<#{value.bytesize} bytes of binary data>" : "<NULL binary data>"
29
29
  end
30
30
 
31
31
  [column.name, value]
@@ -640,7 +640,7 @@ module ActiveRecord
640
640
 
641
641
  say_with_time "#{method}(#{arg_list})" do
642
642
  unless @connection.respond_to? :revert
643
- unless arguments.empty? || method == :execute
643
+ unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
644
644
  arguments[0] = proper_table_name(arguments.first, table_name_options)
645
645
  arguments[1] = proper_table_name(arguments.second, table_name_options) if method == :rename_table
646
646
  end
@@ -305,7 +305,7 @@ module ActiveRecord
305
305
  options[:reject_if] = REJECT_ALL_BLANK_PROC if options[:reject_if] == :all_blank
306
306
 
307
307
  attr_names.each do |association_name|
308
- if reflection = reflect_on_association(association_name)
308
+ if reflection = _reflect_on_association(association_name)
309
309
  reflection.autosave = true
310
310
  add_autosave_association_callbacks(reflection)
311
311
 
@@ -542,7 +542,7 @@ module ActiveRecord
542
542
  end
543
543
 
544
544
  def raise_nested_attributes_record_not_found!(association_name, record_id)
545
- raise RecordNotFound, "Couldn't find #{self.class.reflect_on_association(association_name).klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}"
545
+ raise RecordNotFound, "Couldn't find #{self.class._reflect_on_association(association_name).klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}"
546
546
  end
547
547
  end
548
548
  end
@@ -23,7 +23,7 @@ module ActiveRecord
23
23
  end
24
24
 
25
25
  def size
26
- 0
26
+ calculate :size, nil
27
27
  end
28
28
 
29
29
  def empty?
@@ -43,18 +43,32 @@ module ActiveRecord
43
43
  end
44
44
 
45
45
  def count(*)
46
- 0
46
+ calculate :count, nil
47
47
  end
48
48
 
49
49
  def sum(*)
50
- 0
50
+ calculate :sum, nil
51
+ end
52
+
53
+ def average(*)
54
+ calculate :average, nil
55
+ end
56
+
57
+ def minimum(*)
58
+ calculate :minimum, nil
59
+ end
60
+
61
+ def maximum(*)
62
+ calculate :maximum, nil
51
63
  end
52
64
 
53
65
  def calculate(operation, _column_name, _options = {})
54
66
  # TODO: Remove _options argument as soon we remove support to
55
67
  # activerecord-deprecated_finders.
56
- if operation == :count
57
- 0
68
+ if [:count, :sum, :size].include? operation
69
+ group_values.any? ? Hash.new : 0
70
+ elsif [:average, :minimum, :maximum].include?(operation) && group_values.any?
71
+ Hash.new
58
72
  else
59
73
  nil
60
74
  end