activerecord 6.0.4.8 → 6.1.0.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 (242) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +764 -883
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -3
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/association_relation.rb +22 -14
  7. data/lib/active_record/associations/alias_tracker.rb +19 -15
  8. data/lib/active_record/associations/association.rb +39 -27
  9. data/lib/active_record/associations/association_scope.rb +11 -15
  10. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  12. data/lib/active_record/associations/builder/association.rb +9 -3
  13. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  14. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
  16. data/lib/active_record/associations/builder/has_many.rb +6 -2
  17. data/lib/active_record/associations/builder/has_one.rb +11 -14
  18. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  19. data/lib/active_record/associations/collection_association.rb +19 -13
  20. data/lib/active_record/associations/collection_proxy.rb +12 -5
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -2
  23. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  24. data/lib/active_record/associations/has_one_association.rb +15 -1
  25. data/lib/active_record/associations/join_dependency/join_association.rb +29 -14
  26. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  27. data/lib/active_record/associations/join_dependency.rb +63 -49
  28. data/lib/active_record/associations/preloader/association.rb +13 -5
  29. data/lib/active_record/associations/preloader/through_association.rb +1 -1
  30. data/lib/active_record/associations/preloader.rb +5 -3
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations.rb +114 -11
  33. data/lib/active_record/attribute_assignment.rb +10 -8
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
  35. data/lib/active_record/attribute_methods/dirty.rb +1 -11
  36. data/lib/active_record/attribute_methods/primary_key.rb +6 -2
  37. data/lib/active_record/attribute_methods/query.rb +3 -6
  38. data/lib/active_record/attribute_methods/read.rb +8 -11
  39. data/lib/active_record/attribute_methods/serialization.rb +4 -4
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
  41. data/lib/active_record/attribute_methods/write.rb +12 -20
  42. data/lib/active_record/attribute_methods.rb +52 -48
  43. data/lib/active_record/attributes.rb +27 -7
  44. data/lib/active_record/autosave_association.rb +47 -30
  45. data/lib/active_record/base.rb +2 -14
  46. data/lib/active_record/callbacks.rb +32 -22
  47. data/lib/active_record/coders/yaml_column.rb +1 -1
  48. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +180 -134
  49. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  50. data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
  51. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
  52. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  53. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  54. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  55. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +110 -30
  56. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -24
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +31 -70
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
  61. data/lib/active_record/connection_adapters/column.rb +15 -1
  62. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  63. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -24
  65. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
  67. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +33 -6
  68. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  69. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  70. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -3
  71. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  72. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
  73. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  74. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  75. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  76. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +12 -53
  77. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  78. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  79. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -10
  80. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  84. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  87. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  88. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
  90. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
  91. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  92. data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
  93. data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
  94. data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
  95. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +30 -5
  96. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
  97. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  98. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
  99. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
  100. data/lib/active_record/connection_adapters.rb +50 -0
  101. data/lib/active_record/connection_handling.rb +210 -71
  102. data/lib/active_record/core.rb +215 -49
  103. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  104. data/lib/active_record/database_configurations/database_config.rb +52 -9
  105. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  106. data/lib/active_record/database_configurations/url_config.rb +15 -40
  107. data/lib/active_record/database_configurations.rb +124 -85
  108. data/lib/active_record/delegated_type.rb +209 -0
  109. data/lib/active_record/destroy_association_async_job.rb +36 -0
  110. data/lib/active_record/enum.rb +33 -23
  111. data/lib/active_record/errors.rb +47 -12
  112. data/lib/active_record/explain.rb +9 -4
  113. data/lib/active_record/explain_subscriber.rb +1 -1
  114. data/lib/active_record/fixture_set/file.rb +10 -17
  115. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  116. data/lib/active_record/fixture_set/render_context.rb +1 -1
  117. data/lib/active_record/fixture_set/table_row.rb +2 -2
  118. data/lib/active_record/fixtures.rb +54 -8
  119. data/lib/active_record/gem_version.rb +3 -3
  120. data/lib/active_record/inheritance.rb +40 -18
  121. data/lib/active_record/insert_all.rb +32 -5
  122. data/lib/active_record/integration.rb +3 -5
  123. data/lib/active_record/internal_metadata.rb +15 -4
  124. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  125. data/lib/active_record/locking/optimistic.rb +13 -16
  126. data/lib/active_record/locking/pessimistic.rb +6 -2
  127. data/lib/active_record/log_subscriber.rb +26 -8
  128. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  129. data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
  130. data/lib/active_record/middleware/database_selector.rb +4 -1
  131. data/lib/active_record/migration/command_recorder.rb +47 -27
  132. data/lib/active_record/migration/compatibility.rb +67 -17
  133. data/lib/active_record/migration.rb +113 -83
  134. data/lib/active_record/model_schema.rb +88 -42
  135. data/lib/active_record/nested_attributes.rb +2 -3
  136. data/lib/active_record/no_touching.rb +1 -1
  137. data/lib/active_record/persistence.rb +50 -45
  138. data/lib/active_record/query_cache.rb +15 -5
  139. data/lib/active_record/querying.rb +11 -6
  140. data/lib/active_record/railtie.rb +64 -44
  141. data/lib/active_record/railties/databases.rake +253 -98
  142. data/lib/active_record/readonly_attributes.rb +4 -0
  143. data/lib/active_record/reflection.rb +59 -44
  144. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  145. data/lib/active_record/relation/batches.rb +38 -31
  146. data/lib/active_record/relation/calculations.rb +100 -43
  147. data/lib/active_record/relation/finder_methods.rb +44 -14
  148. data/lib/active_record/relation/from_clause.rb +1 -1
  149. data/lib/active_record/relation/merger.rb +20 -23
  150. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  151. data/lib/active_record/relation/predicate_builder/association_query_value.rb +2 -2
  152. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
  153. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  154. data/lib/active_record/relation/predicate_builder.rb +57 -33
  155. data/lib/active_record/relation/query_methods.rb +319 -196
  156. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  157. data/lib/active_record/relation/spawn_methods.rb +6 -5
  158. data/lib/active_record/relation/where_clause.rb +104 -57
  159. data/lib/active_record/relation.rb +90 -64
  160. data/lib/active_record/result.rb +41 -33
  161. data/lib/active_record/runtime_registry.rb +2 -2
  162. data/lib/active_record/sanitization.rb +6 -17
  163. data/lib/active_record/schema_dumper.rb +34 -4
  164. data/lib/active_record/schema_migration.rb +0 -4
  165. data/lib/active_record/scoping/named.rb +1 -17
  166. data/lib/active_record/secure_token.rb +16 -8
  167. data/lib/active_record/serialization.rb +5 -3
  168. data/lib/active_record/signed_id.rb +116 -0
  169. data/lib/active_record/statement_cache.rb +20 -4
  170. data/lib/active_record/store.rb +2 -2
  171. data/lib/active_record/suppressor.rb +2 -2
  172. data/lib/active_record/table_metadata.rb +36 -52
  173. data/lib/active_record/tasks/database_tasks.rb +139 -113
  174. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
  175. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
  176. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
  177. data/lib/active_record/test_databases.rb +5 -4
  178. data/lib/active_record/test_fixtures.rb +36 -33
  179. data/lib/active_record/timestamp.rb +4 -6
  180. data/lib/active_record/touch_later.rb +21 -21
  181. data/lib/active_record/transactions.rb +15 -64
  182. data/lib/active_record/type/serialized.rb +6 -2
  183. data/lib/active_record/type.rb +8 -1
  184. data/lib/active_record/type_caster/connection.rb +0 -1
  185. data/lib/active_record/type_caster/map.rb +8 -5
  186. data/lib/active_record/validations/associated.rb +1 -1
  187. data/lib/active_record/validations/numericality.rb +35 -0
  188. data/lib/active_record/validations/uniqueness.rb +24 -4
  189. data/lib/active_record/validations.rb +1 -0
  190. data/lib/active_record.rb +7 -14
  191. data/lib/arel/attributes/attribute.rb +4 -0
  192. data/lib/arel/collectors/bind.rb +5 -0
  193. data/lib/arel/collectors/composite.rb +8 -0
  194. data/lib/arel/collectors/sql_string.rb +7 -0
  195. data/lib/arel/collectors/substitute_binds.rb +7 -0
  196. data/lib/arel/nodes/binary.rb +82 -8
  197. data/lib/arel/nodes/bind_param.rb +8 -0
  198. data/lib/arel/nodes/casted.rb +21 -9
  199. data/lib/arel/nodes/equality.rb +6 -9
  200. data/lib/arel/nodes/grouping.rb +3 -0
  201. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  202. data/lib/arel/nodes/in.rb +8 -1
  203. data/lib/arel/nodes/infix_operation.rb +13 -1
  204. data/lib/arel/nodes/join_source.rb +1 -1
  205. data/lib/arel/nodes/node.rb +7 -6
  206. data/lib/arel/nodes/ordering.rb +27 -0
  207. data/lib/arel/nodes/sql_literal.rb +3 -0
  208. data/lib/arel/nodes/table_alias.rb +7 -3
  209. data/lib/arel/nodes/unary.rb +0 -1
  210. data/lib/arel/nodes.rb +3 -1
  211. data/lib/arel/predications.rb +12 -18
  212. data/lib/arel/select_manager.rb +1 -2
  213. data/lib/arel/table.rb +13 -5
  214. data/lib/arel/visitors/dot.rb +14 -2
  215. data/lib/arel/visitors/mysql.rb +11 -1
  216. data/lib/arel/visitors/postgresql.rb +15 -4
  217. data/lib/arel/visitors/to_sql.rb +89 -78
  218. data/lib/arel/visitors.rb +0 -7
  219. data/lib/arel.rb +5 -13
  220. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  221. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  222. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
  223. data/lib/rails/generators/active_record/migration.rb +6 -1
  224. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  225. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  226. metadata +30 -31
  227. data/lib/active_record/advisory_lock_base.rb +0 -18
  228. data/lib/active_record/attribute_decorators.rb +0 -88
  229. data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
  230. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  231. data/lib/active_record/define_callbacks.rb +0 -22
  232. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  233. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  234. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  235. data/lib/arel/attributes.rb +0 -22
  236. data/lib/arel/visitors/depth_first.rb +0 -203
  237. data/lib/arel/visitors/ibm_db.rb +0 -34
  238. data/lib/arel/visitors/informix.rb +0 -62
  239. data/lib/arel/visitors/mssql.rb +0 -156
  240. data/lib/arel/visitors/oracle.rb +0 -158
  241. data/lib/arel/visitors/oracle12.rb +0 -65
  242. data/lib/arel/visitors/where_sql.rb +0 -22
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/enumerable"
3
4
  require "active_support/core_ext/hash/indifferent_access"
