activerecord 6.0.6 → 6.1.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 (242) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +783 -910
  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 +43 -26
  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 +11 -5
  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 +64 -54
  43. data/lib/active_record/attributes.rb +32 -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 +152 -22
  47. data/lib/active_record/coders/yaml_column.rb +2 -24
  48. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +185 -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 +80 -32
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +49 -72
  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 +32 -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 -2
  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 +223 -66
  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 +27 -10
  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 +2 -2
  120. data/lib/active_record/inheritance.rb +40 -18
  121. data/lib/active_record/insert_all.rb +34 -5
  122. data/lib/active_record/integration.rb +3 -5
  123. data/lib/active_record/internal_metadata.rb +16 -7
  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 -13
  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 +266 -95
  142. data/lib/active_record/readonly_attributes.rb +4 -0
  143. data/lib/active_record/reflection.rb +60 -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 +4 -5
  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 +318 -195
  156. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  157. data/lib/active_record/relation/spawn_methods.rb +8 -7
  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 +2 -8
  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 +39 -51
  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 +28 -30
  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,39 +123,170 @@ 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
 
131
- ##
132
- # :singleton-method:
133
- # Application configurable boolean that instructs the YAML Coder to use
134
- # an unsafe load if set to true.
135
- mattr_accessor :use_yaml_unsafe_load, instance_writer: false, default: false
136
-
137
- # Application configurable array that provides additional permitted classes
138
- # to Psych safe_load in the YAML Coder
139
- mattr_accessor :yaml_column_permitted_classes, instance_writer: false, default: [Symbol]
148
+ mattr_accessor :has_many_inversing, instance_accessor: false, default: false
140
149
 
141
150
  class_attribute :default_connection_handler, instance_writer: false
142
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
+
143
158
  self.filter_attributes = []
144
159
 
145
160
  def self.connection_handler
146
- Thread.current.thread_variable_get("ar_connection_handler") || default_connection_handler
161
+ Thread.current.thread_variable_get(:ar_connection_handler) || default_connection_handler
147
162
  end
148
163
 
149
164
  def self.connection_handler=(handler)
150
- 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
+ unless legacy_connection_handling
170
+ raise NotImplementedError, "The new connection handling does not support accessing multiple connection handlers."
171
+ end
172
+
173
+ @@connection_handlers ||= {}
174
+ end
175
+
176
+ def self.connection_handlers=(handlers)
177
+ unless legacy_connection_handling
178
+ raise NotImplementedError, "The new connection handling does not setting support multiple connection handlers."
179
+ end
180
+
181
+ @@connection_handlers = handlers
182
+ end
183
+
184
+ # Returns the symbol representing the current connected role.
185
+ #
186
+ # ActiveRecord::Base.connected_to(role: :writing) do
187
+ # ActiveRecord::Base.current_role #=> :writing
188
+ # end
189
+ #
190
+ # ActiveRecord::Base.connected_to(role: :reading) do
191
+ # ActiveRecord::Base.current_role #=> :reading
192
+ # end
193
+ def self.current_role
194
+ if ActiveRecord::Base.legacy_connection_handling
195
+ connection_handlers.key(connection_handler) || default_role
196
+ else
197
+ connected_to_stack.reverse_each do |hash|
198
+ return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
199
+ return hash[:role] if hash[:role] && hash[:klasses].include?(abstract_base_class)
200
+ end
201
+
202
+ default_role
203
+ end
204
+ end
205
+
206
+ # Returns the symbol representing the current connected shard.
207
+ #
208
+ # ActiveRecord::Base.connected_to(role: :reading) do
209
+ # ActiveRecord::Base.current_shard #=> :default
210
+ # end
211
+ #
212
+ # ActiveRecord::Base.connected_to(role: :writing, shard: :one) do
213
+ # ActiveRecord::Base.current_shard #=> :one
214
+ # end
215
+ def self.current_shard
216
+ connected_to_stack.reverse_each do |hash|
217
+ return hash[:shard] if hash[:shard] && hash[:klasses].include?(Base)
218
+ return hash[:shard] if hash[:shard] && hash[:klasses].include?(abstract_base_class)
219
+ end
220
+
221
+ default_shard
222
+ end
223
+
224
+ # Returns the symbol representing the current setting for
225
+ # preventing writes.
226
+ #
227
+ # ActiveRecord::Base.connected_to(role: :reading) do
228
+ # ActiveRecord::Base.current_preventing_writes #=> true
229
+ # end
230
+ #
231
+ # ActiveRecord::Base.connected_to(role: :writing) do
232
+ # ActiveRecord::Base.current_preventing_writes #=> false
233
+ # end
234
+ def self.current_preventing_writes
235
+ if legacy_connection_handling
236
+ connection_handler.prevent_writes
237
+ else
238
+ connected_to_stack.reverse_each do |hash|
239
+ return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
240
+ return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(abstract_base_class)
241
+ end
242
+
243
+ false
244
+ end
245
+ end
246
+
247
+ def self.connected_to_stack # :nodoc:
248
+ if connected_to_stack = Thread.current.thread_variable_get(:ar_connected_to_stack)
249
+ connected_to_stack
250
+ else
251
+ connected_to_stack = Concurrent::Array.new
252
+ Thread.current.thread_variable_set(:ar_connected_to_stack, connected_to_stack)
253
+ connected_to_stack
254
+ end
255
+ end
256
+
257
+ def self.abstract_base_class # :nodoc:
258
+ klass = self
259
+
260
+ until klass == Base
261
+ break if klass.abstract_class?
262
+ klass = klass.superclass
263
+ end
264
+
265
+ klass
266
+ end
267
+
268
+ def self.allow_unsafe_raw_sql # :nodoc:
269
+ ActiveSupport::Deprecation.warn("ActiveRecord::Base.allow_unsafe_raw_sql is deprecated and will be removed in Rails 6.2")
270
+ end
271
+
272
+ def self.allow_unsafe_raw_sql=(value) # :nodoc:
273
+ ActiveSupport::Deprecation.warn("ActiveRecord::Base.allow_unsafe_raw_sql= is deprecated and will be removed in Rails 6.2")
151
274
  end
