activerecord 6.1.7 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1516 -1019
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +17 -18
  5. data/lib/active_record/aggregations.rb +17 -14
  6. data/lib/active_record/association_relation.rb +1 -11
  7. data/lib/active_record/associations/association.rb +50 -19
  8. data/lib/active_record/associations/association_scope.rb +17 -12
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +11 -5
  12. data/lib/active_record/associations/builder/belongs_to.rb +40 -14
  13. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  14. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
  15. data/lib/active_record/associations/builder/has_many.rb +3 -2
  16. data/lib/active_record/associations/builder/has_one.rb +2 -1
  17. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  18. data/lib/active_record/associations/collection_association.rb +35 -31
  19. data/lib/active_record/associations/collection_proxy.rb +30 -15
  20. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  21. data/lib/active_record/associations/foreign_association.rb +10 -3
  22. data/lib/active_record/associations/has_many_association.rb +28 -18
  23. data/lib/active_record/associations/has_many_through_association.rb +12 -7
  24. data/lib/active_record/associations/has_one_association.rb +20 -10
  25. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  26. data/lib/active_record/associations/join_dependency.rb +26 -16
  27. data/lib/active_record/associations/preloader/association.rb +207 -52
  28. data/lib/active_record/associations/preloader/batch.rb +48 -0
  29. data/lib/active_record/associations/preloader/branch.rb +147 -0
  30. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  31. data/lib/active_record/associations/preloader.rb +50 -121
  32. data/lib/active_record/associations/singular_association.rb +9 -3
  33. data/lib/active_record/associations/through_association.rb +25 -14
  34. data/lib/active_record/associations.rb +423 -289
  35. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  36. data/lib/active_record/attribute_assignment.rb +1 -3
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  38. data/lib/active_record/attribute_methods/dirty.rb +61 -14
  39. data/lib/active_record/attribute_methods/primary_key.rb +78 -26
  40. data/lib/active_record/attribute_methods/query.rb +31 -19
  41. data/lib/active_record/attribute_methods/read.rb +25 -10
  42. data/lib/active_record/attribute_methods/serialization.rb +194 -37
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  44. data/lib/active_record/attribute_methods/write.rb +10 -13
  45. data/lib/active_record/attribute_methods.rb +121 -40
  46. data/lib/active_record/attributes.rb +27 -38
  47. data/lib/active_record/autosave_association.rb +61 -30
  48. data/lib/active_record/base.rb +25 -2
  49. data/lib/active_record/callbacks.rb +18 -34
  50. data/lib/active_record/coders/column_serializer.rb +61 -0
  51. data/lib/active_record/coders/json.rb +1 -1
  52. data/lib/active_record/coders/yaml_column.rb +70 -46
  53. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
  54. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +96 -590
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +171 -51
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +77 -27
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +360 -136
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +622 -149
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +285 -156
  69. data/lib/active_record/connection_adapters/column.rb +13 -0
  70. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  71. data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
  72. data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  76. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +38 -14
  77. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +148 -0
  78. data/lib/active_record/connection_adapters/mysql2_adapter.rb +104 -53
  79. data/lib/active_record/connection_adapters/pool_config.rb +20 -11
  80. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +18 -1
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +86 -52
  83. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  87. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  88. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  91. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
  93. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  94. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  95. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
  96. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  97. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +381 -69
  98. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  99. data/lib/active_record/connection_adapters/postgresql_adapter.rb +492 -230
  100. data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
  101. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  102. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +65 -53
  103. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
  104. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  105. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +294 -102
  107. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  108. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +98 -0
  109. data/lib/active_record/connection_adapters/trilogy_adapter.rb +254 -0
  110. data/lib/active_record/connection_adapters.rb +9 -6
  111. data/lib/active_record/connection_handling.rb +107 -136
  112. data/lib/active_record/core.rb +194 -224
  113. data/lib/active_record/counter_cache.rb +46 -25
  114. data/lib/active_record/database_configurations/connection_url_resolver.rb +2 -1
  115. data/lib/active_record/database_configurations/database_config.rb +21 -12
  116. data/lib/active_record/database_configurations/hash_config.rb +84 -16
  117. data/lib/active_record/database_configurations/url_config.rb +18 -12
  118. data/lib/active_record/database_configurations.rb +95 -59
  119. data/lib/active_record/delegated_type.rb +61 -15
  120. data/lib/active_record/deprecator.rb +7 -0
  121. data/lib/active_record/destroy_association_async_job.rb +3 -1
  122. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  123. data/lib/active_record/dynamic_matchers.rb +1 -1
  124. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  125. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  126. data/lib/active_record/encryption/cipher.rb +53 -0
  127. data/lib/active_record/encryption/config.rb +68 -0
  128. data/lib/active_record/encryption/configurable.rb +60 -0
  129. data/lib/active_record/encryption/context.rb +42 -0
  130. data/lib/active_record/encryption/contexts.rb +76 -0
  131. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  132. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  133. data/lib/active_record/encryption/encryptable_record.rb +224 -0
  134. data/lib/active_record/encryption/encrypted_attribute_type.rb +151 -0
  135. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  136. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  137. data/lib/active_record/encryption/encryptor.rb +155 -0
  138. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  139. data/lib/active_record/encryption/errors.rb +15 -0
  140. data/lib/active_record/encryption/extended_deterministic_queries.rb +172 -0
  141. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  142. data/lib/active_record/encryption/key.rb +28 -0
  143. data/lib/active_record/encryption/key_generator.rb +53 -0
  144. data/lib/active_record/encryption/key_provider.rb +46 -0
  145. data/lib/active_record/encryption/message.rb +33 -0
  146. data/lib/active_record/encryption/message_serializer.rb +92 -0
  147. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  148. data/lib/active_record/encryption/properties.rb +76 -0
  149. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  150. data/lib/active_record/encryption/scheme.rb +96 -0
  151. data/lib/active_record/encryption.rb +56 -0
  152. data/lib/active_record/enum.rb +156 -62
  153. data/lib/active_record/errors.rb +171 -15
  154. data/lib/active_record/explain.rb +23 -3
  155. data/lib/active_record/explain_registry.rb +11 -6
  156. data/lib/active_record/explain_subscriber.rb +1 -1
  157. data/lib/active_record/fixture_set/file.rb +15 -1
  158. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  159. data/lib/active_record/fixture_set/render_context.rb +2 -0
  160. data/lib/active_record/fixture_set/table_row.rb +70 -14
  161. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  162. data/lib/active_record/fixtures.rb +131 -86
  163. data/lib/active_record/future_result.rb +164 -0
  164. data/lib/active_record/gem_version.rb +3 -3
  165. data/lib/active_record/inheritance.rb +81 -29
  166. data/lib/active_record/insert_all.rb +133 -20
  167. data/lib/active_record/integration.rb +11 -10
  168. data/lib/active_record/internal_metadata.rb +117 -33
  169. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  170. data/lib/active_record/locking/optimistic.rb +36 -21
  171. data/lib/active_record/locking/pessimistic.rb +15 -6
  172. data/lib/active_record/log_subscriber.rb +52 -19
  173. data/lib/active_record/marshalling.rb +56 -0
  174. data/lib/active_record/message_pack.rb +124 -0
  175. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  176. data/lib/active_record/middleware/database_selector.rb +23 -13
  177. data/lib/active_record/middleware/shard_selector.rb +62 -0
  178. data/lib/active_record/migration/command_recorder.rb +108 -13
  179. data/lib/active_record/migration/compatibility.rb +221 -48
  180. data/lib/active_record/migration/default_strategy.rb +23 -0
  181. data/lib/active_record/migration/execution_strategy.rb +19 -0
  182. data/lib/active_record/migration/join_table.rb +1 -1
  183. data/lib/active_record/migration.rb +355 -171
  184. data/lib/active_record/model_schema.rb +116 -97
  185. data/lib/active_record/nested_attributes.rb +36 -15
  186. data/lib/active_record/no_touching.rb +3 -3
  187. data/lib/active_record/normalization.rb +159 -0
  188. data/lib/active_record/persistence.rb +405 -85
  189. data/lib/active_record/promise.rb +84 -0
  190. data/lib/active_record/query_cache.rb +3 -21
  191. data/lib/active_record/query_logs.rb +174 -0
  192. data/lib/active_record/query_logs_formatter.rb +41 -0
  193. data/lib/active_record/querying.rb +29 -6
  194. data/lib/active_record/railtie.rb +219 -43
  195. data/lib/active_record/railties/controller_runtime.rb +13 -9
  196. data/lib/active_record/railties/databases.rake +185 -249
  197. data/lib/active_record/railties/job_runtime.rb +23 -0
  198. data/lib/active_record/readonly_attributes.rb +41 -3
  199. data/lib/active_record/reflection.rb +229 -80
  200. data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
  201. data/lib/active_record/relation/batches.rb +192 -63
  202. data/lib/active_record/relation/calculations.rb +211 -90
  203. data/lib/active_record/relation/delegation.rb +27 -13
  204. data/lib/active_record/relation/finder_methods.rb +108 -51
  205. data/lib/active_record/relation/merger.rb +22 -13
  206. data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
  207. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
  208. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  209. data/lib/active_record/relation/predicate_builder.rb +27 -20
  210. data/lib/active_record/relation/query_attribute.rb +30 -12
  211. data/lib/active_record/relation/query_methods.rb +654 -127
  212. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  213. data/lib/active_record/relation/spawn_methods.rb +20 -3
  214. data/lib/active_record/relation/where_clause.rb +10 -19
  215. data/lib/active_record/relation.rb +262 -120
  216. data/lib/active_record/result.rb +37 -11
  217. data/lib/active_record/runtime_registry.rb +18 -13
  218. data/lib/active_record/sanitization.rb +65 -20
  219. data/lib/active_record/schema.rb +36 -22
  220. data/lib/active_record/schema_dumper.rb +73 -24
  221. data/lib/active_record/schema_migration.rb +68 -33
  222. data/lib/active_record/scoping/default.rb +72 -15
  223. data/lib/active_record/scoping/named.rb +5 -13
  224. data/lib/active_record/scoping.rb +65 -34
  225. data/lib/active_record/secure_password.rb +60 -0
  226. data/lib/active_record/secure_token.rb +21 -3
  227. data/lib/active_record/serialization.rb +6 -1
  228. data/lib/active_record/signed_id.rb +10 -8
  229. data/lib/active_record/store.rb +10 -10
  230. data/lib/active_record/suppressor.rb +13 -15
  231. data/lib/active_record/table_metadata.rb +16 -3
  232. data/lib/active_record/tasks/database_tasks.rb +225 -136
  233. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  234. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  235. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  236. data/lib/active_record/test_databases.rb +1 -1
  237. data/lib/active_record/test_fixtures.rb +116 -96
  238. data/lib/active_record/timestamp.rb +28 -17
  239. data/lib/active_record/token_for.rb +113 -0
  240. data/lib/active_record/touch_later.rb +11 -6
  241. data/lib/active_record/transactions.rb +48 -27
  242. data/lib/active_record/translation.rb +3 -3
  243. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  244. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  245. data/lib/active_record/type/internal/timezone.rb +7 -2
  246. data/lib/active_record/type/serialized.rb +9 -5
  247. data/lib/active_record/type/time.rb +4 -0
  248. data/lib/active_record/type/type_map.rb +17 -20
  249. data/lib/active_record/type.rb +1 -2
  250. data/lib/active_record/validations/absence.rb +1 -1
  251. data/lib/active_record/validations/associated.rb +4 -4
  252. data/lib/active_record/validations/numericality.rb +5 -4
  253. data/lib/active_record/validations/presence.rb +5 -28
  254. data/lib/active_record/validations/uniqueness.rb +51 -6
  255. data/lib/active_record/validations.rb +8 -4
  256. data/lib/active_record/version.rb +1 -1
  257. data/lib/active_record.rb +335 -32
  258. data/lib/arel/attributes/attribute.rb +0 -8
  259. data/lib/arel/crud.rb +28 -22
  260. data/lib/arel/delete_manager.rb +18 -4
  261. data/lib/arel/errors.rb +10 -0
  262. data/lib/arel/factory_methods.rb +4 -0
  263. data/lib/arel/filter_predications.rb +9 -0
  264. data/lib/arel/insert_manager.rb +2 -3
  265. data/lib/arel/nodes/and.rb +4 -0
  266. data/lib/arel/nodes/binary.rb +6 -1
  267. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  268. data/lib/arel/nodes/casted.rb +1 -1
  269. data/lib/arel/nodes/cte.rb +36 -0
  270. data/lib/arel/nodes/delete_statement.rb +12 -13
  271. data/lib/arel/nodes/filter.rb +10 -0
  272. data/lib/arel/nodes/fragments.rb +35 -0
  273. data/lib/arel/nodes/function.rb +1 -0
  274. data/lib/arel/nodes/homogeneous_in.rb +0 -8
  275. data/lib/arel/nodes/insert_statement.rb +2 -2
  276. data/lib/arel/nodes/leading_join.rb +8 -0
  277. data/lib/arel/nodes/node.rb +111 -2
  278. data/lib/arel/nodes/select_core.rb +2 -2
  279. data/lib/arel/nodes/select_statement.rb +2 -2
  280. data/lib/arel/nodes/sql_literal.rb +6 -0
  281. data/lib/arel/nodes/table_alias.rb +4 -0
  282. data/lib/arel/nodes/update_statement.rb +8 -3
  283. data/lib/arel/nodes.rb +5 -0
  284. data/lib/arel/predications.rb +13 -3
  285. data/lib/arel/select_manager.rb +10 -4
  286. data/lib/arel/table.rb +9 -6
  287. data/lib/arel/tree_manager.rb +0 -12
  288. data/lib/arel/update_manager.rb +18 -4
  289. data/lib/arel/visitors/dot.rb +80 -90
  290. data/lib/arel/visitors/mysql.rb +16 -3
  291. data/lib/arel/visitors/postgresql.rb +0 -10
  292. data/lib/arel/visitors/to_sql.rb +139 -19
  293. data/lib/arel/visitors/visitor.rb +2 -2
  294. data/lib/arel.rb +18 -3
  295. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  296. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  297. data/lib/rails/generators/active_record/migration.rb +3 -1
  298. data/lib/rails/generators/active_record/model/USAGE +113 -0
  299. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  300. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  301. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  302. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  303. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  304. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  305. metadata +92 -13
  306. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  307. data/lib/active_record/null_relation.rb +0 -67
