activerecord 4.2.0 → 5.0.0

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 (249) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1537 -789
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -8
  5. data/examples/performance.rb +2 -3
  6. data/examples/simple.rb +0 -1
  7. data/lib/active_record/aggregations.rb +37 -23
  8. data/lib/active_record/association_relation.rb +16 -3
  9. data/lib/active_record/associations/alias_tracker.rb +19 -16
  10. data/lib/active_record/associations/association.rb +23 -9
  11. data/lib/active_record/associations/association_scope.rb +74 -102
  12. data/lib/active_record/associations/belongs_to_association.rb +26 -29
  13. data/lib/active_record/associations/builder/association.rb +28 -34
  14. data/lib/active_record/associations/builder/belongs_to.rb +43 -18
  15. data/lib/active_record/associations/builder/collection_association.rb +12 -20
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +22 -15
  17. data/lib/active_record/associations/builder/has_many.rb +4 -4
  18. data/lib/active_record/associations/builder/has_one.rb +11 -6
  19. data/lib/active_record/associations/builder/singular_association.rb +3 -10
  20. data/lib/active_record/associations/collection_association.rb +61 -33
  21. data/lib/active_record/associations/collection_proxy.rb +81 -35
  22. data/lib/active_record/associations/foreign_association.rb +11 -0
  23. data/lib/active_record/associations/has_many_association.rb +21 -57
  24. data/lib/active_record/associations/has_many_through_association.rb +15 -45
  25. data/lib/active_record/associations/has_one_association.rb +13 -5
  26. data/lib/active_record/associations/join_dependency/join_association.rb +20 -8
  27. data/lib/active_record/associations/join_dependency.rb +37 -21
  28. data/lib/active_record/associations/preloader/association.rb +51 -53
  29. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  30. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  31. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  32. data/lib/active_record/associations/preloader/through_association.rb +27 -14
  33. data/lib/active_record/associations/preloader.rb +18 -8
  34. data/lib/active_record/associations/singular_association.rb +8 -8
  35. data/lib/active_record/associations/through_association.rb +22 -9
  36. data/lib/active_record/associations.rb +321 -212
  37. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  38. data/lib/active_record/attribute.rb +79 -15
  39. data/lib/active_record/attribute_assignment.rb +20 -141
  40. data/lib/active_record/attribute_decorators.rb +6 -5
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +6 -1
  42. data/lib/active_record/attribute_methods/dirty.rb +51 -81
  43. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  44. data/lib/active_record/attribute_methods/query.rb +2 -2
  45. data/lib/active_record/attribute_methods/read.rb +31 -59
  46. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +65 -14
  48. data/lib/active_record/attribute_methods/write.rb +14 -38
  49. data/lib/active_record/attribute_methods.rb +70 -45
  50. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  51. data/lib/active_record/attribute_set/builder.rb +37 -15
  52. data/lib/active_record/attribute_set.rb +34 -3
  53. data/lib/active_record/attributes.rb +199 -73
  54. data/lib/active_record/autosave_association.rb +73 -25
  55. data/lib/active_record/base.rb +35 -27
  56. data/lib/active_record/callbacks.rb +39 -43
  57. data/lib/active_record/coders/json.rb +1 -1
  58. data/lib/active_record/coders/yaml_column.rb +20 -8
  59. data/lib/active_record/collection_cache_key.rb +40 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +457 -181
  61. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  62. data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -59
  63. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -3
  64. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -9
  65. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -4
  66. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +61 -39
  67. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +246 -185
  68. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +72 -17
  69. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +438 -136
  70. data/lib/active_record/connection_adapters/abstract/transaction.rb +53 -40
  71. data/lib/active_record/connection_adapters/abstract_adapter.rb +166 -66
  72. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +429 -335
  73. data/lib/active_record/connection_adapters/column.rb +28 -43
  74. data/lib/active_record/connection_adapters/connection_specification.rb +15 -27
  75. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  76. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  77. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  78. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  79. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  81. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  82. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  83. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  84. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -177
  85. data/lib/active_record/connection_adapters/postgresql/column.rb +5 -10
  86. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +11 -73
  87. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +27 -56
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -13
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -1
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  95. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  97. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -4
  98. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  99. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +31 -17
  101. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +17 -5
  102. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  103. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  104. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  106. data/lib/active_record/connection_adapters/postgresql/quoting.rb +26 -18
  107. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  108. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  109. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +248 -154
  111. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  112. data/lib/active_record/connection_adapters/postgresql_adapter.rb +258 -170
  113. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  114. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  115. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  116. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  117. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  118. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +150 -209
  119. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  120. data/lib/active_record/connection_handling.rb +38 -15
  121. data/lib/active_record/core.rb +109 -114
  122. data/lib/active_record/counter_cache.rb +14 -25
  123. data/lib/active_record/dynamic_matchers.rb +1 -20
  124. data/lib/active_record/enum.rb +115 -79
  125. data/lib/active_record/errors.rb +88 -48
  126. data/lib/active_record/explain_registry.rb +1 -1
  127. data/lib/active_record/explain_subscriber.rb +2 -2
  128. data/lib/active_record/fixture_set/file.rb +26 -5
  129. data/lib/active_record/fixtures.rb +84 -46
  130. data/lib/active_record/gem_version.rb +2 -2
  131. data/lib/active_record/inheritance.rb +32 -40
  132. data/lib/active_record/integration.rb +4 -4
  133. data/lib/active_record/internal_metadata.rb +56 -0
  134. data/lib/active_record/legacy_yaml_adapter.rb +46 -0
  135. data/lib/active_record/locale/en.yml +3 -2
  136. data/lib/active_record/locking/optimistic.rb +27 -25
  137. data/lib/active_record/locking/pessimistic.rb +1 -1
  138. data/lib/active_record/log_subscriber.rb +43 -21
  139. data/lib/active_record/migration/command_recorder.rb +59 -18
  140. data/lib/active_record/migration/compatibility.rb +126 -0
  141. data/lib/active_record/migration.rb +372 -114
  142. data/lib/active_record/model_schema.rb +128 -38
  143. data/lib/active_record/nested_attributes.rb +71 -32
  144. data/lib/active_record/no_touching.rb +1 -1
  145. data/lib/active_record/null_relation.rb +16 -8
  146. data/lib/active_record/persistence.rb +124 -80
  147. data/lib/active_record/query_cache.rb +15 -18
  148. data/lib/active_record/querying.rb +10 -9
  149. data/lib/active_record/railtie.rb +28 -19
  150. data/lib/active_record/railties/controller_runtime.rb +1 -1
  151. data/lib/active_record/railties/databases.rake +67 -51
  152. data/lib/active_record/readonly_attributes.rb +1 -1
  153. data/lib/active_record/reflection.rb +318 -139
  154. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  155. data/lib/active_record/relation/batches.rb +139 -34
  156. data/lib/active_record/relation/calculations.rb +80 -102
  157. data/lib/active_record/relation/delegation.rb +7 -20
  158. data/lib/active_record/relation/finder_methods.rb +167 -97
  159. data/lib/active_record/relation/from_clause.rb +32 -0
  160. data/lib/active_record/relation/merger.rb +38 -41
  161. data/lib/active_record/relation/predicate_builder/array_handler.rb +12 -16
  162. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  163. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  164. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  165. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  166. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  167. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  168. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  169. data/lib/active_record/relation/predicate_builder.rb +124 -82
  170. data/lib/active_record/relation/query_attribute.rb +19 -0
  171. data/lib/active_record/relation/query_methods.rb +323 -257
  172. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  173. data/lib/active_record/relation/spawn_methods.rb +11 -10
  174. data/lib/active_record/relation/where_clause.rb +174 -0
  175. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  176. data/lib/active_record/relation.rb +176 -115
  177. data/lib/active_record/result.rb +4 -3
  178. data/lib/active_record/runtime_registry.rb +1 -1
  179. data/lib/active_record/sanitization.rb +95 -66
  180. data/lib/active_record/schema.rb +26 -22
  181. data/lib/active_record/schema_dumper.rb +62 -38
  182. data/lib/active_record/schema_migration.rb +11 -17
  183. data/lib/active_record/scoping/default.rb +24 -9
  184. data/lib/active_record/scoping/named.rb +49 -28
  185. data/lib/active_record/scoping.rb +32 -15
  186. data/lib/active_record/secure_token.rb +38 -0
  187. data/lib/active_record/serialization.rb +2 -4
  188. data/lib/active_record/statement_cache.rb +16 -14
  189. data/lib/active_record/store.rb +8 -3
  190. data/lib/active_record/suppressor.rb +58 -0
  191. data/lib/active_record/table_metadata.rb +68 -0
  192. data/lib/active_record/tasks/database_tasks.rb +59 -42
  193. data/lib/active_record/tasks/mysql_database_tasks.rb +32 -26
  194. data/lib/active_record/tasks/postgresql_database_tasks.rb +29 -9
  195. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  196. data/lib/active_record/timestamp.rb +20 -9
  197. data/lib/active_record/touch_later.rb +58 -0
  198. data/lib/active_record/transactions.rb +159 -67
  199. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  200. data/lib/active_record/type/date.rb +2 -41
  201. data/lib/active_record/type/date_time.rb +2 -38
  202. data/lib/active_record/type/hash_lookup_type_map.rb +8 -2
  203. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  204. data/lib/active_record/type/internal/timezone.rb +15 -0
  205. data/lib/active_record/type/serialized.rb +21 -14
  206. data/lib/active_record/type/time.rb +10 -16
  207. data/lib/active_record/type/type_map.rb +4 -4
  208. data/lib/active_record/type.rb +66 -17
  209. data/lib/active_record/type_caster/connection.rb +29 -0
  210. data/lib/active_record/type_caster/map.rb +19 -0
  211. data/lib/active_record/type_caster.rb +7 -0
  212. data/lib/active_record/validations/absence.rb +23 -0
  213. data/lib/active_record/validations/associated.rb +10 -3
  214. data/lib/active_record/validations/length.rb +24 -0
  215. data/lib/active_record/validations/presence.rb +11 -12
  216. data/lib/active_record/validations/uniqueness.rb +29 -18
  217. data/lib/active_record/validations.rb +33 -32
  218. data/lib/active_record.rb +9 -2
  219. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  220. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -6
  221. data/lib/rails/generators/active_record/migration/templates/migration.rb +8 -7
  222. data/lib/rails/generators/active_record/migration.rb +7 -0
  223. data/lib/rails/generators/active_record/model/model_generator.rb +32 -15
  224. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  225. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  226. metadata +60 -34
  227. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  228. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  229. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  230. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  231. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  232. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  233. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  234. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  235. data/lib/active_record/type/big_integer.rb +0 -13
  236. data/lib/active_record/type/binary.rb +0 -50
  237. data/lib/active_record/type/boolean.rb +0 -30
  238. data/lib/active_record/type/decimal.rb +0 -40
  239. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  240. data/lib/active_record/type/decorator.rb +0 -14
  241. data/lib/active_record/type/float.rb +0 -19
  242. data/lib/active_record/type/integer.rb +0 -55
  243. data/lib/active_record/type/mutable.rb +0 -16
  244. data/lib/active_record/type/numeric.rb +0 -36
  245. data/lib/active_record/type/string.rb +0 -36
  246. data/lib/active_record/type/text.rb +0 -11
  247. data/lib/active_record/type/time_value.rb +0 -38
  248. data/lib/active_record/type/unsigned_integer.rb +0 -15
  249. data/lib/active_record/type/value.rb +0 -101