4
5
  require "active_support/core_ext/string/filters"
5
6
  require "active_support/parameter_filter"
@@ -25,6 +26,18 @@ module ActiveRecord
25
26
  # their relevant queries. Defaults to false.
26
27
  mattr_accessor :verbose_query_logs, instance_writer: false, default: false
27
28
 
29
+ ##
30
+ # :singleton-method:
31
+ #
32
+ # Specifies the names of the queues used by background jobs.
33
+ mattr_accessor :queues, instance_accessor: false, default: {}
34
+
35
+ ##
36
+ # :singleton-method:
37
+ #
38
+ # Specifies the job used to destroy associations in the background
39
+ class_attribute :destroy_association_async_job, instance_writer: false, instance_predicate: false, default: false
40
+
28
41
  ##
29
42
  # Contains the database configuration - as is typically stored in config/database.yml -
30
43
  # as an ActiveRecord::DatabaseConfigurations object.
@@ -43,9 +56,9 @@ module ActiveRecord
43
56
  #
44
57
  # #<ActiveRecord::DatabaseConfigurations:0x00007fd1acbdf800 @configurations=[
45
58
  # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
46
- # @spec_name="primary", @config={"adapter"=>"sqlite3", "database"=>"db/development.sqlite3"}>,
59
+ # @name="primary", @config={adapter: "sqlite3", database: "db/development.sqlite3"}>,
47
60
  # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="production",