@@ -9,9 +9,6 @@ module ActiveRecord
9
9
  ON_ERROR_STOP_1 = "ON_ERROR_STOP=1"
10
10
  SQL_COMMENT_BEGIN = "--"
11
11
 
12
- delegate :connection, :establish_connection, :clear_active_connections!,
13
- to: ActiveRecord::Base
14
-
15
12
  def self.using_database_configurations?
16
13
  true
17
14
  end
@@ -21,14 +18,14 @@ module ActiveRecord
21
18
  @configuration_hash = db_config.configuration_hash
22
19
  end
23
20
 
24
- def create(master_established = false)
25
- establish_master_connection unless master_established
21
+ def create(connection_already_established = false)
22
+ establish_connection(public_schema_config) unless connection_already_established
26
23
  connection.create_database(db_config.database, configuration_hash.merge(encoding: encoding))
27
- establish_connection(db_config)
24
+ establish_connection
28
25
  end
29
26
 
30
27
  def drop
31
- establish_master_connection
28
+ establish_connection(public_schema_config)
32
29
  connection.drop_database(db_config.database)
33
30
  end
34
31
 
@@ -41,26 +38,27 @@ module ActiveRecord
41
38
  end
42
39
 
43
40
  def purge
44
- clear_active_connections!
41
+ ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
45
42
  drop
