activerecord 5.2.6 → 6.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 (268) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +609 -622
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +4 -2
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +4 -2
  7. data/lib/active_record/associations/association.rb +52 -19
  8. data/lib/active_record/associations/association_scope.rb +4 -6
  9. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  11. data/lib/active_record/associations/builder/association.rb +14 -18
  12. data/lib/active_record/associations/builder/belongs_to.rb +19 -52
  13. data/lib/active_record/associations/builder/collection_association.rb +3 -13
  14. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
  15. data/lib/active_record/associations/builder/has_many.rb +2 -0
  16. data/lib/active_record/associations/builder/has_one.rb +35 -1
  17. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  18. data/lib/active_record/associations/collection_association.rb +6 -21
  19. data/lib/active_record/associations/collection_proxy.rb +12 -15
  20. data/lib/active_record/associations/foreign_association.rb +7 -0
  21. data/lib/active_record/associations/has_many_association.rb +2 -10
  22. data/lib/active_record/associations/has_many_through_association.rb +14 -14
  23. data/lib/active_record/associations/has_one_association.rb +28 -30
  24. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  25. data/lib/active_record/associations/join_dependency/join_association.rb +9 -10
  26. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  27. data/lib/active_record/associations/join_dependency.rb +24 -28
  28. data/lib/active_record/associations/preloader/association.rb +38 -36
  29. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  30. data/lib/active_record/associations/preloader.rb +40 -32
  31. data/lib/active_record/associations/singular_association.rb +2 -16
  32. data/lib/active_record/associations.rb +19 -14
  33. data/lib/active_record/attribute_assignment.rb +7 -10
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
  35. data/lib/active_record/attribute_methods/dirty.rb +111 -40
  36. data/lib/active_record/attribute_methods/primary_key.rb +15 -22
  37. data/lib/active_record/attribute_methods/query.rb +2 -3
  38. data/lib/active_record/attribute_methods/read.rb +15 -53
  39. data/lib/active_record/attribute_methods/serialization.rb +1 -1
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
  41. data/lib/active_record/attribute_methods/write.rb +17 -24
  42. data/lib/active_record/attribute_methods.rb +28 -100
  43. data/lib/active_record/attributes.rb +13 -0
  44. data/lib/active_record/autosave_association.rb +5 -9
  45. data/lib/active_record/base.rb +2 -3
  46. data/lib/active_record/callbacks.rb +5 -19
  47. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +94 -16
  48. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
  49. data/lib/active_record/connection_adapters/abstract/database_statements.rb +95 -123
  50. data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -8
  51. data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
  52. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
  53. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
  54. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
  55. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +132 -53
  56. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
  57. data/lib/active_record/connection_adapters/abstract_adapter.rb +180 -47
  58. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +128 -194
  59. data/lib/active_record/connection_adapters/column.rb +17 -13
  60. data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
  61. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
  62. data/lib/active_record/connection_adapters/mysql/database_statements.rb +73 -13
  63. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  64. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
  65. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  66. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  67. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
  68. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  69. data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -9
  70. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
  71. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -1
  72. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  73. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  74. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
  75. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
  76. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  77. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
  78. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  79. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  80. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
  81. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
  82. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -1
  83. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  84. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
  85. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  86. data/lib/active_record/connection_adapters/postgresql_adapter.rb +160 -74
  87. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  88. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  89. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  90. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -6
  91. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
  92. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +125 -141
  93. data/lib/active_record/connection_handling.rb +149 -27
  94. data/lib/active_record/core.rb +100 -60
  95. data/lib/active_record/counter_cache.rb +4 -29
  96. data/lib/active_record/database_configurations/database_config.rb +37 -0
  97. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  98. data/lib/active_record/database_configurations/url_config.rb +79 -0
  99. data/lib/active_record/database_configurations.rb +233 -0
  100. data/lib/active_record/dynamic_matchers.rb +1 -1
  101. data/lib/active_record/enum.rb +37 -7
  102. data/lib/active_record/errors.rb +15 -7
  103. data/lib/active_record/explain.rb +1 -1
  104. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  105. data/lib/active_record/fixture_set/render_context.rb +17 -0
  106. data/lib/active_record/fixture_set/table_row.rb +153 -0
  107. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  108. data/lib/active_record/fixtures.rb +145 -472
  109. data/lib/active_record/gem_version.rb +3 -3
  110. data/lib/active_record/inheritance.rb +13 -3
  111. data/lib/active_record/insert_all.rb +179 -0
  112. data/lib/active_record/integration.rb +68 -16
  113. data/lib/active_record/internal_metadata.rb +10 -2
  114. data/lib/active_record/locking/optimistic.rb +5 -6
  115. data/lib/active_record/locking/pessimistic.rb +3 -3
  116. data/lib/active_record/log_subscriber.rb +7 -26
  117. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  118. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  119. data/lib/active_record/middleware/database_selector.rb +75 -0
  120. data/lib/active_record/migration/command_recorder.rb +50 -6
  121. data/lib/active_record/migration/compatibility.rb +76 -49
  122. data/lib/active_record/migration.rb +100 -81
  123. data/lib/active_record/model_schema.rb +30 -9
  124. data/lib/active_record/nested_attributes.rb +2 -2
  125. data/lib/active_record/no_touching.rb +7 -0
  126. data/lib/active_record/persistence.rb +228 -24
  127. data/lib/active_record/query_cache.rb +11 -4
  128. data/lib/active_record/querying.rb +32 -20
  129. data/lib/active_record/railtie.rb +80 -43
  130. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  131. data/lib/active_record/railties/controller_runtime.rb +30 -35
  132. data/lib/active_record/railties/databases.rake +196 -46
  133. data/lib/active_record/reflection.rb +32 -30
  134. data/lib/active_record/relation/batches.rb +13 -10
  135. data/lib/active_record/relation/calculations.rb +53 -47
  136. data/lib/active_record/relation/delegation.rb +26 -43
  137. data/lib/active_record/relation/finder_methods.rb +13 -26
  138. data/lib/active_record/relation/merger.rb +11 -20
  139. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  140. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  141. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  142. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  143. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  144. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  145. data/lib/active_record/relation/predicate_builder.rb +4 -6
  146. data/lib/active_record/relation/query_attribute.rb +13 -8
  147. data/lib/active_record/relation/query_methods.rb +189 -63
  148. data/lib/active_record/relation/spawn_methods.rb +1 -1
  149. data/lib/active_record/relation/where_clause.rb +14 -10
  150. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  151. data/lib/active_record/relation.rb +310 -80
  152. data/lib/active_record/result.rb +30 -11
  153. data/lib/active_record/sanitization.rb +32 -40
  154. data/lib/active_record/schema.rb +2 -11
  155. data/lib/active_record/schema_dumper.rb +22 -7
  156. data/lib/active_record/schema_migration.rb +5 -1
  157. data/lib/active_record/scoping/default.rb +4 -5
  158. data/lib/active_record/scoping/named.rb +19 -15
  159. data/lib/active_record/scoping.rb +8 -8
  160. data/lib/active_record/statement_cache.rb +30 -3
  161. data/lib/active_record/store.rb +87 -8
  162. data/lib/active_record/table_metadata.rb +10 -17
  163. data/lib/active_record/tasks/database_tasks.rb +194 -25
  164. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
  165. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
  166. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
  167. data/lib/active_record/test_databases.rb +23 -0
  168. data/lib/active_record/test_fixtures.rb +224 -0
  169. data/lib/active_record/timestamp.rb +39 -25
  170. data/lib/active_record/touch_later.rb +4 -2
  171. data/lib/active_record/transactions.rb +57 -66
  172. data/lib/active_record/translation.rb +1 -1
  173. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  174. data/lib/active_record/type.rb +3 -4
  175. data/lib/active_record/type_caster/connection.rb +15 -14
  176. data/lib/active_record/type_caster/map.rb +1 -4
  177. data/lib/active_record/validations/uniqueness.rb +15 -27
  178. data/lib/active_record/validations.rb +1 -0
  179. data/lib/active_record.rb +9 -2
  180. data/lib/arel/alias_predication.rb +9 -0
  181. data/lib/arel/attributes/attribute.rb +37 -0
  182. data/lib/arel/attributes.rb +22 -0
  183. data/lib/arel/collectors/bind.rb +24 -0
  184. data/lib/arel/collectors/composite.rb +31 -0
  185. data/lib/arel/collectors/plain_string.rb +20 -0
  186. data/lib/arel/collectors/sql_string.rb +20 -0
  187. data/lib/arel/collectors/substitute_binds.rb +28 -0
  188. data/lib/arel/crud.rb +42 -0
  189. data/lib/arel/delete_manager.rb +18 -0
  190. data/lib/arel/errors.rb +9 -0
  191. data/lib/arel/expressions.rb +29 -0
  192. data/lib/arel/factory_methods.rb +49 -0
  193. data/lib/arel/insert_manager.rb +49 -0
  194. data/lib/arel/math.rb +45 -0
  195. data/lib/arel/nodes/and.rb +32 -0
  196. data/lib/arel/nodes/ascending.rb +23 -0
  197. data/lib/arel/nodes/binary.rb +52 -0
  198. data/lib/arel/nodes/bind_param.rb +36 -0
  199. data/lib/arel/nodes/case.rb +55 -0
  200. data/lib/arel/nodes/casted.rb +50 -0
  201. data/lib/arel/nodes/comment.rb +29 -0
  202. data/lib/arel/nodes/count.rb +12 -0
  203. data/lib/arel/nodes/delete_statement.rb +45 -0
  204. data/lib/arel/nodes/descending.rb +23 -0
  205. data/lib/arel/nodes/equality.rb +18 -0
  206. data/lib/arel/nodes/extract.rb +24 -0
  207. data/lib/arel/nodes/false.rb +16 -0
  208. data/lib/arel/nodes/full_outer_join.rb +8 -0
  209. data/lib/arel/nodes/function.rb +44 -0
  210. data/lib/arel/nodes/grouping.rb +8 -0
  211. data/lib/arel/nodes/in.rb +8 -0
  212. data/lib/arel/nodes/infix_operation.rb +80 -0
  213. data/lib/arel/nodes/inner_join.rb +8 -0
  214. data/lib/arel/nodes/insert_statement.rb +37 -0
  215. data/lib/arel/nodes/join_source.rb +20 -0
  216. data/lib/arel/nodes/matches.rb +18 -0
  217. data/lib/arel/nodes/named_function.rb +23 -0
  218. data/lib/arel/nodes/node.rb +50 -0
  219. data/lib/arel/nodes/node_expression.rb +13 -0
  220. data/lib/arel/nodes/outer_join.rb +8 -0
  221. data/lib/arel/nodes/over.rb +15 -0
  222. data/lib/arel/nodes/regexp.rb +16 -0
  223. data/lib/arel/nodes/right_outer_join.rb +8 -0
  224. data/lib/arel/nodes/select_core.rb +67 -0
  225. data/lib/arel/nodes/select_statement.rb +41 -0
  226. data/lib/arel/nodes/sql_literal.rb +16 -0
  227. data/lib/arel/nodes/string_join.rb +11 -0
  228. data/lib/arel/nodes/table_alias.rb +27 -0
  229. data/lib/arel/nodes/terminal.rb +16 -0
  230. data/lib/arel/nodes/true.rb +16 -0
  231. data/lib/arel/nodes/unary.rb +45 -0
  232. data/lib/arel/nodes/unary_operation.rb +20 -0
  233. data/lib/arel/nodes/unqualified_column.rb +22 -0
  234. data/lib/arel/nodes/update_statement.rb +41 -0
  235. data/lib/arel/nodes/values_list.rb +9 -0
  236. data/lib/arel/nodes/window.rb +126 -0
  237. data/lib/arel/nodes/with.rb +11 -0
  238. data/lib/arel/nodes.rb +68 -0
  239. data/lib/arel/order_predications.rb +13 -0
  240. data/lib/arel/predications.rb +257 -0
  241. data/lib/arel/select_manager.rb +271 -0
  242. data/lib/arel/table.rb +110 -0
  243. data/lib/arel/tree_manager.rb +72 -0
  244. data/lib/arel/update_manager.rb +34 -0
  245. data/lib/arel/visitors/depth_first.rb +204 -0
  246. data/lib/arel/visitors/dot.rb +297 -0
  247. data/lib/arel/visitors/ibm_db.rb +34 -0
  248. data/lib/arel/visitors/informix.rb +62 -0
  249. data/lib/arel/visitors/mssql.rb +157 -0
  250. data/lib/arel/visitors/mysql.rb +83 -0
  251. data/lib/arel/visitors/oracle.rb +159 -0
  252. data/lib/arel/visitors/oracle12.rb +66 -0
  253. data/lib/arel/visitors/postgresql.rb +110 -0
  254. data/lib/arel/visitors/sqlite.rb +39 -0
  255. data/lib/arel/visitors/to_sql.rb +889 -0
  256. data/lib/arel/visitors/visitor.rb +46 -0
  257. data/lib/arel/visitors/where_sql.rb +23 -0
  258. data/lib/arel/visitors.rb +20 -0
  259. data/lib/arel/window_predications.rb +9 -0
  260. data/lib/arel.rb +51 -0
  261. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  262. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  263. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  264. data/lib/rails/generators/active_record/migration.rb +14 -1
  265. data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
  266. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  267. metadata +108 -26
  268. data/lib/active_record/collection_cache_key.rb +0 -53
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_record/insert_all"
4
+
3
5
  module ActiveRecord