48
- # @spec_name="primary", @config={"adapter"=>"mysql2", "database"=>"db/production.sqlite3"}>
61
+ # @name="primary", @config={adapter: "sqlite3", database: "db/production.sqlite3"}>
49
62
  # ]>
50
63
  def self.configurations=(config)
51
64
  @@configurations = ActiveRecord::DatabaseConfigurations.new(config)
@@ -80,14 +93,6 @@ module ActiveRecord
80
93
  # scope being ignored is error-worthy, rather than a warning.
81
94
  mattr_accessor :error_on_ignored_order, instance_writer: false, default: false
82
95
 
83
- # :singleton-method:
84
- # Specify the behavior for unsafe raw query methods. Values are as follows
85
- # deprecated - Warnings are logged when unsafe raw SQL is passed to
86
- # query methods.
87
- # disabled - Unsafe raw SQL passed to query methods results in
88
- # UnknownAttributeReference exception.
89
- mattr_accessor :allow_unsafe_raw_sql, instance_writer: false, default: :deprecated
90
-
91
96
  ##
92
97
  # :singleton-method:
93
98
  # Specify whether or not to use timestamps for migration versions
@@ -103,7 +108,7 @@ module ActiveRecord
103
108
 
104
109
  ##
105
110
  # :singleton-method:
106
- # Specifies which database schemas to dump when calling db:structure:dump.
111
+ # Specifies which database schemas to dump when calling db:schema:dump.
107
112
  # If the value is :schema_search_path (the default), any schemas listed in
108
113
  # schema_search_path are dumped. Use :all to dump all schemas regardless
109
114
  # of schema_search_path, or a string of comma separated schemas for a