@@ -14,121 +14,112 @@ module ActiveRecord
14
14
  # Person.distinct.count(:age)
15
15
  # # => counts the number of different age values
16
16
  #
17
- # If +count+ is used with +group+, it returns a Hash whose keys represent the aggregated column,
17
+ # If #count is used with {Relation#group}[rdoc-ref:QueryMethods#group],
18
+ # it returns a Hash whose keys represent the aggregated column,
18
19
  # and the values are the respective amounts:
19
20
  #
20
21
  # Person.group(:city).count
21
22
  # # => { 'Rome' => 5, 'Paris' => 3 }
22
23
  #
23
- # If +count+ is used with +group+ for multiple columns, it returns a Hash whose
24
+ # If #count is used with {Relation#group}[rdoc-ref:QueryMethods#group] for multiple columns, it returns a Hash whose
24
25
  # keys are an array containing the individual values of each column and the value
25
- # of each key would be the +count+.
26
+ # of each key would be the #count.
26
27
  #
27
28
  # Article.group(:status, :category).count
28
29
  # # => {["draft", "business"]=>10, ["draft", "technology"]=>4,
29
30
  # ["published", "business"]=>0, ["published", "technology"]=>2}
30
31
  #
31
- # If +count+ is used with +select+, it will count the selected columns:
32
+ # If #count is used with {Relation#select}[rdoc-ref:QueryMethods#select], it will count the selected columns:
32
33
  #