4
6
  # = Active Record \Persistence
5
7
  module Persistence
@@ -55,6 +57,192 @@ module ActiveRecord
55
57
  end
56
58
  end
57
59
 
60
+ # Inserts a single record into the database in a single SQL INSERT
61
+ # statement. It does not instantiate any models nor does it trigger
62
+ # Active Record callbacks or validations. Though passed values
63
+ # go through Active Record's type casting and serialization.
64
+ #
65
+ # See <tt>ActiveRecord::Persistence#insert_all</tt> for documentation.
66
+ def insert(attributes, returning: nil, unique_by: nil)
67
+ insert_all([ attributes ], returning: returning, unique_by: unique_by)
68
+ end
69
+
70
+ # Inserts multiple records into the database in a single SQL INSERT
71
+ # statement. It does not instantiate any models nor does it trigger
72
+ # Active Record callbacks or validations. Though passed values
73
+ # go through Active Record's type casting and serialization.
74
+ #
75
+ # The +attributes+ parameter is an Array of Hashes. Every Hash determines
76
+ # the attributes for a single row and must have the same keys.
77
+ #
78
+ # Rows are considered to be unique by every unique index on the table. Any
79
+ # duplicate rows are skipped.
80
+ # Override with <tt>:unique_by</tt> (see below).
81
+ #
82
+ # Returns an <tt>ActiveRecord::Result</tt> with its contents based on
83
+ # <tt>:returning</tt> (see below).
84
+ #
85
+ # ==== Options
86
+ #
87
+ # [:returning]
88
+ # (PostgreSQL only) An array of attributes to return for all successfully
89
+ # inserted records, which by default is the primary key.
90
+ # Pass <tt>returning: %w[ id name ]</tt> for both id and name
91
+ # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
92
+ # clause entirely.
93
+ #
94
+ # [:unique_by]
95
+ # (PostgreSQL and SQLite only) By default rows are considered to be unique
96
+ # by every unique index on the table. Any duplicate rows are skipped.
97
+ #
98
+ # To skip rows according to just one unique index pass <tt>:unique_by</tt>.
99
+ #
100
+ # Consider a Book model where no duplicate ISBNs make sense, but if any
101
+ # row has an existing id, or is not unique by another unique index,
102
+ # <tt>ActiveRecord::RecordNotUnique</tt> is raised.
103
+ #
104
+ # Unique indexes can be identified by columns or name:
105
+ #
106
+ # unique_by: :isbn
107
+ # unique_by: %i[ author_id name ]
108
+ # unique_by: :index_books_on_isbn
109
+ #
110
+ # Because it relies on the index information from the database
111
+ # <tt>:unique_by</tt> is recommended to be paired with
112
+ # Active Record's schema_cache.
113
+ #
114
+ # ==== Example
115
+ #
116
+ # # Insert records and skip inserting any duplicates.
117
+ # # Here "Eloquent Ruby" is skipped because its id is not unique.
118
+ #
119
+ # Book.insert_all([
120
+ # { id: 1, title: "Rework", author: "David" },
121
+ # { id: 1, title: "Eloquent Ruby", author: "Russ" }
122
+ # ])
123
+ def insert_all(attributes, returning: nil, unique_by: nil)
124
+ InsertAll.new(self, attributes, on_duplicate: :skip, returning: returning, unique_by: unique_by).execute
125
+ end
126
+
127
+ # Inserts a single record into the database in a single SQL INSERT
128
+ # statement. It does not instantiate any models nor does it trigger
129
+ # Active Record callbacks or validations. Though passed values
130
+ # go through Active Record's type casting and serialization.
131
+ #
132
+ # See <tt>ActiveRecord::Persistence#insert_all!</tt> for more.
133
+ def insert!(attributes, returning: nil)
134
+ insert_all!([ attributes ], returning: returning)
135
+ end
136
+
137
+ # Inserts multiple records into the database in a single SQL INSERT
138
+ # statement. It does not instantiate any models nor does it trigger
139
+ # Active Record callbacks or validations. Though passed values
140
+ # go through Active Record's type casting and serialization.
141
+ #
142
+ # The +attributes+ parameter is an Array of Hashes. Every Hash determines
143
+ # the attributes for a single row and must have the same keys.
144
+ #
145
+ # Raises <tt>ActiveRecord::RecordNotUnique</tt> if any rows violate a
146
+ # unique index on the table. In that case, no rows are inserted.
147
+ #
148
+ # To skip duplicate rows, see <tt>ActiveRecord::Persistence#insert_all</tt>.
149
+ # To replace them, see <tt>ActiveRecord::Persistence#upsert_all</tt>.
150
+ #
151
+ # Returns an <tt>ActiveRecord::Result</tt> with its contents based on
152
+ # <tt>:returning</tt> (see below).
153
+ #
154
+ # ==== Options
155
+ #
156
+ # [:returning]
157
+ # (PostgreSQL only) An array of attributes to return for all successfully
158
+ # inserted records, which by default is the primary key.
159
+ # Pass <tt>returning: %w[ id name ]</tt> for both id and name
160
+ # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
161
+ # clause entirely.
162
+ #
163
+ # ==== Examples
164
+ #
165
+ # # Insert multiple records
166
+ # Book.insert_all!([
167
+ # { title: "Rework", author: "David" },
168
+ # { title: "Eloquent Ruby", author: "Russ" }
169
+ # ])
170
+ #
171
+ # # Raises ActiveRecord::RecordNotUnique because "Eloquent Ruby"
172
+ # # does not have a unique id.
173
+ # Book.insert_all!([
174
+ # { id: 1, title: "Rework", author: "David" },
175
+ # { id: 1, title: "Eloquent Ruby", author: "Russ" }
176
+ # ])
177
+ def insert_all!(attributes, returning: nil)
178
+ InsertAll.new(self, attributes, on_duplicate: :raise, returning: returning).execute
179
+ end
180
+
181
+ # Updates or inserts (upserts) a single record into the database in a
182
+ # single SQL INSERT statement. It does not instantiate any models nor does
183
+ # it trigger Active Record callbacks or validations. Though passed values
184
+ # go through Active Record's type casting and serialization.
185
+ #
186
+ # See <tt>ActiveRecord::Persistence#upsert_all</tt> for documentation.
187
+ def upsert(attributes, returning: nil, unique_by: nil)
188
+ upsert_all([ attributes ], returning: returning, unique_by: unique_by)
189
+ end
190
+
191
+ # Updates or inserts (upserts) multiple records into the database in a
192
+ # single SQL INSERT statement. It does not instantiate any models nor does
193
+ # it trigger Active Record callbacks or validations. Though passed values
194
+ # go through Active Record's type casting and serialization.
195
+ #
196
+ # The +attributes+ parameter is an Array of Hashes. Every Hash determines
197
+ # the attributes for a single row and must have the same keys.
198
+ #
199
+ # Returns an <tt>ActiveRecord::Result</tt> with its contents based on
200
+ # <tt>:returning</tt> (see below).
201
+ #
202
+ # ==== Options
203
+ #
204
+ # [:returning]
205
+ # (PostgreSQL only) An array of attributes to return for all successfully
206
+ # inserted records, which by default is the primary key.
207
+ # Pass <tt>returning: %w[ id name ]</tt> for both id and name
208
+ # or <tt>returning: false</tt> to omit the underlying <tt>RETURNING</tt> SQL
209
+ # clause entirely.
210
+ #
211
+ # [:unique_by]
212
+ # (PostgreSQL and SQLite only) By default rows are considered to be unique
213
+ # by every unique index on the table. Any duplicate rows are skipped.
214
+ #
215
+ # To skip rows according to just one unique index pass <tt>:unique_by</tt>.
216
+ #
217
+ # Consider a Book model where no duplicate ISBNs make sense, but if any
218
+ # row has an existing id, or is not unique by another unique index,
219
+ # <tt>ActiveRecord::RecordNotUnique</tt> is raised.
220
+ #
221
+ # Unique indexes can be identified by columns or name:
222
+ #
223
+ # unique_by: :isbn
224
+ # unique_by: %i[ author_id name ]
225
+ # unique_by: :index_books_on_isbn
226
+ #
227
+ # Because it relies on the index information from the database
228
+ # <tt>:unique_by</tt> is recommended to be paired with
229
+ # Active Record's schema_cache.
230
+ #
231
+ # ==== Examples
232
+ #
233
+ # # Inserts multiple records, performing an upsert when records have duplicate ISBNs.
234
+ # # Here "Eloquent Ruby" overwrites "Rework" because its ISBN is duplicate.
235
+ #
236
+ # Book.upsert_all([
237
+ # { title: "Rework", author: "David", isbn: "1" },
238
+ # { title: "Eloquent Ruby", author: "Russ", isbn: "1" }
239
+ # ], unique_by: :isbn)
240
+ #
241
+ # Book.find_by(isbn: "1").title # => "Eloquent Ruby"
242
+ def upsert_all(attributes, returning: nil, unique_by: nil)
243
+ InsertAll.new(self, attributes, on_duplicate: :update, returning: returning, unique_by: unique_by).execute
244
+ end
245
+
58
246
  # Given an attributes hash, +instantiate+ returns a new instance of