@@ -118,29 +123,162 @@ module ActiveRecord
118
123
  # potentially cause memory bloat.
119
124
  mattr_accessor :warn_on_records_fetched_greater_than, instance_writer: false
120
125
 
126
+ ##
127
+ # :singleton-method:
128
+ # Show a warning when Rails couldn't parse your database.yml
129
+ # for multiple databases.
130
+ mattr_accessor :suppress_multiple_database_warning, instance_writer: false, default: false
131
+
121
132
  mattr_accessor :maintain_test_schema, instance_accessor: false
122
133
 
123
- mattr_accessor :belongs_to_required_by_default, instance_accessor: false
134
+ class_attribute :belongs_to_required_by_default, instance_accessor: false
135
+
136
+ ##
137
+ # :singleton-method:
138
+ # Set the application to log or raise when an association violates strict loading.
139
+ # Defaults to :raise.
140
+ mattr_accessor :action_on_strict_loading_violation, instance_accessor: false, default: :raise
124
141
 
125
- mattr_accessor :connection_handlers, instance_accessor: false, default: {}
142
+ class_attribute :strict_loading_by_default, instance_accessor: false, default: false
126
143
 
127
144
  mattr_accessor :writing_role, instance_accessor: false, default: :writing
128
145
 
129
146
  mattr_accessor :reading_role, instance_accessor: false, default: :reading
130
147
 
148
+ mattr_accessor :has_many_inversing, instance_accessor: false, default: false
149
+
131
150
  class_attribute :default_connection_handler, instance_writer: false
132
151
 
152
+ class_attribute :default_role, instance_writer: false
153
+
154
+ class_attribute :default_shard, instance_writer: false
155
+
156
+ mattr_accessor :legacy_connection_handling, instance_writer: false, default: true
157
+
133
158
  self.filter_attributes = []
134
159
 
135
160
  def self.connection_handler
136
- Thread.current.thread_variable_get("ar_connection_handler") || default_connection_handler
161
+ Thread.current.thread_variable_get(:ar_connection_handler) || default_connection_handler
137
162
  end
138
163
 
139
164
  def self.connection_handler=(handler)
140
- Thread.current.thread_variable_set("ar_connection_handler", handler)
165
+ Thread.current.thread_variable_set(:ar_connection_handler, handler)
166
+ end
167
+
168
+ def self.connection_handlers
169
+ @@connection_handlers ||= {}
170
+ end
171
+
172
+ def self.connection_handlers=(handlers)
173
+ @@connection_handlers = handlers
174
+ end
175
+
176
+ # Returns the symbol representing the current connected role.
177
+ #
178
+ # ActiveRecord::Base.connected_to(role: :writing) do
179
+ # ActiveRecord::Base.current_role #=> :writing
180
+ # end
181
+ #
182
+ # ActiveRecord::Base.connected_to(role: :reading) do
183
+ # ActiveRecord::Base.current_role #=> :reading
184
+ # end
185
+ def self.current_role
186
+ if ActiveRecord::Base.legacy_connection_handling
187
+ connection_handlers.key(connection_handler) || default_role
188
+ else
189
+ connected_to_stack.reverse_each do |hash|
190
+ return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
191
+ return hash[:role] if hash[:role] && hash[:klasses].include?(abstract_base_class)
192
+ end
193
+
194
+ default_role
195
+ end
196
+ end
197
+
198
+ # Returns the symbol representing the current connected shard.
199
+ #
200
+ # ActiveRecord::Base.connected_to(role: :reading) do
201
+ # ActiveRecord::Base.current_shard #=> :default
202
+ # end
203
+ #
204
+ # ActiveRecord::Base.connected_to(role: :writing, shard: :one) do
205
+ # ActiveRecord::Base.current_shard #=> :one
206
+ # end
207
+ def self.current_shard
208
+ connected_to_stack.reverse_each do |hash|
209
+ return hash[:shard] if hash[:shard] && hash[:klasses].include?(Base)
210
+ return hash[:shard] if hash[:shard] && hash[:klasses].include?(abstract_base_class)
211
+ end
212
+
213
+ default_shard
214
+ end
215
+
216
+ # Returns the symbol representing the current setting for
217
+ # preventing writes.
218
+ #
219
+ # ActiveRecord::Base.connected_to(role: :reading) do
220
+ # ActiveRecord::Base.current_preventing_writes #=> true
221
+ # end
222
+ #
223
+ # ActiveRecord::Base.connected_to(role: :writing) do
224
+ # ActiveRecord::Base.current_preventing_writes #=> false
225
+ # end
226
+ def self.current_preventing_writes
227
+ if legacy_connection_handling
228
+ connection_handler.prevent_writes
229
+ else
230
+ connected_to_stack.reverse_each do |hash|
231
+ return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
232
+ return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(abstract_base_class)
233
+ end
234
+
235
+ false
236
+ end
237
+ end
238
+
239
+ def self.connected_to_stack # :nodoc:
240
+ if connected_to_stack = Thread.current.thread_variable_get(:ar_connected_to_stack)
241
+ connected_to_stack
242
+ else
243
+ connected_to_stack = Concurrent::Array.new
244
+ Thread.current.thread_variable_set(:ar_connected_to_stack, connected_to_stack)
245
+ connected_to_stack
246
+ end
247
+ end
248
+
249
+ def self.abstract_base_class # :nodoc:
250
+ klass = self
251
+
252
+ until klass == Base
253
+ break if klass.abstract_class?
254
+ klass = klass.superclass
255
+ end
256
+
257
+ klass
258
+ end
259
+
260
+ def self.allow_unsafe_raw_sql # :nodoc:
261
+ ActiveSupport::Deprecation.warn("ActiveRecord::Base.allow_unsafe_raw_sql is deprecated and will be removed in Rails 6.2")
262
+ end
263
+
264
+ def self.allow_unsafe_raw_sql=(value) # :nodoc:
265
+ ActiveSupport::Deprecation.warn("ActiveRecord::Base.allow_unsafe_raw_sql= is deprecated and will be removed in Rails 6.2")
141
266
  end