33
34
  # Person.select(:age).count
34
35
  # # => counts the number of different age values
35
36
  #
36
- # Note: not all valid +select+ expressions are valid +count+ expressions. The specifics differ
37
+ # Note: not all valid {Relation#select}[rdoc-ref:QueryMethods#select] expressions are valid #count expressions. The specifics differ
37
38
  # between databases. In invalid cases, an error from the database is thrown.
38
- def count(column_name = nil, options = {})
39
- # TODO: Remove options argument as soon we remove support to
40
- # activerecord-deprecated_finders.
41
- column_name, options = nil, column_name if column_name.is_a?(Hash)
42
- calculate(:count, column_name, options)
39
+ def count(column_name = nil)
40
+ calculate(:count, column_name)
43
41
  end
44
42
 
45
43
  # Calculates the average value on a given column. Returns +nil+ if there's
46
- # no row. See +calculate+ for examples with options.
44
+ # no row. See #calculate for examples with options.
47
45
  #
48
46
  # Person.average(:age) # => 35.8
49
- def average(column_name, options = {})
50
- # TODO: Remove options argument as soon we remove support to
51
- # activerecord-deprecated_finders.
52
- calculate(:average, column_name, options)
47
+ def average(column_name)
48
+ calculate(:average, column_name)
53
49
  end