46
43
  create true
47
44
  end
48
45
 
49
46
  def structure_dump(filename, extra_flags)
50
- set_psql_env
51
-
52
47
  search_path = \
53
- case ActiveRecord::Base.dump_schemas
48
+ case ActiveRecord.dump_schemas
54
49
  when :schema_search_path
55
50
  configuration_hash[:schema_search_path]
56
51
  when :all
57
52
  nil
58
53
  when String
59
- ActiveRecord::Base.dump_schemas
54
+ ActiveRecord.dump_schemas
60
55
  end
61
56
 
62
- args = ["--schema-only", "--no-privileges", "--no-owner", "--file", filename]
57
+ args = ["--schema-only", "--no-privileges", "--no-owner"]
58
+ args.concat(["--file", filename])
59
+
63
60
  args.concat(Array(extra_flags)) if extra_flags
61
+
64
62
  unless search_path.blank?
65
63
  args += search_path.split(",").map do |part|
66
64
  "--schema=#{part.strip}"
@@ -69,6 +67,7 @@ module ActiveRecord
69
67
 
70
68
  ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
71
69
  if ignore_tables.any?
70
+ ignore_tables = connection.data_sources.select { |table| ignore_tables.any? { |pattern| pattern === table } }
72
71
  args += ignore_tables.flat_map { |table| ["-T", table] }