152
275
 
153
276
  self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
277
+ self.default_role = writing_role
278
+ self.default_shard = :default
279
+
280
+ def self.strict_loading_violation!(owner:, association:) # :nodoc:
281
+ case action_on_strict_loading_violation
282
+ when :raise
283
+ message = "`#{association}` called on `#{owner}` is marked for strict_loading and cannot be lazily loaded."
284
+ raise ActiveRecord::StrictLoadingViolationError.new(message)
285
+ when :log
286
+ name = "strict_loading_violation.active_record"
287
+ ActiveSupport::Notifications.instrument(name, owner: owner, association: association)
288
+ end
289
+ end
154
290
  end
155
291
 
156
292
  module ClassMethods
@@ -161,16 +297,20 @@ module ActiveRecord
161
297
  def inherited(child_class) # :nodoc:
162
298
  # initialize cache at class definition for thread safety
163
299
  child_class.initialize_find_by_cache
300
+ unless child_class.base_class?
301
+ klass = self
302
+ until klass.base_class?
303
+ klass.initialize_find_by_cache
304
+ klass = klass.superclass
305
+ end
306
+ end
164
307
  super
165
308
  end
166
309
 
167
310
  def find(*ids) # :nodoc:
168
311
  # We don't have cache keys for this stuff yet
169
312
  return super unless ids.length == 1
170
- return super if block_given? ||
171
- primary_key.nil? ||
172
- scope_attributes? ||
173
- columns_hash.key?(inheritance_column) && !base_class?
313
+ return super if block_given? || primary_key.nil? || scope_attributes?
174
314
 
175
315
  id = ids.first
176
316
 
@@ -182,36 +322,41 @@ module ActiveRecord
182
322
  where(key => params.bind).limit(1)
183
323
  }
184
324
 
185
- record = statement.execute([id], connection)&.first
186
- unless record
187
- raise RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id)
188
- end
189
- record
325
+ statement.execute([id], connection).first ||
326
+ raise(RecordNotFound.new("Couldn't find #{name} with '#{key}'=#{id}", name, key, id))
190
327
  end
191
328
 
192
329
  def find_by(*args) # :nodoc:
193
- return super if scope_attributes? || reflect_on_all_aggregations.any? ||
194
- columns_hash.key?(inheritance_column) && !base_class?
330
+ return super if scope_attributes?
195
331
 
196
332
  hash = args.first
333
+ return super unless Hash === hash
334
+
335
+ values = hash.values.map! { |value| value.respond_to?(:id) ? value.id : value }
336
+ return super if values.any? { |v| StatementCache.unsupported_value?(v) }
337
+
338
+ keys = hash.keys.map! do |key|
339
+ attribute_aliases[name = key.to_s] || begin
340
+ reflection = _reflect_on_association(name)
341
+ if reflection&.belongs_to? && !reflection.polymorphic?
342
+ reflection.join_foreign_key
343
+ elsif reflect_on_aggregation(name)
344
+ return super
345
+ else
346
+ name
347
+ end
348
+ end
349
+ end
197
350
 
198
- return super if !(Hash === hash) || hash.values.any? { |v|
199
- StatementCache.unsupported_value?(v)
200
- }
201
-
202
- # We can't cache Post.find_by(author: david) ...yet
203
- return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
204
-
205
- keys = hash.keys
351
+ return super unless keys.all? { |k| columns_hash.key?(k) }
206
352
 
207
353
  statement = cached_find_by_statement(keys) { |params|
208
- wheres = keys.each_with_object({}) { |param, o|
209
- o[param] = params.bind
210
- }
354
+ wheres = keys.index_with { params.bind }
211
355
  where(wheres).limit(1)
212
356
  }
357
+
213
358
  begin
214
- statement.execute(hash.values, connection)&.first
359
+ statement.execute(values, connection).first
215
360
  rescue TypeError