54
50
 
55
51
  # Calculates the minimum value on a given column. The value is returned
56
52
  # with the same data type of the column, or +nil+ if there's no row. See
57
- # +calculate+ for examples with options.
53
+ # #calculate for examples with options.
58
54
  #
59
55
  # Person.minimum(:age) # => 7
60
- def minimum(column_name, options = {})
61
- # TODO: Remove options argument as soon we remove support to
62
- # activerecord-deprecated_finders.
63
- calculate(:minimum, column_name, options)
56
+ def minimum(column_name)
57
+ calculate(:minimum, column_name)
64
58
  end
65
59
 
66
60
  # Calculates the maximum value on a given column. The value is returned
67
61
  # with the same data type of the column, or +nil+ if there's no row. See
68
- # +calculate+ for examples with options.
62
+ # #calculate for examples with options.
69
63
  #
70
64
  # Person.maximum(:age) # => 93
71
- def maximum(column_name, options = {})
72
- # TODO: Remove options argument as soon we remove support to
73
- # activerecord-deprecated_finders.
74
- calculate(:maximum, column_name, options)
65
+ def maximum(column_name)
66
+ calculate(:maximum, column_name)
75
67
  end
76
68
 
77
69
  # Calculates the sum of values on a given column. The value is returned
78
- # with the same data type of the column, 0 if there's no row. See
79
- # +calculate+ for examples with options.
70
+ # with the same data type of the column, +0+ if there's no row. See
71
+ # #calculate for examples with options.
80
72
  #
81
73
  # Person.sum(:age) # => 4562