73
72
  end
74
73
 
@@ -79,8 +78,7 @@ module ActiveRecord
79
78
  end
80
79
 
81
80
  def structure_load(filename, extra_flags)
82
- set_psql_env
83
- args = ["--set", ON_ERROR_STOP_1, "--quiet", "--no-psqlrc", "--file", filename]
81
+ args = ["--set", ON_ERROR_STOP_1, "--quiet", "--no-psqlrc", "--output", File::NULL, "--file", filename]
84
82
  args.concat(Array(extra_flags)) if extra_flags
85
83
  args << db_config.database
86
84
  run_cmd("psql", args, "loading")
@@ -89,26 +87,37 @@ module ActiveRecord
89
87
  private
90
88
  attr_reader :db_config, :configuration_hash
91
89
 
90
+ def connection
91
+ ActiveRecord::Base.connection
92
+ end
93
+
94
+ def establish_connection(config = db_config)
95
+ ActiveRecord::Base.establish_connection(config)
96
+ end
97
+
92
98
  def encoding
93
99
  configuration_hash[:encoding] || DEFAULT_ENCODING
94
100
  end
95
101
 
96
- def establish_master_connection
97
- establish_connection configuration_hash.merge(
98
- database: "postgres",
99
- schema_search_path: "public"
100
- )
102
+ def public_schema_config
103
+ configuration_hash.merge(database: "postgres", schema_search_path: "public")
101
104
  end
102
105
 
103
- def set_psql_env
104
- ENV["PGHOST"] = db_config.host if db_config.host
105
- ENV["PGPORT"] = configuration_hash[:port].to_s if configuration_hash[:port]
106
- ENV["PGPASSWORD"] = configuration_hash[:password].to_s if configuration_hash[:password]
107
- ENV["PGUSER"] = configuration_hash[:username].to_s if configuration_hash[:username]
106
+ def psql_env
107
+ {}.tap do |env|
108
+ env["PGHOST"] = db_config.host if db_config.host
109
+ env["PGPORT"] = configuration_hash[:port].to_s if configuration_hash[:port]
110
+ env["PGPASSWORD"] = configuration_hash[:password].to_s if configuration_hash[:password]
111
+ env["PGUSER"] = configuration_hash[:username].to_s if configuration_hash[:username]
112
+ env["PGSSLMODE"] = configuration_hash[:sslmode].to_s if configuration_hash[:sslmode]
113
+ env["PGSSLCERT"] = configuration_hash[:sslcert].to_s if configuration_hash[:sslcert]
114
+ env["PGSSLKEY"] = configuration_hash[:sslkey].to_s if configuration_hash[:sslkey]
115
+ env["PGSSLROOTCERT"] = configuration_hash[:sslrootcert].to_s if configuration_hash[:sslrootcert]
116
+ end
108
117
  end
109
118
 
110
119
  def run_cmd(cmd, args, action)
111
- fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
120
+ fail run_cmd_error(cmd, args, action) unless Kernel.system(psql_env, cmd, *args)
112
121
  end
113
122
 
114
123
  def run_cmd_error(cmd, args, action)