216
361
  raise ActiveRecord::StatementInvalid
217
362
  end
@@ -274,14 +419,13 @@ module ActiveRecord
274
419
  # scope :published_and_commented, -> { published.and(arel_table[:comments_count].gt(0)) }
275
420
  # end
276
421
  def arel_table # :nodoc:
277
- @arel_table ||= Arel::Table.new(table_name, type_caster: type_caster)
422
+ @arel_table ||= Arel::Table.new(table_name, klass: self)
278
423
  end
279
424
 
280
425
  def arel_attribute(name, table = arel_table) # :nodoc:
281
- name = name.to_s
282
- name = attribute_aliases[name] || name
283
426
  table[name]
284
427
  end
428
+ deprecate :arel_attribute
285
429
 
286
430
  def predicate_builder # :nodoc:
287
431
  @predicate_builder ||= PredicateBuilder.new(table_metadata)
@@ -409,9 +553,9 @@ module ActiveRecord
409
553
  _run_initialize_callbacks
410
554
 
411
555
  @new_record = true
556
+ @previously_new_record = false
412
557
  @destroyed = false
413
558
  @_start_transaction_state = nil
414
- @transaction_state = nil
415
559
 
416
560
  super
417
561
  end
@@ -471,7 +615,6 @@ module ActiveRecord
471
615
 
472
616
  # Returns +true+ if the attributes hash has been frozen.
473
617
  def frozen?
474
- sync_with_transaction_state if @transaction_state&.finalized?
475
618
  @attributes.frozen?
476
619
  end
477
620
 
@@ -492,12 +635,27 @@ module ActiveRecord
492
635
  false
493
636
  end
494
637
 
495
- # Returns +true+ if the record is read only. Records loaded through joins with piggy-back
496
- # attributes will be marked as read only since they cannot be saved.
638
+ # Returns +true+ if the record is read only.
497
639
  def readonly?
498
640
  @readonly
499
641
  end
500
642
 
643
+ # Returns +true+ if the record is in strict_loading mode.
644
+ def strict_loading?
645
+ @strict_loading
646
+ end
647
+
648
+ # Sets the record to strict_loading mode. This will raise an error
649
+ # if the record tries to lazily load an association.
650
+ #
651
+ # user = User.first
652
+ # user.strict_loading!
653
+ # user.comments.to_a
654
+ # => ActiveRecord::StrictLoadingViolationError
655
+ def strict_loading!
656
+ @strict_loading = true
657
+ end
658
+
501
659
  # Marks this record as read only.
502
660
  def readonly!
503
661
  @readonly = true
@@ -513,15 +671,8 @@ module ActiveRecord
513
671
  # allocated but not initialized.
514
672
  inspection = if defined?(@attributes) && @attributes
515
673
  self.class.attribute_names.collect do |name|
516
- if has_attribute?(name)
517
- attr = _read_attribute(name)
518
- value = if attr.nil?
519
- attr.inspect
520
- else
521
- attr = format_for_inspect(attr)
522
- inspection_filter.filter_param(name, attr)
523
- end
524
- "#{name}: #{value}"
674
+ if _has_attribute?(name)
675
+ "#{name}: #{attribute_for_inspect(name)}"
525
676
  end
526
677
  end.compact.join(", ")
527
678
  else
@@ -537,7 +688,7 @@ module ActiveRecord
537
688
  return super if custom_inspect_method_defined?
538
689
  pp.object_address_group(self) do
539
690
  if defined?(@attributes) && @attributes
540
- attr_names = self.class.attribute_names.select { |name| has_attribute?(name) }
691
+ attr_names = self.class.attribute_names.select { |name| _has_attribute?(name) }
541
692
  pp.seplist(attr_names, proc { pp.text "," }) do |attr_name|
542
693
  pp.breakable " "
543
694
  pp.group(1) do
@@ -558,7 +709,12 @@ module ActiveRecord
558
709
 
559
710
  # Returns a hash of the given methods with their names as keys and returned values as values.
560
711
  def slice(*methods)
561
- Hash[methods.flatten.map! { |method| [method, public_send(method)] }].with_indifferent_access
712
+ methods.flatten.index_with { |method| public_send(method) }.with_indifferent_access
713
+ end
714
+
715
+ # Returns an array of the values returned by the given methods.
716
+ def values_at(*methods)
717
+ methods.flatten.map! { |method| public_send(method) }
562
718
  end
563
719
 
564
720
  private
@@ -577,11 +733,12 @@ module ActiveRecord
577
733
  def init_internals
578
734
  @primary_key = self.class.primary_key
579
735
  @readonly = false
736
+ @previously_new_record = false
580
737
  @destroyed = false
581
738
  @marked_for_destruction = false
582
739
  @destroyed_by_association = nil
583
740
  @_start_transaction_state = nil
584
- @transaction_state = nil
741
+ @strict_loading = self.class.strict_loading_by_default
585
742
 
586
743
  self.class.define_attribute_methods
587
744
  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