82
- def sum(*args)
83
- calculate(:sum, *args)
74
+ def sum(column_name = nil, &block)
75
+ return super(&block) if block_given?
76
+ calculate(:sum, column_name)
84
77
  end
85
78
 
86
- # This calculates aggregate values in the given column. Methods for count, sum, average,
87
- # minimum, and maximum have been added as shortcuts.
79
+ # This calculates aggregate values in the given column. Methods for #count, #sum, #average,
80
+ # #minimum, and #maximum have been added as shortcuts.
88
81
  #
89
- # There are two basic forms of output:
82
+ # Person.calculate(:count, :all) # The same as Person.count
83
+ # Person.average(:age) # SELECT AVG(age) FROM people...
90
84
  #
91
- # * Single aggregate value: The single value is type cast to Fixnum for COUNT, Float
92
- # for AVG, and the given column's type for everything else.
85
+ # # Selects the minimum age for any family without any minors
86
+ # Person.group(:last_name).having("min(age) > 17").minimum(:age)
93
87
  #
94
- # * Grouped values: This returns an ordered hash of the values and groups them. It
95
- # takes either a column name, or the name of a belongs_to association.
88
+ # Person.sum("2 * age")
96
89
  #
97
- # values = Person.group('last_name').maximum(:age)
98
- # puts values["Drake"]
99
- # # => 43
90
+ # There are two basic forms of output:
100
91
  #
101
- # drake = Family.find_by(last_name: 'Drake')
102
- # values = Person.group(:family).maximum(:age) # Person belongs_to :family
103
- # puts values[drake]
104
- # # => 43
92
+ # * Single aggregate value: The single value is type cast to Integer for COUNT, Float
93
+ # for AVG, and the given column's type for everything else.
105
94
  #
106
- # values.each do |family, max_age|
107
- # ...
108
- # end
95
+ # * Grouped values: This returns an ordered hash of the values and groups them. It
96
+ # takes either a column name, or the name of a belongs_to association.
109
97
  #
110
- # Person.calculate(:count, :all) # The same as Person.count
111
- # Person.average(:age) # SELECT AVG(age) FROM people...
98
+ # values = Person.group('last_name').maximum(:age)
99
+ # puts values["Drake"]
100
+ # # => 43
112
101
  #
113
- # # Selects the minimum age for any family without any minors
114
- # Person.group(:last_name).having("min(age) > 17").minimum(:age)
102
+ # drake = Family.find_by(last_name: 'Drake')
103
+ # values = Person.group(:family).maximum(:age) # Person belongs_to :family
104
+ # puts values[drake]
105
+ # # => 43
115
106
  #
116
- # Person.sum("2 * age")
117
- def calculate(operation, column_name, options = {})
118
- # TODO: Remove options argument as soon we remove support to
119
- # activerecord-deprecated_finders.
107
+ # values.each do |family, max_age|
108
+ # ...
109
+ # end
110
+ def calculate(operation, column_name)
120
111
  if column_name.is_a?(Symbol) && attribute_alias?(column_name)
121
112
  column_name = attribute_alias(column_name)
122
113
  end
123
114
 
124
115
  if has_include?(column_name)
125
- construct_relation_for_association_calculations.calculate(operation, column_name, options)
116
+ construct_relation_for_association_calculations.calculate(operation, column_name)
126
117
  else
127
- perform_calculation(operation, column_name, options)
118
+ perform_calculation(operation, column_name)
128
119
  end
129
120
  end
130
121
 
131
- # Use <tt>pluck</tt> as a shortcut to select one or more attributes without
122
+ # Use #pluck as a shortcut to select one or more attributes without
132
123
  # loading a bunch of records just to grab the attributes you want.
133
124
  #
134
125
  # Person.pluck(:name)
@@ -137,19 +128,19 @@ module ActiveRecord
137
128
  #
138
129
  # Person.all.map(&:name)
139
130
  #
140
- # Pluck returns an <tt>Array</tt> of attribute values type-casted to match
131
+ # Pluck returns an Array of attribute values type-casted to match
141
132
  # the plucked column names, if they can be deduced. Plucking an SQL fragment