@@ -3,8 +3,6 @@
3
3
  module ActiveRecord
4
4
  module Tasks # :nodoc:
5
5
  class SQLiteDatabaseTasks # :nodoc:
6
- delegate :connection, :establish_connection, to: ActiveRecord::Base
7
-
8
6
  def self.using_database_configurations?
9
7
  true
10
8
  end
@@ -17,25 +15,26 @@ module ActiveRecord
17
15
  def create
18
16
  raise DatabaseAlreadyExists if File.exist?(db_config.database)
19
17
 
20
- establish_connection(db_config)
18
+ establish_connection
21
19
  connection
22
20
  end
23
21
 
24
22
  def drop
25
- require "pathname"
26
- path = Pathname.new(db_config.database)
27
- file = path.absolute? ? path.to_s : File.join(root, path)
28
-
23
+ db_path = db_config.database
24
+ file = File.absolute_path?(db_path) ? db_path : File.join(root, db_path)
29
25
  FileUtils.rm(file)
26
+ FileUtils.rm_f(["#{file}-shm", "#{file}-wal"])
30
27
  rescue Errno::ENOENT => error
31
28
  raise NoDatabaseError.new(error.message)
32
29
  end
33
30
 
34
31
  def purge
32
+ connection.disconnect!
35
33
  drop
36
34
  rescue NoDatabaseError
37
35
  ensure
38
36
  create
37
+ connection.reconnect!
39
38
  end
40
39
 
41
40
  def charset
@@ -49,6 +48,7 @@ module ActiveRecord
49
48
 
50
49
  ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
51
50
  if ignore_tables.any?
51
+ ignore_tables = connection.data_sources.select { |table| ignore_tables.any? { |pattern| pattern === table } }
52
52
  condition = ignore_tables.map { |table| connection.quote(table) }.join(", ")
53
53
  args << "SELECT sql FROM sqlite_master WHERE tbl_name NOT IN (#{condition}) ORDER BY tbl_name, type DESC, name"
54
54
  else
@@ -65,6 +65,14 @@ module ActiveRecord
65
65
  private
66
66
  attr_reader :db_config, :root
67
67
 
68
+ def connection
69
+ ActiveRecord::Base.connection
70
+ end
71
+
72
+ def establish_connection(config = db_config)
73
+ ActiveRecord::Base.establish_connection(config)
74
+ end
75
+
68
76
  def run_cmd(cmd, args, out)
69
77
  fail run_cmd_error(cmd, args) unless Kernel.system(cmd, *args, out: out)
70
78
  end
@@ -14,7 +14,7 @@ module ActiveRecord
14
14
  ActiveRecord::Base.configurations.configs_for(env_name: env_name).each do |db_config|
15
15
  db_config._database = "#{db_config.database}-#{i}"
16
16
 
17
- ActiveRecord::Tasks::DatabaseTasks.reconstruct_from_schema(db_config, ActiveRecord::Base.schema_format, nil)
17
+ ActiveRecord::Tasks::DatabaseTasks.reconstruct_from_schema(db_config, ActiveRecord.schema_format, nil)
18
18
  end
19
19
  ensure
20
20
  ActiveRecord::Base.establish_connection
@@ -17,13 +17,26 @@ module ActiveRecord
17
17
  end
18
18
 
19
19
  included do
20
- class_attribute :fixture_path, instance_writer: false
20
+ ##
21
+ # :singleton-method: fixture_paths
22
+ #
23
+ # Returns the ActiveRecord::FixtureSet collection
24
+
25
+ ##
26
+ # :singleton-method: fixture_paths=
27
+ #
28
+ # :call-seq:
29
+ # fixture_paths=(fixture_paths)
30
+ class_attribute :fixture_paths, instance_writer: false, default: []
21
31
  class_attribute :fixture_table_names, default: []
22
32
  class_attribute :fixture_class_names, default: {}
23
33
  class_attribute :use_transactional_tests, default: true
24
34
  class_attribute :use_instantiated_fixtures, default: false # true, false, or :no_instances
25
35
  class_attribute :pre_loaded_fixtures, default: false
26
36
  class_attribute :lock_threads, default: true
37
+ class_attribute :fixture_sets, default: {}
38
+
39
+ ActiveSupport.run_load_hooks(:active_record_fixtures, self)
27
40
  end
28
41
 
29
42
  module ClassMethods
@@ -39,12 +52,28 @@ module ActiveRecord
39
52
  self.fixture_class_names = fixture_class_names.merge(class_names.stringify_keys)
40
53
  end
41
54
 
55
+ def fixture_path # :nodoc:
56
+ ActiveRecord.deprecator.warn(<<~WARNING)
57
+ TestFixtures.fixture_path is deprecated and will be removed in Rails 7.2. Use .fixture_paths instead.
58
+ If multiple fixture paths have been configured with .fixture_paths, then .fixture_path will just return
59
+ the first path.
60
+ WARNING
61
+ fixture_paths.first
62
+ end
63
+
64
+ def fixture_path=(path) # :nodoc:
65
+ ActiveRecord.deprecator.warn("TestFixtures.fixture_path= is deprecated and will be removed in Rails 7.2. Use .fixture_paths= instead.")
66
+ self.fixture_paths = Array(path)
67
+ end
68
+
42
69
  def fixtures(*fixture_set_names)