59
247
  # the appropriate class. Accepts only keys as strings.
60
248
  #
@@ -67,8 +255,7 @@ module ActiveRecord
67
255
  # how this "single-table" inheritance mapping is implemented.
68
256
  def instantiate(attributes, column_types = {}, &block)
69
257
  klass = discriminate_class_for_record(attributes)
70
- attributes = klass.attributes_builder.build_from_database(attributes, column_types)
71
- klass.allocate.init_with("attributes" => attributes, "new_record" => false, &block)
258
+ instantiate_instance_of(klass, attributes, column_types, &block)
72
259
  end
73
260
 
74
261
  # Updates an object (or multiple objects) and saves it to the database, if validations pass.
@@ -143,7 +330,7 @@ module ActiveRecord
143
330
  end
144
331
  end
145
332
 
146
- # Deletes the row with a primary key matching the +id+ argument, using a
333
+ # Deletes the row with a primary key matching the +id+ argument, using an
147
334
  # SQL +DELETE+ statement, and returns the number of rows deleted. Active
148
335
  # Record objects are not instantiated, so the object's callbacks are not
149
336
  # executed, including any <tt>:dependent</tt> association options.
@@ -162,10 +349,11 @@ module ActiveRecord
162
349
  # # Delete multiple rows
163
350
  # Todo.delete([2,3,4])