142
133
  # returns String values by default.
143
134
  #
144
- # Person.pluck(:id)
145
- # # SELECT people.id FROM people
146
- # # => [1, 2, 3]
135
+ # Person.pluck(:name)
136
+ # # SELECT people.name FROM people
137
+ # # => ['David', 'Jeremy', 'Jose']
147
138
  #
148
139
  # Person.pluck(:id, :name)
149
140
  # # SELECT people.id, people.name FROM people
150
141
  # # => [[1, 'David'], [2, 'Jeremy'], [3, 'Jose']]
151
142
  #
152
- # Person.pluck('DISTINCT role')
143
+ # Person.distinct.pluck(:role)
153
144
  # # SELECT DISTINCT role FROM people
154
145
  # # => ['admin', 'member', 'guest']
155
146
  #
@@ -161,13 +152,11 @@ module ActiveRecord
161
152
  # # SELECT DATEDIFF(updated_at, created_at) FROM people
162
153
  # # => ['0', '27761', '173']
163
154
  #
155
+ # See also #ids.
156
+ #
164
157
  def pluck(*column_names)
165
- column_names.map! do |column_name|
166
- if column_name.is_a?(Symbol) && attribute_alias?(column_name)
167
- attribute_alias(column_name)
168
- else
169
- column_name.to_s
170
- end
158
+ if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
159
+ return @records.pluck(*column_names)
171
160
  end
172
161
 
173
162
  if has_include?(column_names.first)
@@ -175,10 +164,10 @@ module ActiveRecord
175
164
  else
176
165
  relation = spawn
177
166
  relation.select_values = column_names.map { |cn|
178
- columns_hash.key?(cn) ? arel_table[cn] : cn
167
+ @klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn
179
168
  }
180
- result = klass.connection.select_all(relation.arel, nil, relation.arel.bind_values + bind_values)
181
- result.cast_values(klass.column_types)
169
+ result = klass.connection.select_all(relation.arel, nil, bound_attributes)
170
+ result.cast_values(klass.attribute_types)
182
171
  end
183
172
  end
184
173
 
@@ -193,15 +182,14 @@ module ActiveRecord
193
182
  private
194
183
 
195
184
  def has_include?(column_name)
196
- eager_loading? || (includes_values.present? && ((column_name && column_name != :all) || references_eager_loaded_tables?))
185
+ eager_loading? || (includes_values.present? && column_name && column_name != :all)
197
186
  end
198
187
 
199
- def perform_calculation(operation, column_name, options = {})
200
- # TODO: Remove options argument as soon we remove support to
201
- # activerecord-deprecated_finders.
188
+ def perform_calculation(operation, column_name)
202
189
  operation = operation.to_s.downcase
203
190
 
204
- # If #count is used with #distinct / #uniq it is considered distinct. (eg. relation.distinct.count)
191
+ # If #count is used with #distinct (i.e. `relation.distinct.count`) it is
192
+ # considered distinct.
205
193
  distinct = self.distinct_value
206
194
 
207
195
  if operation == "count"
@@ -223,6 +211,8 @@ module ActiveRecord
223
211
  end
224
212
 
225
213
  def aggregate_column(column_name)
214
+ return column_name if Arel::Expressions === column_name
215
+
226
216
  if @klass.column_names.include?(column_name.to_s)
227
217
  Arel::Attribute.new(@klass.unscoped.table, column_name)
228
218
  else
@@ -235,19 +225,16 @@ module ActiveRecord
235
225
  end
236
226
 
237
227
  def execute_simple_calculation(operation, column_name, distinct) #:nodoc:
238
- # Postgresql doesn't like ORDER BY when there are no GROUP BY
228
+ # PostgreSQL doesn't like ORDER BY when there are no GROUP BY
239
229
  relation = unscope(:order)
240
230
 
241
231
  column_alias = column_name
242
232
 
243
- bind_values = nil
244
-
245
233
  if operation == "count" && (relation.limit_value || relation.offset_value)
246
234
  # Shortcut when limit is zero.