43
70
  if fixture_set_names.first == :all
44
- raise StandardError, "No fixture path found. Please set `#{self}.fixture_path`." if fixture_path.blank?
45
- fixture_set_names = Dir[::File.join(fixture_path, "{**,*}/*.{yml}")].uniq
46
- fixture_set_names.reject! { |f| f.start_with?(file_fixture_path.to_s) } if defined?(file_fixture_path) && file_fixture_path
47
- fixture_set_names.map! { |f| f[fixture_path.to_s.size..-5].delete_prefix("/") }
71
+ raise StandardError, "No fixture path found. Please set `#{self}.fixture_paths`." if fixture_paths.blank?
72
+ fixture_set_names = fixture_paths.flat_map do |path|
73
+ names = Dir[::File.join(path, "{**,*}/*.{yml}")].uniq
74
+ names.reject! { |f| f.start_with?(file_fixture_path.to_s) } if defined?(file_fixture_path) && file_fixture_path
75
+ names.map! { |f| f[path.to_s.size..-5].delete_prefix("/") }
76
+ end.uniq
48
77
  else
49
78
  fixture_set_names = fixture_set_names.flatten.map(&:to_s)
50
79
  end
@@ -55,37 +84,20 @@ module ActiveRecord
55
84
 
56
85
  def setup_fixture_accessors(fixture_set_names = nil)
57
86
  fixture_set_names = Array(fixture_set_names || fixture_table_names)
58
- methods = Module.new do
87
+ unless fixture_set_names.empty?
88
+ self.fixture_sets = fixture_sets.dup
59
89
  fixture_set_names.each do |fs_name|
60
- fs_name = fs_name.to_s
61
- accessor_name = fs_name.tr("/", "_").to_sym
62
-
63
- define_method(accessor_name) do |*fixture_names|
64
- force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
65
- return_single_record = fixture_names.size == 1
66
- fixture_names = @loaded_fixtures[fs_name].fixtures.keys if fixture_names.empty?
67
-
68
- @fixture_cache[fs_name] ||= {}
69
-
70
- instances = fixture_names.map do |f_name|
71
- f_name = f_name.to_s if f_name.is_a?(Symbol)
72
- @fixture_cache[fs_name].delete(f_name) if force_reload
73
-
74
- if @loaded_fixtures[fs_name][f_name]
75
- @fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
76
- else
77
- raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
78
- end
79
- end
80
-
81
- return_single_record ? instances.first : instances
82
- end
83
- private accessor_name
90
+ key = fs_name.to_s.include?("/") ? -fs_name.to_s.tr("/", "_") : fs_name
91
+ key = -key.to_s if key.is_a?(Symbol)
92
+ fs_name = -fs_name.to_s if fs_name.is_a?(Symbol)
93
+ fixture_sets[key] = fs_name
84
94
  end
85
95
  end
86
- include methods
87
96
  end
88
97
 
98
+ # Prevents automatically wrapping each specified test in a transaction,
99
+ # to allow application logic transactions to be tested in a top-level
100
+ # (non-nested) context.
89
101
  def uses_transaction(*methods)
90
102
  @uses_transaction = [] unless defined?(@uses_transaction)
91
103
  @uses_transaction.concat methods.map(&:to_s)
@@ -97,6 +109,15 @@ module ActiveRecord
97
109
  end
98
110
  end
99
111
 
112
+ def fixture_path # :nodoc:
113
+ ActiveRecord.deprecator.warn(<<~WARNING)
114
+ TestFixtures#fixture_path is deprecated and will be removed in Rails 7.2. Use #fixture_paths instead.
115
+ If multiple fixture paths have been configured with #fixture_paths, then #fixture_path will just return
116
+ the first path.
117
+ WARNING
118
+ fixture_paths.first
119
+ end
120
+
100
121
  def run_in_transaction?
101
122
  use_transactional_tests &&
102
123
  !self.class.uses_transaction?(name)
@@ -111,7 +132,6 @@ module ActiveRecord
111
132
  @fixture_connections = []
112
133
  @@already_loaded_fixtures ||= {}
113
134
  @connection_subscriber = nil
114
- @legacy_saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
115
135
  @saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
116
136
 
117
137
  # Load fixtures once and begin transaction.
@@ -132,19 +152,18 @@ module ActiveRecord
132
152
 
133
153
  # When connections are established in the future, begin a transaction too
134
154
  @connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
135
- spec_name = payload[:spec_name] if payload.key?(:spec_name)
155
+ connection_name = payload[:connection_name] if payload.key?(:connection_name)
136
156
  shard = payload[:shard] if payload.key?(:shard)
137
- setup_shared_connection_pool if ActiveRecord::Base.legacy_connection_handling
138
157
 
139
- if spec_name
158
+ if connection_name
140
159
  begin
141
- connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name, shard: shard)
160
+ connection = ActiveRecord::Base.connection_handler.retrieve_connection(connection_name, shard: shard)
142
161
  rescue ConnectionNotEstablished