164
351
  def delete(id_or_array)
165
- where(primary_key => id_or_array).delete_all
352
+ delete_by(primary_key => id_or_array)
166
353
  end
167
354
 
168
355
  def _insert_record(values) # :nodoc:
356
+ primary_key = self.primary_key
169
357
  primary_key_value = nil
170
358
 
171
359
  if primary_key && Hash === values
@@ -178,7 +366,7 @@ module ActiveRecord
178
366
  end
179
367
 
180
368
  if values.empty?
181
- im = arel_table.compile_insert(connection.empty_insert_statement_value)
369
+ im = arel_table.compile_insert(connection.empty_insert_statement_value(primary_key))
182
370
  im.into arel_table
183
371
  else
184
372
  im = arel_table.compile_insert(_substitute_values(values))
@@ -208,6 +396,13 @@ module ActiveRecord
208
396
  end
209
397
 
210
398
  private
399
+ # Given a class, an attributes hash, +instantiate_instance_of+ returns a
400
+ # new instance of the class. Accepts only keys as strings.
401
+ def instantiate_instance_of(klass, attributes, column_types = {}, &block)
402
+ attributes = klass.attributes_builder.build_from_database(attributes, column_types)
403
+ klass.allocate.init_with_attributes(attributes, &block)
404
+ end
405
+
211
406
  # Called by +instantiate+ to decide which class to use for a new