247
235
  return 0 if relation.limit_value == 0
248
236
 
249
237
  query_builder = build_count_subquery(relation, column_name, distinct)
250
- bind_values = query_builder.bind_values + relation.bind_values
251
238
  else
252
239
  column = aggregate_column(column_name)
253
240
 
@@ -258,10 +245,9 @@ module ActiveRecord
258
245
  relation.select_values = [select_value]
259
246
 
260
247
  query_builder = relation.arel
261
- bind_values = query_builder.bind_values + relation.bind_values
262
248
  end
263
249
 
264
- result = @klass.connection.select_all(query_builder, nil, bind_values)
250
+ result = @klass.connection.select_all(query_builder, nil, bound_attributes)
265
251
  row = result.first
266
252
  value = row && row.values.first
267
253
  column = result.column_types.fetch(column_alias) do
@@ -281,15 +267,10 @@ module ActiveRecord
281
267
  else
282
268
  group_fields = group_attrs
283
269
  end
270
+ group_fields = arel_columns(group_fields)
284
271
 
285
- group_aliases = group_fields.map { |field|
286
- column_alias_for(field)
287
- }
288
- group_columns = group_aliases.zip(group_fields).map { |aliaz,field|
289
- [aliaz, field]
290
- }
291
-
292
- group = group_fields
272
+ group_aliases = group_fields.map { |field| column_alias_for(field) }
273
+ group_columns = group_aliases.zip(group_fields)
293
274
 
294
275
  if operation == 'count' && column_name == :all
295
276
  aggregate_alias = 'count_all'
@@ -303,9 +284,9 @@ module ActiveRecord
303
284
  operation,
304
285
  distinct).as(aggregate_alias)
305
286
  ]
306
- select_values += select_values unless having_values.empty?
287
+ select_values += select_values unless having_clause.empty?
307
288
 