142
267
 
143
268
  self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
269
+ self.default_role = writing_role
270
+ self.default_shard = :default
271
+
272
+ def self.strict_loading_violation!(owner:, association:) # :nodoc:
273
+ case action_on_strict_loading_violation
274
+ when :raise
275
+ message = "`#{association}` called on `#{owner}` is marked for strict_loading and cannot be lazily loaded."
276
+ raise ActiveRecord::StrictLoadingViolationError.new(message)
277
+ when :log
278
+ name = "strict_loading_violation.active_record"
279
+ ActiveSupport::Notifications.instrument(name, owner: owner, association: association)
280
+ end
281
+ end
144
282
  end
145
283
 
146
284
  module ClassMethods
@@ -151,16 +289,20 @@ module ActiveRecord
151
289
  def inherited(child_class) # :nodoc:
152
290
  # initialize cache at class definition for thread safety
153
291
  child_class.initialize_find_by_cache
292
+ unless child_class.base_class?
293
+ klass = self
294
+ until klass.base_class?
295
+ klass.initialize_find_by_cache
296
+ klass = klass.superclass
297
+ end
298
+ end
154
299
  super
155
300
  end
156
301
 
157
302
  def find(*ids) # :nodoc:
158
303
  # We don't have cache keys for this stuff yet
159
304
  return super unless ids.length == 1
160
- return super if block_given? ||
161
- primary_key.nil? ||
162
- scope_attributes? ||
163
- columns_hash.key?(inheritance_column) && !base_class?
305
+ return super if block_given? || primary_key.nil? || scope_attributes?
164
306
 
165
307
  id = ids.first
166
308
 
@@ -172,36 +314,41 @@ module ActiveRecord
172
314
  where(key => params.bind).limit(1)
173
315
  }
174
316
 
175
- record = statement.execute([id], connection)&.first
176
- unless record
177
- raise RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id)
178
- end
179
- record
317
+ statement.execute([id], connection).first ||
318
+ raise(RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id))
180
319
  end
181
320
 
182
321
  def find_by(*args) # :nodoc:
183
- return super if scope_attributes? || reflect_on_all_aggregations.any? ||
184
- columns_hash.key?(inheritance_column) && !base_class?
322
+ return super if scope_attributes?
185
323
 
186
324
  hash = args.first
325
+ return super unless Hash === hash
326
+
327
+ values = hash.values.map! { |value| value.is_a?(Base) ? value.id : value }
328
+ return super if values.any? { |v| StatementCache.unsupported_value?(v) }
329
+
330
+ keys = hash.keys.map! do |key|
331
+ attribute_aliases[name = key.to_s] || begin
332
+ reflection = _reflect_on_association(name)
333
+ if reflection&.belongs_to? && !reflection.polymorphic?
334
+ reflection.join_foreign_key
335
+ elsif reflect_on_aggregation(name)
336
+ return super
337
+ else
338
+ name
339
+ end
340
+ end
341
+ end
187
342
 
188
- return super if !(Hash === hash) || hash.values.any? { |v|
189
- StatementCache.unsupported_value?(v)
190
- }
191
-
192
- # We can't cache Post.find_by(author: david) ...yet
193
- return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
194
-
195
- keys = hash.keys
343
+ return super unless keys.all? { |k| columns_hash.key?(k) }
196
344
 