212
407
  # record instance.
213
408
  #
@@ -229,20 +424,20 @@ module ActiveRecord
229
424
  # Returns true if this object hasn't been saved yet -- that is, a record
230
425
  # for the object doesn't exist in the database yet; otherwise, returns false.
231
426
  def new_record?
232
- sync_with_transaction_state
427
+ sync_with_transaction_state if @transaction_state&.finalized?
233
428
  @new_record
234
429
  end
235
430
 
236
431
  # Returns true if this object has been destroyed, otherwise returns false.
237
432
  def destroyed?
238
- sync_with_transaction_state
433
+ sync_with_transaction_state if @transaction_state&.finalized?
239
434
  @destroyed
240
435
  end
241
436
 
242
437
  # Returns true if the record is persisted, i.e. it's not a new record and it was
243
438
  # not destroyed, otherwise returns false.
244
439
  def persisted?
245
- sync_with_transaction_state
440
+ sync_with_transaction_state if @transaction_state&.finalized?
246
441
  !(@new_record || @destroyed)
247
442
  end
248
443
 
@@ -336,7 +531,6 @@ module ActiveRecord
336
531
  def destroy
337
532
  _raise_readonly_record_error if readonly?
338
533
  destroy_associations
339
- self.class.connection.add_transaction_record(self)
340
534
  @_trigger_destroy_callback = if persisted?