308
- select_values.concat group_fields.zip(group_aliases).map { |field,aliaz|
289
+ select_values.concat group_columns.map { |aliaz, field|
309
290
  if field.respond_to?(:as)
310
291
  field.as(aliaz)
311
292
  else
@@ -314,14 +295,14 @@ module ActiveRecord
314
295
  }
315
296
 
316
297
  relation = except(:group)
317
- relation.group_values = group
298
+ relation.group_values = group_fields
318
299
  relation.select_values = select_values
319
300
 
320
- calculated_data = @klass.connection.select_all(relation, nil, relation.arel.bind_values + bind_values)
301
+ calculated_data = @klass.connection.select_all(relation, nil, relation.bound_attributes)
321
302
 
322
303
  if association
323
304
  key_ids = calculated_data.collect { |row| row[group_aliases.first] }
324
- key_records = association.klass.base_class.find(key_ids)
305
+ key_records = association.klass.base_class.where(association.klass.base_class.primary_key => key_ids)
325
306
  key_records = Hash[key_records.map { |r| [r.id, r] }]
326
307
  end
327
308
 
@@ -347,7 +328,6 @@ module ActiveRecord
347
328
  # column_alias_for("sum(id)") # => "sum_id"
348
329
  # column_alias_for("count(distinct users.id)") # => "count_distinct_users_id"
349
330
  # column_alias_for("count(*)") # => "count_all"
350
- # column_alias_for("count", "id") # => "count_id"
351
331
  def column_alias_for(keys)
352
332
  if keys.respond_to? :name
353
333
  keys = "#{keys.relation.name}.#{keys.name}"
@@ -370,15 +350,15 @@ module ActiveRecord
370
350
  def type_cast_calculated_value(value, type, operation = nil)
371
351
  case operation
372
352
  when 'count' then value.to_i
373
- when 'sum' then type.type_cast_from_database(value || 0)
353
+ when 'sum' then type.deserialize(value || 0)
374
354
  when 'average' then value.respond_to?(:to_d) ? value.to_d : value
375
- else type.type_cast_from_database(value)
355
+ else type.deserialize(value)
376
356
  end
377
357
  end
378
358
 
379
- # TODO: refactor to allow non-string `select_values` (eg. Arel nodes).
380
359
  def select_for_count
381
360
  if select_values.present?
361
+ return select_values.first if select_values.one?
382
362
  select_values.join(", ")
383
363
  else
384
364
  :all
@@ -391,11 +371,9 @@ module ActiveRecord
391
371
 
392
372
  aliased_column = aggregate_column(column_name == :all ? 1 : column_name).as(column_alias)
393
373
  relation.select_values = [aliased_column]
394
- arel = relation.arel
395
- subquery = arel.as(subquery_alias)
374
+ subquery = relation.arel.as(subquery_alias)
396
375
 
397
376
  sm = Arel::SelectManager.new relation.engine
398
- sm.bind_values = arel.bind_values
399
377
  select_value = operation_over_aggregate_column(column_alias, 'count', distinct)
400
378
  sm.project(select_value).from(subquery)
401
379
  end
@@ -1,15 +1,13 @@
1
- require 'set'
2
1
  require 'active_support/concern'
3
- require 'active_support/deprecation'
4
2
 
5
3
  module ActiveRecord
6
4
  module Delegation # :nodoc:
7
- module DelegateCache
8
- def relation_delegate_class(klass) # :nodoc:
5
+ module DelegateCache # :nodoc:
6
+ def relation_delegate_class(klass)
9
7
  @relation_delegate_cache[klass]
10
8
  end
11
9
 
12
- def initialize_relation_delegate_cache # :nodoc:
10
+ def initialize_relation_delegate_cache
13
11
  @relation_delegate_cache = cache = {}
14
12
  [
15
13
  ActiveRecord::Relation,
@@ -19,7 +17,7 @@ module ActiveRecord
19
17
  delegate = Class.new(klass) {
20
18
  include ClassSpecificRelation
21
19
  }
22
- const_set klass.name.gsub('::', '_'), delegate
20
+ const_set klass.name.gsub('::'.freeze, '_'.freeze), delegate
23
21
  cache[klass] = delegate
24
22
  end
25
23
  end
@@ -37,13 +35,9 @@ module ActiveRecord
37
35
  # may vary depending on the klass of a relation, so we create a subclass of Relation
38
36
  # for each different klass, and the delegations are compiled into that subclass only.
39
37
 
40
- BLACKLISTED_ARRAY_METHODS = [
41
- :compact!, :flatten!, :reject!, :reverse!, :rotate!, :map!,
42
- :shuffle!, :slice!, :sort!, :sort_by!, :delete_if,
43
- :keep_if, :pop, :shift, :delete_at, :compact, :select!
44
- ].to_set # :nodoc:
45
-
46
- delegate :to_xml, :to_yaml, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join, to: :to_a
38
+ delegate :to_xml, :encode_with, :length, :collect, :map, :each, :all?, :include?, :to_ary, :join,
39
+ :[], :&, :|, :+, :-, :sample, :reverse, :compact, :in_groups, :in_groups_of,
40
+ :shuffle, :split, to: :records
47
41
 
48
42
  delegate :table_name, :quoted_table_name, :primary_key, :quoted_primary_key,
49
43
  :connection, :columns_hash, :to => :klass
@@ -115,21 +109,14 @@ module ActiveRecord
115
109
 
116
110
  def respond_to?(method, include_private = false)
117
111
  super || @klass.respond_to?(method, include_private) ||
118
- array_delegable?(method) ||
119
112
  arel.respond_to?(method, include_private)
120
113
  end
121
114
 
122
115
  protected
123
116
 
124
- def array_delegable?(method)
125
- Array.method_defined?(method) && BLACKLISTED_ARRAY_METHODS.exclude?(method)
126
- end
127
-
128
117
  def method_missing(method, *args, &block)
129
118
  if @klass.respond_to?(method)
130
119
  scoping { @klass.public_send(method, *args, &block) }
131
- elsif array_delegable?(method)
132
- to_a.public_send(method, *args, &block)
133
120
  elsif arel.respond_to?(method)
134
121
  arel.public_send(method, *args, &block)
135
122
  else