197
345
  statement = cached_find_by_statement(keys) { |params|
198
- wheres = keys.each_with_object({}) { |param, o|
199
- o[param] = params.bind
200
- }
346
+ wheres = keys.index_with { params.bind }
201
347
  where(wheres).limit(1)
202
348
  }
349
+
203
350
  begin
204
- statement.execute(hash.values, connection)&.first
351
+ statement.execute(values, connection).first
205
352
  rescue TypeError
206
353
  raise ActiveRecord::StatementInvalid
207
354
  end
@@ -264,14 +411,13 @@ module ActiveRecord
264
411
  # scope :published_and_commented, -> { published.and(arel_table[:comments_count].gt(0)) }
265
412
  # end
266
413
  def arel_table # :nodoc:
267
- @arel_table ||= Arel::Table.new(table_name, type_caster: type_caster)
414
+ @arel_table ||= Arel::Table.new(table_name, klass: self)
268
415
  end
269
416
 
270
417
  def arel_attribute(name, table = arel_table) # :nodoc:
271
- name = name.to_s
272
- name = attribute_aliases[name] || name
273
418
  table[name]
274
419
  end
420
+ deprecate :arel_attribute
275
421
 
276
422
  def predicate_builder # :nodoc:
277
423
  @predicate_builder ||= PredicateBuilder.new(table_metadata)
@@ -399,9 +545,9 @@ module ActiveRecord
399
545
  _run_initialize_callbacks
400
546
 
401
547
  @new_record = true
548
+ @previously_new_record = false
402
549
  @destroyed = false
403
550
  @_start_transaction_state = nil
404
- @transaction_state = nil
405
551
 
406
552
  super
407
553
  end
@@ -461,7 +607,6 @@ module ActiveRecord
461
607
 
462
608
  # Returns +true+ if the attributes hash has been frozen.
463
609
  def frozen?
464
- sync_with_transaction_state if @transaction_state&.finalized?
465
610
  @attributes.frozen?
466
611
  end
467
612
 
@@ -482,12 +627,27 @@ module ActiveRecord
482
627
  false
483
628
  end
484
629
 
485
- # Returns +true+ if the record is read only. Records loaded through joins with piggy-back
486
- # attributes will be marked as read only since they cannot be saved.
630
+ # Returns +true+ if the record is read only.
487
631
  def readonly?
488
632
  @readonly
489
633
  end
490
634
 
635
+ # Returns +true+ if the record is in strict_loading mode.
636
+ def strict_loading?
637
+ @strict_loading
638
+ end
639
+
640
+ # Sets the record to strict_loading mode. This will raise an error
641
+ # if the record tries to lazily load an association.
642
+ #
643
+ # user = User.first
644
+ # user.strict_loading!
645
+ # user.comments.to_a
646
+ # => ActiveRecord::StrictLoadingViolationError
647
+ def strict_loading!
648
+ @strict_loading = true
649
+ end
650
+
491
651
  # Marks this record as read only.
492
652
  def readonly!
493
653
  @readonly = true
@@ -503,7 +663,7 @@ module ActiveRecord
503
663
  # allocated but not initialized.
504
664
  inspection = if defined?(@attributes) && @attributes
505
665
  self.class.attribute_names.collect do |name|
506
- if has_attribute?(name)
666
+ if _has_attribute?(name)
507
667
  attr = _read_attribute(name)
508
668
  value = if attr.nil?
509
669
  attr.inspect
@@ -527,7 +687,7 @@ module ActiveRecord
527
687
  return super if custom_inspect_method_defined?
528
688
  pp.object_address_group(self) do
529
689
  if defined?(@attributes) && @attributes
530
- attr_names = self.class.attribute_names.select { |name| has_attribute?(name) }
690
+ attr_names = self.class.attribute_names.select { |name| _has_attribute?(name) }
531
691
  pp.seplist(attr_names, proc { pp.text "," }) do |attr_name|
532
692
  pp.breakable " "
533
693
  pp.group(1) do
@@ -548,7 +708,12 @@ module ActiveRecord
548
708
 
549
709
  # Returns a hash of the given methods with their names as keys and returned values as values.
550
710
  def slice(*methods)
551
- Hash[methods.flatten.map! { |method| [method, public_send(method)] }].with_indifferent_access
711
+ methods.flatten.index_with { |method| public_send(method) }.with_indifferent_access
712
+ end
713
+
714
+ # Returns an array of the values returned by the given methods.
715
+ def values_at(*methods)
716
+ methods.flatten.map! { |method| public_send(method) }
552
717
  end
553
718
 
554
719
  private
@@ -567,11 +732,12 @@ module ActiveRecord
567
732
  def init_internals