341
535
  destroy_row > 0
342
536
  else
@@ -374,7 +568,6 @@ module ActiveRecord
374
568
  became.send(:initialize)
375
569
  became.instance_variable_set("@attributes", @attributes)
376
570
  became.instance_variable_set("@mutations_from_database", @mutations_from_database ||= nil)
377
- became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
378
571
  became.instance_variable_set("@new_record", new_record?)
379
572
  became.instance_variable_set("@destroyed", destroyed?)
380
573
  became.errors.copy!(errors)
@@ -430,6 +623,7 @@ module ActiveRecord
430
623
  end
431
624
 
432
625
  alias update_attributes update
626
+ deprecate update_attributes: "please, use update instead"
433
627
 
434
628
  # Updates its receiver just like #update but calls #save! instead
435
629
  # of +save+, so an exception is raised if the record is invalid and saving will fail.
@@ -443,6 +637,7 @@ module ActiveRecord
443
637
  end
444
638
 
445
639
  alias update_attributes! update!
640
+ deprecate update_attributes!: "please, use update! instead"
446
641
 
447
642
  # Equivalent to <code>update_columns(name => value)</code>.
448
643
  def update_column(name, value)
@@ -469,8 +664,13 @@ module ActiveRecord
469
664
  raise ActiveRecordError, "cannot update a new record" if new_record?
470
665
  raise ActiveRecordError, "cannot update a destroyed record" if destroyed?
471
666
 
667
+ attributes = attributes.transform_keys do |key|
668
+ name = key.to_s
669
+ self.class.attribute_aliases[name] || name
670
+ end
671
+
472
672
  attributes.each_key do |key|
473
- verify_readonly_attribute(key.to_s)
673
+ verify_readonly_attribute(key)
474
674
  end
475
675
 
476
676
  id_in_database = self.id_in_database
@@ -480,7 +680,7 @@ module ActiveRecord
480
680
 
481
681
  affected_rows = self.class._update_record(
482
682
  attributes,
483
- self.class.primary_key => id_in_database
683
+ @primary_key => id_in_database
484
684
  )