143
162
  connection = nil
144
163
  end
145
164
 
146
165
  if connection
147
- setup_shared_connection_pool unless ActiveRecord::Base.legacy_connection_handling
166
+ setup_shared_connection_pool
148
167
 
149
168
  if !@fixture_connections.include?(connection)
150
169
  connection.begin_transaction joinable: false, _lazy: false
@@ -180,13 +199,13 @@ module ActiveRecord
180
199
  ActiveRecord::FixtureSet.reset_cache
181
200
  end
182
201
 
183
- ActiveRecord::Base.clear_active_connections!
202
+ ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
184
203
  end
185
204
 
186
205
  def enlist_fixture_connections
187
206
  setup_shared_connection_pool
188
207
 
189
- ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
208
+ ActiveRecord::Base.connection_handler.connection_pool_list(:writing).map(&:connection)
190
209
  end
191
210
 
192
211
  private
@@ -197,79 +216,43 @@ module ActiveRecord
197
216
  # need to share a connection pool so that the reading connection
198
217
  # can see data in the open transaction on the writing connection.
199
218
  def setup_shared_connection_pool
200
- if ActiveRecord::Base.legacy_connection_handling
201
- writing_handler = ActiveRecord::Base.connection_handlers[ActiveRecord::Base.writing_role]
202
-
203
- ActiveRecord::Base.connection_handlers.values.each do |handler|
204
- if handler != writing_handler
205
- handler.connection_pool_names.each do |name|
206
- writing_pool_manager = writing_handler.send(:owner_to_pool_manager)[name]
207
- return unless writing_pool_manager
208
-
209
- pool_manager = handler.send(:owner_to_pool_manager)[name]
210
- @legacy_saved_pool_configs[handler][name] ||= {}
211
- pool_manager.shard_names.each do |shard_name|
212
- writing_pool_config = writing_pool_manager.get_pool_config(nil, shard_name)
213
- pool_config = pool_manager.get_pool_config(nil, shard_name)
214
- next if pool_config == writing_pool_config
215
-
216
- @legacy_saved_pool_configs[handler][name][shard_name] = pool_config
217
- pool_manager.set_pool_config(nil, shard_name, writing_pool_config)
218
- end
219
- end
220
- end
221
- end
222
- else
223
- handler = ActiveRecord::Base.connection_handler
224
-
225
- handler.connection_pool_names.each do |name|
226
- pool_manager = handler.send(:owner_to_pool_manager)[name]
227
- pool_manager.shard_names.each do |shard_name|
228
- writing_pool_config = pool_manager.get_pool_config(ActiveRecord::Base.writing_role, shard_name)
229
- @saved_pool_configs[name][shard_name] ||= {}
230
- pool_manager.role_names.each do |role|
231
- next unless pool_config = pool_manager.get_pool_config(role, shard_name)
232
- next if pool_config == writing_pool_config
233
-
234
- @saved_pool_configs[name][shard_name][role] = pool_config
235
- pool_manager.set_pool_config(role, shard_name, writing_pool_config)
236
- end
219
+ handler = ActiveRecord::Base.connection_handler
220
+
221
+ handler.connection_pool_names.each do |name|
222
+ pool_manager = handler.send(:connection_name_to_pool_manager)[name]
223
+ pool_manager.shard_names.each do |shard_name|
224
+ writing_pool_config = pool_manager.get_pool_config(ActiveRecord.writing_role, shard_name)
225
+ @saved_pool_configs[name][shard_name] ||= {}
226
+ pool_manager.role_names.each do |role|
227
+ next unless pool_config = pool_manager.get_pool_config(role, shard_name)
228
+ next if pool_config == writing_pool_config
229
+
230
+ @saved_pool_configs[name][shard_name][role] = pool_config
231
+ pool_manager.set_pool_config(role, shard_name, writing_pool_config)
237
232
  end
238
233
  end
239
234
  end
240
235
  end
241
236
 
242
237
  def teardown_shared_connection_pool
243
- if ActiveRecord::Base.legacy_connection_handling
244
- @legacy_saved_pool_configs.each_pair do |handler, names|
245
- names.each_pair do |name, shards|
246
- shards.each_pair do |shard_name, pool_config|
247
- pool_manager = handler.send(:owner_to_pool_manager)[name]
248
- pool_manager.set_pool_config(nil, shard_name, pool_config)
249
- end
250
- end
251
- end
252
- else
253
- handler = ActiveRecord::Base.connection_handler
238
+ handler = ActiveRecord::Base.connection_handler
254
239
 
255
- @saved_pool_configs.each_pair do |name, shards|
256
- pool_manager = handler.send(:owner_to_pool_manager)[name]
257
- shards.each_pair do |shard_name, roles|
258
- roles.each_pair do |role, pool_config|
259
- next unless pool_manager.get_pool_config(role, shard_name)
240
+ @saved_pool_configs.each_pair do |name, shards|
241
+ pool_manager = handler.send(:connection_name_to_pool_manager)[name]
242
+ shards.each_pair do |shard_name, roles|
243
+ roles.each_pair do |role, pool_config|
244
+ next unless pool_manager.get_pool_config(role, shard_name)
260
245
 