568
733
  @primary_key = self.class.primary_key
569
734
  @readonly = false
735
+ @previously_new_record = false
570
736
  @destroyed = false
571
737
  @marked_for_destruction = false
572
738
  @destroyed_by_association = nil
573
739
  @_start_transaction_state = nil
574
- @transaction_state = nil
740
+ @strict_loading = self.class.strict_loading_by_default
575
741
 
576
742
  self.class.define_attribute_methods
577
743
  end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/enumerable"
4
+
5
+ module ActiveRecord
6
+ class DatabaseConfigurations
7
+ # Expands a connection string into a hash.
8
+ class ConnectionUrlResolver # :nodoc:
9
+ # == Example
10
+ #
11
+ # url = "postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000"
12
+ # ConnectionUrlResolver.new(url).to_hash
13
+ # # => {
14
+ # adapter: "postgresql",
15
+ # host: "localhost",
16
+ # port: 9000,
17
+ # database: "foo_test",
18
+ # username: "foo",
19
+ # password: "bar",
20
+ # pool: "5",
21
+ # timeout: "3000"
22
+ # }
23
+ def initialize(url)
24
+ raise "Database URL cannot be empty" if url.blank?
25
+ @uri = uri_parser.parse(url)
26
+ @adapter = @uri.scheme && @uri.scheme.tr("-", "_")
27
+ @adapter = "postgresql" if @adapter == "postgres"
28
+
29
+ if @uri.opaque
30
+ @uri.opaque, @query = @uri.opaque.split("?", 2)
31
+ else
32
+ @query = @uri.query
33
+ end
34
+ end
35
+
36
+ # Converts the given URL to a full connection hash.
37
+ def to_hash
38
+ config = raw_config.compact_blank
39
+ config.map { |key, value| config[key] = uri_parser.unescape(value) if value.is_a? String }
40
+ config
41
+ end
42
+
43
+ private
44
+ attr_reader :uri
45
+
46
+ def uri_parser
47
+ @uri_parser ||= URI::Parser.new
48
+ end
49
+
50
+ # Converts the query parameters of the URI into a hash.
51
+ #
52
+ # "localhost?pool=5&reaping_frequency=2"
53
+ # # => { pool: "5", reaping_frequency: "2" }
54
+ #
55
+ # returns empty hash if no query present.
56
+ #
57
+ # "localhost"
58
+ # # => {}
59
+ def query_hash
60
+ Hash[(@query || "").split("&").map { |pair| pair.split("=", 2) }].symbolize_keys
61
+ end
62
+
63
+ def raw_config
64
+ if uri.opaque
65
+ query_hash.merge(
66
+ adapter: @adapter,
67
+ database: uri.opaque
68
+ )
69
+ else
70
+ query_hash.merge(
71
+ adapter: @adapter,
72
+ username: uri.user,
73
+ password: uri.password,
74
+ port: uri.port,
75
+ database: database_from_path,
76
+ host: uri.hostname
77
+ )
78
+ end
79
+ end
80
+
81
+ # Returns name of the database.
82
+ def database_from_path
83
+ if @adapter == "sqlite3"
84
+ # 'sqlite3:/foo' is absolute, because that makes sense. The
85
+ # corresponding relative version, 'sqlite3:foo', is handled
86
+ # elsewhere, as an "opaque".
87
+
88
+ uri.path
89
+ else
90
+ # Only SQLite uses a filename as the "database" name; for
91
+ # anything else, a leading slash would be silly.
92
+
93
+ uri.path.delete_prefix("/")
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -6,32 +6,75 @@ module ActiveRecord
6
6
  # UrlConfig respectively. It will never return a DatabaseConfig object,
7
7
  # as this is the parent class for the types of database configuration objects.
8
8
  class DatabaseConfig # :nodoc:
9
- attr_reader :env_name, :spec_name
9
+ attr_reader :env_name, :name
10
10
 
11
- def initialize(env_name, spec_name)
11
+ attr_accessor :owner_name
12
+
13
+ def initialize(env_name, name)
12
14
  @env_name = env_name
13
- @spec_name = spec_name
15
+ @name = name
14
16
  end
15
17
 
16
- def replica?
18
+ def spec_name
19
+ @name
20
+ end
21
+ deprecate spec_name: "please use name instead"
22
+
23
+ def config
17
24
  raise NotImplementedError
18
25
  end
19
26
 
20
- def migrations_paths
27
+ def adapter_method
28
+ "#{adapter}_connection"
29
+ end
30
+
31
+ def host
32
+ raise NotImplementedError
33
+ end
34
+
35
+ def database
21
36
  raise NotImplementedError
22
37
  end
23
38
 