485
685
 
486
686
  affected_rows == 1
@@ -657,7 +857,9 @@ module ActiveRecord
657
857
  end
658
858
 
659
859
  attribute_names = timestamp_attributes_for_update_in_model
660
- attribute_names |= names.map(&:to_s)
860
+ attribute_names |= names.map!(&:to_s).map! { |name|
861
+ self.class.attribute_aliases[name] || name
862
+ }
661
863
 
662
864
  unless attribute_names.empty?
663
865
  affected_rows = _touch_row(attribute_names, time)
@@ -678,15 +880,14 @@ module ActiveRecord
678
880
  end
679
881
 
680
882
  def _delete_row
681
- self.class._delete_record(self.class.primary_key => id_in_database)
883
+ self.class._delete_record(@primary_key => id_in_database)
682
884
  end
683
885
 
684
886
  def _touch_row(attribute_names, time)
685
887
  time ||= current_time_from_proper_timezone
686
888
 
687
889
  attribute_names.each do |attr_name|
688
- write_attribute(attr_name, time)
689
- clear_attribute_change(attr_name)
890
+ _write_attribute(attr_name, time)
690
891
  end
691
892
 
692
893
  _update_row(attribute_names, "touch")
@@ -695,21 +896,20 @@ module ActiveRecord
695
896
  def _update_row(attribute_names, attempted_action = "update")
696
897
  self.class._update_record(
697
898
  attributes_with_values(attribute_names),
698
- self.class.primary_key => id_in_database
899
+ @primary_key => id_in_database
699
900
  )
700
901
  end
701
902
 
702
- def create_or_update(*args, &block)
903
+ def create_or_update(**, &block)
703
904
  _raise_readonly_record_error if readonly?
704
905
  return false if destroyed?
705
- result = new_record? ? _create_record(&block) : _update_record(*args, &block)
906
+ result = new_record? ? _create_record(&block) : _update_record(&block)
706
907
  result != false
707
908
  end
708
909
 
709
910
  # Updates the associated record with values matching those of the instance attributes.
710
911
  # Returns the number of affected rows.
711
912
  def _update_record(attribute_names = self.attribute_names)
712
- attribute_names &= self.class.column_names
713
913
  attribute_names = attributes_for_update(attribute_names)
714
914
 
715
915
  if attribute_names.empty?
@@ -728,11 +928,13 @@ module ActiveRecord
728
928
  # Creates a record with values matching those of the instance attributes
729
929
  # and returns its id.
730
930
  def _create_record(attribute_names = self.attribute_names)
731
- attribute_names &= self.class.column_names
732
- attributes_values = attributes_with_values_for_create(attribute_names)
931
+ attribute_names = attributes_for_create(attribute_names)
932
+
933
+ new_id = self.class._insert_record(
934
+ attributes_with_values(attribute_names)
935
+ )
733
936
 
734
- new_id = self.class._insert_record(attributes_values)
735
- self.id ||= new_id if self.class.primary_key
937
+ self.id ||= new_id if @primary_key
736
938
 
737
939
  @new_record = false
738
940
 
@@ -752,6 +954,8 @@ module ActiveRecord
752
954
  @_association_destroy_exception = nil
753
955
  end
754
956
 
957
+ # The name of the method used to touch a +belongs_to+ association when the
958
+ # +:touch+ option is used.
755
959
  def belongs_to_touch_method
756
960
  :touch
757
961
  end
@@ -26,15 +26,22 @@ module ActiveRecord
26
26
  end
27
27
 
28
28
  def self.run
29
- ActiveRecord::Base.connection_handler.connection_pool_list.
30
- reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! }
29
+ pools = []
30
+
31
+ ActiveRecord::Base.connection_handlers.each do |key, handler|
32
+ pools << handler.connection_pool_list.reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! }
33
+ end
34
+
35
+ pools.flatten
31
36
  end
32
37
 
33
38
  def self.complete(pools)
34
39
  pools.each { |pool| pool.disable_query_cache! }
35
40
 
36
- ActiveRecord::Base.connection_handler.connection_pool_list.each do |pool|
37
- pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
41
+ ActiveRecord::Base.connection_handlers.each do |_, handler|
42
+ handler.connection_pool_list.each do |pool|
43
+ pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
44
+ end
38
45
  end
39
46
  end
40
47
 