261
- pool_manager.set_pool_config(role, shard_name, pool_config)
262
- end
246
+ pool_manager.set_pool_config(role, shard_name, pool_config)
263
247
  end
264
248
  end
265
249
  end
266
250
 
267
- @legacy_saved_pool_configs.clear
268
251
  @saved_pool_configs.clear
269
252
  end
270
253
 
271
254
  def load_fixtures(config)
272
- ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config).index_by(&:name)
255
+ ActiveRecord::FixtureSet.create_fixtures(fixture_paths, fixture_table_names, fixture_class_names, config).index_by(&:name)
273
256
  end
274
257
 
275
258
  def instantiate_fixtures
@@ -287,5 +270,42 @@ module ActiveRecord
287
270
  def load_instances?
288
271
  use_instantiated_fixtures != :no_instances
289
272
  end
273
+
274
+ def method_missing(name, *args, **kwargs, &block)
275
+ if fs_name = fixture_sets[name.to_s]
276
+ access_fixture(fs_name, *args, **kwargs, &block)
277
+ else
278
+ super
279
+ end
280
+ end
281
+
282
+ def respond_to_missing?(name, include_private = false)
283
+ if include_private && fixture_sets.key?(name.to_s)
284
+ true
285
+ else
286
+ super
287
+ end
288
+ end
289
+
290
+ def access_fixture(fs_name, *fixture_names)
291
+ force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
292
+ return_single_record = fixture_names.size == 1
293
+
294
+ fixture_names = @loaded_fixtures[fs_name].fixtures.keys if fixture_names.empty?
295
+ @fixture_cache[fs_name] ||= {}
296
+
297
+ instances = fixture_names.map do |f_name|
298
+ f_name = f_name.to_s if f_name.is_a?(Symbol)
299
+ @fixture_cache[fs_name].delete(f_name) if force_reload
300
+
301
+ if @loaded_fixtures[fs_name][f_name]
302
+ @fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
303
+ else
304
+ raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
305
+ end
306
+ end
307
+
308
+ return_single_record ? instances.first : instances
309
+ end
290
310
  end
291
311
  end
@@ -75,9 +75,17 @@ module ActiveRecord
75
75
  end
76
76
 
77
77
  def current_time_from_proper_timezone
78
- default_timezone == :utc ? Time.now.utc : Time.now
78
+ connection.default_timezone == :utc ? Time.now.utc : Time.now
79
79
  end
80
80
 
81
+ protected
82
+ def reload_schema_from_cache(recursive = true)
83
+ @timestamp_attributes_for_create_in_model = nil
84
+ @timestamp_attributes_for_update_in_model = nil
85
+ @all_timestamp_attributes_in_model = nil
86
+ super
87
+ end
88
+
81
89
  private
82
90
  def timestamp_attributes_for_create
83
91
  ["created_at", "created_on"].map! { |name| attribute_aliases[name] || name }
@@ -86,16 +94,14 @@ module ActiveRecord
86
94
  def timestamp_attributes_for_update
87
95
  ["updated_at", "updated_on"].map! { |name| attribute_aliases[name] || name }
88
96
  end
89
-
90
- def reload_schema_from_cache
91
- @timestamp_attributes_for_create_in_model = nil
92
- @timestamp_attributes_for_update_in_model = nil
93
- @all_timestamp_attributes_in_model = nil
94
- super
95
- end
96
97
  end
97
98
 
98
99
  private
100
+ def init_internals
101
+ super
102
+ @_touch_record = nil
103
+ end
104
+
99
105
  def _create_record
100
106
  if record_timestamps
101
107
  current_time = current_time_from_proper_timezone
@@ -109,6 +115,17 @@ module ActiveRecord
109
115
  end
110
116
 
111
117
  def _update_record
118
+ record_update_timestamps
119
+
120
+ super
121
+ end
122
+
123
+ def create_or_update(touch: true, **)
124
+ @_touch_record = touch
125
+ super
126
+ end
127
+
128
+ def record_update_timestamps
112
129
  if @_touch_record && should_record_timestamps?
113
130
  current_time = current_time_from_proper_timezone
114
131
 
@@ -118,16 +135,11 @@ module ActiveRecord
118
135
  end
119
136
  end
120
137
 
121
- super
122
- end
123
-
124
- def create_or_update(touch: true, **)
125
- @_touch_record = touch
126
- super
138
+ yield if block_given?
127
139
  end
128
140
 
129
141
  def should_record_timestamps?
130
- record_timestamps && (!partial_writes? || has_changes_to_save?)
142
+ record_timestamps && (!partial_updates? || has_changes_to_save?)
131
143
  end
132
144
 
133
145
  def timestamp_attributes_for_create_in_model
@@ -148,8 +160,7 @@ module ActiveRecord
148
160
 
149
161
  def max_updated_column_timestamp
150
162
  timestamp_attributes_for_update_in_model
151
- .map { |attr| self[attr]&.to_time }
152
- .compact
163
+ .filter_map { |attr| self[attr]&.to_time }
153
164
  .max
154
165
  end
155
166