24
- def url_config?
25
- false
39
+ def _database=(database)
40
+ raise NotImplementedError
41
+ end
42
+
43
+ def adapter
44
+ raise NotImplementedError
26
45
  end
27
46
 
28
- def to_legacy_hash
29
- { env_name => config }
47
+ def pool
48
+ raise NotImplementedError
49
+ end
50
+
51
+ def checkout_timeout
52
+ raise NotImplementedError
53
+ end
54
+
55
+ def reaping_frequency
56
+ raise NotImplementedError
57
+ end
58
+
59
+ def idle_timeout
60
+ raise NotImplementedError
61
+ end
62
+
63
+ def replica?
64
+ raise NotImplementedError
65
+ end
66
+
67
+ def migrations_paths
68
+ raise NotImplementedError
30
69
  end
31
70
 
32
71
  def for_current_env?
33
72
  env_name == ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
34
73
  end
74
+
75
+ def schema_cache_path
76
+ raise NotImplementedError
77
+ end
35
78
  end
36
79
  end
37
80
  end
@@ -12,12 +12,12 @@ module ActiveRecord
12
12
  # Becomes:
13
13
  #
14
14
  # #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10
15
- # @env_name="development", @spec_name="primary", @config={"database"=>"db_name"}>
15
+ # @env_name="development", @name="primary", @config={database: "db_name"}>
16
16
  #
17
17
  # ==== Options
18
18
  #
19
19
  # * <tt>:env_name</tt> - The Rails environment, i.e. "development".
20
- # * <tt>:spec_name</tt> - The specification name. In a standard two-tier
20
+ # * <tt>:name</tt> - The db config name. In a standard two-tier
21
21
  # database configuration this will default to "primary". In a multiple
22
22
  # database three-tier database configuration this corresponds to the name
23
23
  # used in the second tier, for example "primary_readonly".
@@ -25,25 +25,71 @@ module ActiveRecord
25
25
  # database adapter, name, and other important information for database
26
26
  # connections.
27
27
  class HashConfig < DatabaseConfig
28
- attr_reader :config
28
+ attr_reader :configuration_hash
29
+ def initialize(env_name, name, configuration_hash)
30
+ super(env_name, name)
31
+ @configuration_hash = configuration_hash.symbolize_keys.freeze
32
+ end
29
33
 
30
- def initialize(env_name, spec_name, config)
31
- super(env_name, spec_name)
32
- @config = config
34
+ def config
35
+ ActiveSupport::Deprecation.warn("DatabaseConfig#config will be removed in 6.2.0 in favor of DatabaseConfigurations#configuration_hash which returns a hash with symbol keys")
36
+ configuration_hash.stringify_keys
33
37
  end
34
38
 
35
39
  # Determines whether a database configuration is for a replica / readonly
36
40
  # connection. If the +replica+ key is present in the config, +replica?+ will
37
41
  # return +true+.
38
42
  def replica?
39
- config["replica"]
43
+ configuration_hash[:replica]
40
44
  end
41
45
 
42
46
  # The migrations paths for a database configuration. If the
43
47
  # +migrations_paths+ key is present in the config, +migrations_paths+
44
48
  # will return its value.
45
49
  def migrations_paths
46
- config["migrations_paths"]
50
+ configuration_hash[:migrations_paths]
51
+ end
52
+
53
+ def host
54
+ configuration_hash[:host]
55
+ end
56
+
57
+ def database
58
+ configuration_hash[:database]
59
+ end
60
+
61
+ def _database=(database) # :nodoc:
62
+ @configuration_hash = configuration_hash.merge(database: database).freeze
63
+ end
64
+
65
+ def pool
66
+ (configuration_hash[:pool] || 5).to_i
67
+ end
68
+
69
+ def checkout_timeout
70
+ (configuration_hash[:checkout_timeout] || 5).to_f
71
+ end
72
+
73
+ # +reaping_frequency+ is configurable mostly for historical reasons, but it could
74
+ # also be useful if someone wants a very low +idle_timeout+.
75
+ def reaping_frequency
76
+ configuration_hash.fetch(:reaping_frequency, 60)&.to_f
77
+ end
78
+
79
+ def idle_timeout
80
+ timeout = configuration_hash.fetch(:idle_timeout, 300).to_f
81
+ timeout if timeout > 0
82
+ end
83
+
84
+ def adapter
85
+ configuration_hash[:adapter]
86
+ end
87
+
88
+ # The path to the schema cache dump file for a database.
89
+ # If omitted, the filename will be read from ENV or a
90
+ # default will be derived.
91
+ def schema_cache_path
92
+ configuration_hash[:schema_cache_path]
47
93
  end
48
94
  end
49
95
  end