@@ -2,31 +2,36 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Querying
5
- delegate :find, :take, :take!, :first, :first!, :last, :last!, :exists?, :any?, :many?, :none?, :one?, to: :all
6
- delegate :second, :second!, :third, :third!, :fourth, :fourth!, :fifth, :fifth!, :forty_two, :forty_two!, :third_to_last, :third_to_last!, :second_to_last, :second_to_last!, to: :all
7
- delegate :first_or_create, :first_or_create!, :first_or_initialize, to: :all
8
- delegate :find_or_create_by, :find_or_create_by!, :find_or_initialize_by, to: :all
9
- delegate :find_by, :find_by!, to: :all
10
- delegate :destroy_all, :delete_all, :update_all, to: :all
11
- delegate :find_each, :find_in_batches, :in_batches, to: :all
12
- delegate :select, :group, :order, :except, :reorder, :limit, :offset, :joins, :left_joins, :left_outer_joins, :or,
13
- :where, :rewhere, :preload, :eager_load, :includes, :from, :lock, :readonly, :extending,
14
- :having, :create_with, :distinct, :references, :none, :unscope, :merge, to: :all
15
- delegate :count, :average, :minimum, :maximum, :sum, :calculate, to: :all
16
- delegate :pluck, :ids, to: :all
5
+ QUERYING_METHODS = [
6
+ :find, :find_by, :find_by!, :take, :take!, :first, :first!, :last, :last!,
7
+ :second, :second!, :third, :third!, :fourth, :fourth!, :fifth, :fifth!,
8
+ :forty_two, :forty_two!, :third_to_last, :third_to_last!, :second_to_last, :second_to_last!,
9
+ :exists?, :any?, :many?, :none?, :one?,
10
+ :first_or_create, :first_or_create!, :first_or_initialize,
11
+ :find_or_create_by, :find_or_create_by!, :find_or_initialize_by,
12
+ :create_or_find_by, :create_or_find_by!,
13
+ :destroy_all, :delete_all, :update_all, :touch_all, :destroy_by, :delete_by,
14
+ :find_each, :find_in_batches, :in_batches,
15
+ :select, :reselect, :order, :reorder, :group, :limit, :offset, :joins, :left_joins, :left_outer_joins,
16
+ :where, :rewhere, :preload, :extract_associated, :eager_load, :includes, :from, :lock, :readonly, :extending, :or,
17
+ :having, :create_with, :distinct, :references, :none, :unscope, :optimizer_hints, :merge, :except, :only,
18
+ :count, :average, :minimum, :maximum, :sum, :calculate, :annotate,
19
+ :pluck, :pick, :ids
20
+ ].freeze # :nodoc:
21
+ delegate(*QUERYING_METHODS, to: :all)
17
22
 
18
23
  # Executes a custom SQL query against your database and returns all the results. The results will
19
- # be returned as an array with columns requested encapsulated as attributes of the model you call
20
- # this method from. If you call <tt>Product.find_by_sql</tt> then the results will be returned in
24
+ # be returned as an array, with the requested columns encapsulated as attributes of the model you call
25
+ # this method from. For example, if you call <tt>Product.find_by_sql</tt>, then the results will be returned in
21
26
  # a +Product+ object with the attributes you specified in the SQL query.
22
27
  #
23
- # If you call a complicated SQL query which spans multiple tables the columns specified by the
28
+ # If you call a complicated SQL query which spans multiple tables, the columns specified by the
24
29
  # SELECT will be attributes of the model, whether or not they are columns of the corresponding
25
30
  # table.
26
31
  #
27
- # The +sql+ parameter is a full SQL query as a string. It will be called as is, there will be
28
- # no database agnostic conversions performed. This should be a last resort because using, for example,
29
- # MySQL specific terms will lock you to using that particular database engine or require you to
32
+ # The +sql+ parameter is a full SQL query as a string. It will be called as is; there will be
33
+ # no database agnostic conversions performed. This should be a last resort because using
34
+ # database-specific terms will lock you into using that particular database engine, or require you to
30
35
  # change your call if you switch engines.
31
36
  #
32
37
  # # A simple SQL query spanning multiple tables
@@ -49,13 +54,20 @@ module ActiveRecord
49
54
  }
50
55
 
51
56
  message_bus.instrument("instantiation.active_record", payload) do
52
- result_set.map { |record| instantiate(record, column_types, &block) }
57
+ if result_set.includes_column?(inheritance_column)
58
+ result_set.map { |record| instantiate(record, column_types, &block) }
59
+ else
60
+ # Instantiate a homogeneous set
61
+ result_set.map { |record| instantiate_instance_of(self, record, column_types, &block) }
62
+ end
53
63
  end
54
64
  end
55
65
 
56
66
  # Returns the result of an SQL statement that should only include a COUNT(*) in the SELECT part.
57
67
  # The use of this method should be restricted to complicated SQL queries that can't be executed
58
- # using the ActiveRecord::Calculations class methods. Look into those before using this.
68
+ # using the ActiveRecord::Calculations class methods. Look into those before using this method,
69
+ # as it could lock you into a specific database engine or require a code change to switch
70
+ # database engines.
59
71
  #
60
72
  # Product.count_by_sql "SELECT COUNT(*) FROM sales s, customers c WHERE s.customer_id = c.id"
61
73
  # # => 12