activerecord 6.0.1 → 6.1.7

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 (270) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1314 -633
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/active_record/aggregations.rb +5 -6
  6. data/lib/active_record/association_relation.rb +26 -15
  7. data/lib/active_record/associations/alias_tracker.rb +19 -16
  8. data/lib/active_record/associations/association.rb +55 -37
  9. data/lib/active_record/associations/association_scope.rb +19 -15
  10. data/lib/active_record/associations/belongs_to_association.rb +23 -10
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
  12. data/lib/active_record/associations/builder/association.rb +32 -5
  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 -3
  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 +38 -13
  20. data/lib/active_record/associations/collection_proxy.rb +14 -7
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -3
  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 +39 -16
  26. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  27. data/lib/active_record/associations/join_dependency.rb +73 -42
  28. data/lib/active_record/associations/preloader/association.rb +49 -25
  29. data/lib/active_record/associations/preloader/through_association.rb +2 -2
  30. data/lib/active_record/associations/preloader.rb +12 -7
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations/through_association.rb +1 -1
  33. data/lib/active_record/associations.rb +119 -12
  34. data/lib/active_record/attribute_assignment.rb +10 -9
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
  36. data/lib/active_record/attribute_methods/dirty.rb +3 -13
  37. data/lib/active_record/attribute_methods/primary_key.rb +6 -4
  38. data/lib/active_record/attribute_methods/query.rb +3 -6
  39. data/lib/active_record/attribute_methods/read.rb +8 -12
  40. data/lib/active_record/attribute_methods/serialization.rb +11 -6
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  42. data/lib/active_record/attribute_methods/write.rb +12 -21
  43. data/lib/active_record/attribute_methods.rb +64 -54
  44. data/lib/active_record/attributes.rb +33 -9
  45. data/lib/active_record/autosave_association.rb +56 -41
  46. data/lib/active_record/base.rb +2 -14
  47. data/lib/active_record/callbacks.rb +153 -24
  48. data/lib/active_record/coders/yaml_column.rb +24 -3
  49. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +190 -136
  50. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +83 -38
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -9
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  54. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +145 -52
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +267 -105
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +94 -36
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +63 -77
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +136 -111
  62. data/lib/active_record/connection_adapters/column.rb +15 -1
  63. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  64. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  65. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/database_statements.rb +30 -36
  67. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  68. data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
  69. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
  70. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  71. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
  72. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +20 -13
  73. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  74. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
  75. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  76. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +21 -56
  79. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  81. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  83. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
  87. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
  91. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
  92. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  97. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
  101. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  102. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  103. data/lib/active_record/connection_adapters/postgresql_adapter.rb +80 -66
  104. data/lib/active_record/connection_adapters/schema_cache.rb +130 -15
  105. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  106. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +38 -12
  107. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
  108. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  109. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
  110. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +57 -57
  111. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  112. data/lib/active_record/connection_adapters.rb +52 -0
  113. data/lib/active_record/connection_handling.rb +218 -87
  114. data/lib/active_record/core.rb +269 -68
  115. data/lib/active_record/counter_cache.rb +4 -1
  116. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  117. data/lib/active_record/database_configurations/database_config.rb +52 -9
  118. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  119. data/lib/active_record/database_configurations/url_config.rb +15 -41
  120. data/lib/active_record/database_configurations.rb +125 -85
  121. data/lib/active_record/delegated_type.rb +209 -0
  122. data/lib/active_record/destroy_association_async_job.rb +36 -0
  123. data/lib/active_record/dynamic_matchers.rb +2 -3
  124. data/lib/active_record/enum.rb +80 -38
  125. data/lib/active_record/errors.rb +47 -12
  126. data/lib/active_record/explain.rb +9 -5
  127. data/lib/active_record/explain_subscriber.rb +1 -1
  128. data/lib/active_record/fixture_set/file.rb +10 -17
  129. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  130. data/lib/active_record/fixture_set/render_context.rb +1 -1
  131. data/lib/active_record/fixture_set/table_row.rb +2 -3
  132. data/lib/active_record/fixture_set/table_rows.rb +0 -1
  133. data/lib/active_record/fixtures.rb +58 -12
  134. data/lib/active_record/gem_version.rb +2 -2
  135. data/lib/active_record/inheritance.rb +40 -21
  136. data/lib/active_record/insert_all.rb +42 -9
  137. data/lib/active_record/integration.rb +3 -5
  138. data/lib/active_record/internal_metadata.rb +18 -7
  139. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  140. data/lib/active_record/locking/optimistic.rb +33 -18
  141. data/lib/active_record/locking/pessimistic.rb +6 -2
  142. data/lib/active_record/log_subscriber.rb +28 -9
  143. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  144. data/lib/active_record/middleware/database_selector/resolver.rb +6 -2
  145. data/lib/active_record/middleware/database_selector.rb +4 -2
  146. data/lib/active_record/migration/command_recorder.rb +53 -45
  147. data/lib/active_record/migration/compatibility.rb +75 -21
  148. data/lib/active_record/migration/join_table.rb +0 -1
  149. data/lib/active_record/migration.rb +115 -85
  150. data/lib/active_record/model_schema.rb +117 -15
  151. data/lib/active_record/nested_attributes.rb +2 -5
  152. data/lib/active_record/no_touching.rb +1 -1
  153. data/lib/active_record/null_relation.rb +0 -1
  154. data/lib/active_record/persistence.rb +50 -46
  155. data/lib/active_record/query_cache.rb +15 -5
  156. data/lib/active_record/querying.rb +12 -7
  157. data/lib/active_record/railtie.rb +65 -45
  158. data/lib/active_record/railties/console_sandbox.rb +2 -4
  159. data/lib/active_record/railties/databases.rake +280 -99
  160. data/lib/active_record/readonly_attributes.rb +4 -0
  161. data/lib/active_record/reflection.rb +77 -63
  162. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  163. data/lib/active_record/relation/batches.rb +38 -32
  164. data/lib/active_record/relation/calculations.rb +106 -45
  165. data/lib/active_record/relation/delegation.rb +9 -7
  166. data/lib/active_record/relation/finder_methods.rb +45 -16
  167. data/lib/active_record/relation/from_clause.rb +5 -1
  168. data/lib/active_record/relation/merger.rb +27 -26
  169. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  170. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  171. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
  172. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  173. data/lib/active_record/relation/predicate_builder.rb +59 -40
  174. data/lib/active_record/relation/query_methods.rb +339 -188
  175. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  176. data/lib/active_record/relation/spawn_methods.rb +8 -8
  177. data/lib/active_record/relation/where_clause.rb +111 -62
  178. data/lib/active_record/relation.rb +116 -83
  179. data/lib/active_record/result.rb +41 -34
  180. data/lib/active_record/runtime_registry.rb +2 -2
  181. data/lib/active_record/sanitization.rb +6 -17
  182. data/lib/active_record/schema_dumper.rb +34 -4
  183. data/lib/active_record/schema_migration.rb +2 -8
  184. data/lib/active_record/scoping/default.rb +1 -4
  185. data/lib/active_record/scoping/named.rb +7 -18
  186. data/lib/active_record/scoping.rb +0 -1
  187. data/lib/active_record/secure_token.rb +16 -8
  188. data/lib/active_record/serialization.rb +5 -3
  189. data/lib/active_record/signed_id.rb +116 -0
  190. data/lib/active_record/statement_cache.rb +20 -4
  191. data/lib/active_record/store.rb +9 -4
  192. data/lib/active_record/suppressor.rb +2 -2
  193. data/lib/active_record/table_metadata.rb +42 -36
  194. data/lib/active_record/tasks/database_tasks.rb +140 -113
  195. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
  196. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
  197. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
  198. data/lib/active_record/test_databases.rb +5 -4
  199. data/lib/active_record/test_fixtures.rb +87 -20
  200. data/lib/active_record/timestamp.rb +4 -7
  201. data/lib/active_record/touch_later.rb +20 -21
  202. data/lib/active_record/transactions.rb +25 -72
  203. data/lib/active_record/type/adapter_specific_registry.rb +2 -5
  204. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  205. data/lib/active_record/type/serialized.rb +6 -3
  206. data/lib/active_record/type/time.rb +10 -0
  207. data/lib/active_record/type/type_map.rb +0 -1
  208. data/lib/active_record/type/unsigned_integer.rb +0 -1
  209. data/lib/active_record/type.rb +8 -2
  210. data/lib/active_record/type_caster/connection.rb +0 -1
  211. data/lib/active_record/type_caster/map.rb +8 -5
  212. data/lib/active_record/validations/associated.rb +1 -2
  213. data/lib/active_record/validations/numericality.rb +35 -0
  214. data/lib/active_record/validations/uniqueness.rb +24 -4
  215. data/lib/active_record/validations.rb +3 -3
  216. data/lib/active_record.rb +7 -13
  217. data/lib/arel/attributes/attribute.rb +4 -0
  218. data/lib/arel/collectors/bind.rb +5 -0
  219. data/lib/arel/collectors/composite.rb +8 -0
  220. data/lib/arel/collectors/sql_string.rb +7 -0
  221. data/lib/arel/collectors/substitute_binds.rb +7 -0
  222. data/lib/arel/nodes/binary.rb +82 -8
  223. data/lib/arel/nodes/bind_param.rb +8 -0
  224. data/lib/arel/nodes/casted.rb +21 -9
  225. data/lib/arel/nodes/equality.rb +6 -9
  226. data/lib/arel/nodes/grouping.rb +3 -0
  227. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  228. data/lib/arel/nodes/in.rb +8 -1
  229. data/lib/arel/nodes/infix_operation.rb +13 -1
  230. data/lib/arel/nodes/join_source.rb +1 -1
  231. data/lib/arel/nodes/node.rb +7 -6
  232. data/lib/arel/nodes/ordering.rb +27 -0
  233. data/lib/arel/nodes/sql_literal.rb +3 -0
  234. data/lib/arel/nodes/table_alias.rb +7 -3
  235. data/lib/arel/nodes/unary.rb +0 -1
  236. data/lib/arel/nodes.rb +3 -1
  237. data/lib/arel/predications.rb +17 -24
  238. data/lib/arel/select_manager.rb +1 -2
  239. data/lib/arel/table.rb +13 -5
  240. data/lib/arel/visitors/dot.rb +14 -3
  241. data/lib/arel/visitors/mysql.rb +11 -1
  242. data/lib/arel/visitors/postgresql.rb +15 -5
  243. data/lib/arel/visitors/sqlite.rb +0 -1
  244. data/lib/arel/visitors/to_sql.rb +89 -79
  245. data/lib/arel/visitors/visitor.rb +0 -1
  246. data/lib/arel/visitors.rb +0 -7
  247. data/lib/arel.rb +5 -9
  248. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  249. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  250. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  251. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
  252. data/lib/rails/generators/active_record/migration.rb +6 -2
  253. data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
  254. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  255. metadata +30 -29
  256. data/lib/active_record/attribute_decorators.rb +0 -90
  257. data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
  258. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  259. data/lib/active_record/define_callbacks.rb +0 -22
  260. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  261. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  262. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  263. data/lib/arel/attributes.rb +0 -22
  264. data/lib/arel/visitors/depth_first.rb +0 -204
  265. data/lib/arel/visitors/ibm_db.rb +0 -34
  266. data/lib/arel/visitors/informix.rb +0 -62
  267. data/lib/arel/visitors/mssql.rb +0 -157
  268. data/lib/arel/visitors/oracle.rb +0 -159
  269. data/lib/arel/visitors/oracle12.rb +0 -66
  270. data/lib/arel/visitors/where_sql.rb +0 -23
@@ -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 7.0.0 in favor of DatabaseConfig#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
@@ -13,14 +13,14 @@ module ActiveRecord
13
13
  # Becomes:
14
14
  #
15
15
  # #<ActiveRecord::DatabaseConfigurations::UrlConfig:0x00007fdc3238f340
16
- # @env_name="default_env", @spec_name="primary",
17
- # @config={"adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost"},
16
+ # @env_name="default_env", @name="primary",
17
+ # @config={adapter: "postgresql", database: "foo", host: "localhost"},
18
18
  # @url="postgres://localhost/foo">
19
19
  #
20
20
  # ==== Options
21
21
  #
22
22
  # * <tt>:env_name</tt> - The Rails environment, ie "development".
23
- # * <tt>:spec_name</tt> - The specification name. In a standard two-tier
23
+ # * <tt>:name</tt> - The db config name. In a standard two-tier
24
24
  # database configuration this will default to "primary". In a multiple
25
25
  # database three-tier database configuration this corresponds to the name
26
26
  # used in the second tier, for example "primary_readonly".
@@ -28,50 +28,24 @@ module ActiveRecord
28
28
  # * <tt>:config</tt> - The config hash. This is the hash that contains the
29
29
  # database adapter, name, and other important information for database
30
30
  # connections.
31
- class UrlConfig < DatabaseConfig
32
- attr_reader :url, :config
31
+ class UrlConfig < HashConfig
32
+ attr_reader :url
33
33
 
34
- def initialize(env_name, spec_name, url, config = {})
35
- super(env_name, spec_name)
36
- @config = build_config(config, url)
37
- @url = url
38
- end
39
-
40
- def url_config? # :nodoc:
41
- true
42
- end
34
+ def initialize(env_name, name, url, configuration_hash = {})
35
+ super(env_name, name, configuration_hash)
43
36
 
44
- # Determines whether a database configuration is for a replica / readonly
45
- # connection. If the +replica+ key is present in the config, +replica?+ will
46
- # return +true+.
47
- def replica?
48
- config["replica"]
49
- end
50
-
51
- # The migrations paths for a database configuration. If the
52
- # +migrations_paths+ key is present in the config, +migrations_paths+
53
- # will return its value.
54
- def migrations_paths
55
- config["migrations_paths"]
37
+ @url = url
38
+ @configuration_hash = @configuration_hash.merge(build_url_hash).freeze
56
39
  end
57
40
 
58
41
  private
59
-
60
- def build_url_hash(url)
61
- if url.nil? || /^jdbc:/.match?(url)
62
- { "url" => url }
63
- else
64
- ActiveRecord::ConnectionAdapters::ConnectionSpecification::ConnectionUrlResolver.new(url).to_hash
65
- end
66
- end
67
-
68
- def build_config(original_config, url)
69
- hash = build_url_hash(url)
70
-
71
- if original_config[env_name]
72
- original_config[env_name].merge(hash)
42
+ # Return a Hash that can be merged into the main config that represents
43
+ # the passed in url
44
+ def build_url_hash
45
+ if url.nil? || %w(jdbc: http: https:).any? { |protocol| url.start_with?(protocol) }
46
+ { url: url }
73
47
  else
74
- original_config.merge(hash)
48
+ ConnectionUrlResolver.new(url).to_hash
75
49
  end
76
50
  end
77
51
  end
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "uri"
3
4
  require "active_record/database_configurations/database_config"
4
5
  require "active_record/database_configurations/hash_config"
5
6
  require "active_record/database_configurations/url_config"
7
+ require "active_record/database_configurations/connection_url_resolver"
6
8
 
7
9
  module ActiveRecord
8
10
  # ActiveRecord::DatabaseConfigurations returns an array of DatabaseConfig
@@ -21,7 +23,7 @@ module ActiveRecord
21
23
  # Collects the configs for the environment and optionally the specification
22
24
  # name passed in. To include replica configurations pass <tt>include_replicas: true</tt>.
23
25
  #
24
- # If a spec name is provided a single DatabaseConfig object will be
26
+ # If a name is provided a single DatabaseConfig object will be
25
27
  # returned, otherwise an array of DatabaseConfig objects will be
26
28
  # returned that corresponds with the environment and type requested.
27
29
  #
@@ -29,13 +31,20 @@ module ActiveRecord
29
31
  #
30
32
  # * <tt>env_name:</tt> The environment name. Defaults to +nil+ which will collect
31
33
  # configs for all environments.
32
- # * <tt>spec_name:</tt> The specification name (i.e. primary, animals, etc.). Defaults
33
- # to +nil+.
34
+ # * <tt>name:</tt> The db config name (i.e. primary, animals, etc.). Defaults
35
+ # to +nil+. If no +env_name+ is specified the config for the default env and the
36
+ # passed +name+ will be returned.
34
37
  # * <tt>include_replicas:</tt> Determines whether to include replicas in
35
38
  # the returned list. Most of the time we're only iterating over the write
36
39
  # connection (i.e. migrations don't need to run for the write and read connection).
37
40
  # Defaults to +false+.
38
- def configs_for(env_name: nil, spec_name: nil, include_replicas: false)
41
+ def configs_for(env_name: nil, spec_name: nil, name: nil, include_replicas: false)
42
+ if spec_name
43
+ name = spec_name
44
+ ActiveSupport::Deprecation.warn("The kwarg `spec_name` is deprecated in favor of `name`. `spec_name` will be removed in Rails 7.0")
45
+ end
46
+
47
+ env_name ||= default_env if name
39
48
  configs = env_with_configs(env_name)
40
49
 
41
50
  unless include_replicas
@@ -44,9 +53,9 @@ module ActiveRecord
44
53
  end
45
54
  end
46
55
 
47
- if spec_name
56
+ if name
48
57
  configs.find do |db_config|
49
- db_config.spec_name == spec_name
58
+ db_config.name == name
50
59
  end
51
60
  else
52
61
  configs
@@ -59,31 +68,46 @@ module ActiveRecord
59
68
  # return the first config hash for the environment.
60
69
  #
61
70
  # { database: "my_db", adapter: "mysql2" }
62
- def default_hash(env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call.to_s)
71
+ def default_hash(env = default_env)
63
72
  default = find_db_config(env)
64
- default.config if default
73
+ default.configuration_hash if default
65
74
  end
66
75
  alias :[] :default_hash
76
+ deprecate "[]": "Use configs_for", default_hash: "Use configs_for"
67
77
 
68
78
  # Returns a single DatabaseConfig object based on the requested environment.
69
79
  #
70
80
  # If the application has multiple databases +find_db_config+ will return
71
81
  # the first DatabaseConfig for the environment.
72
82
  def find_db_config(env)
73
- configurations.find do |db_config|
74
- db_config.env_name == env.to_s ||
75
- (db_config.for_current_env? && db_config.spec_name == env.to_s)
76
- end
83
+ configurations
84
+ .sort_by.with_index { |db_config, i| db_config.for_current_env? ? [0, i] : [1, i] }
85
+ .find do |db_config|
86
+ db_config.env_name == env.to_s ||
87
+ (db_config.for_current_env? && db_config.name == env.to_s)
88
+ end
89
+ end
90
+
91
+ # A primary configuration is one that is named primary or if there is
92
+ # no primary, the first configuration for an environment will be treated
93
+ # as primary. This is used as the "default" configuration and is used
94
+ # when the application needs to treat one configuration differently. For
95
+ # example, when Rails dumps the schema, the primary configuration's schema
96
+ # file will be named `schema.rb` instead of `primary_schema.rb`.
97
+ def primary?(name) # :nodoc:
98
+ return true if name == "primary"
99
+
100
+ first_config = find_db_config(default_env)
101
+ first_config && name == first_config.name
77
102
  end
78
103
 
79
104
  # Returns the DatabaseConfigurations object as a Hash.
80
105
  def to_h
81
- configs = configurations.reverse.inject({}) do |memo, db_config|
82
- memo.merge(db_config.to_legacy_hash)
106
+ configurations.inject({}) do |memo, db_config|
107
+ memo.merge(db_config.env_name => db_config.configuration_hash.stringify_keys)
83
108
  end
84
-
85
- Hash[configs.to_a.reverse]
86
109
  end
110
+ deprecate to_h: "You can use `ActiveRecord::Base.configurations.configs_for(env_name: 'env', name: 'primary').configuration_hash` to get the configuration hashes."
87
111
 
88
112
  # Checks if the application's configurations are empty.
89
113
  #
@@ -93,20 +117,43 @@ module ActiveRecord
93
117
  end
94
118
  alias :blank? :empty?
95
119
 
96
- def each
97
- throw_getter_deprecation(:each)
98
- configurations.each { |config|
99
- yield [config.env_name, config.config]
100
- }
101
- end
102
-
103
- def first
104
- throw_getter_deprecation(:first)
105
- config = configurations.first
106
- [config.env_name, config.config]
120
+ # Returns fully resolved connection, accepts hash, string or symbol.
121
+ # Always returns a DatabaseConfiguration::DatabaseConfig
122
+ #
123
+ # == Examples
124
+ #
125
+ # Symbol representing current environment.
126
+ #
127
+ # DatabaseConfigurations.new("production" => {}).resolve(:production)
128
+ # # => DatabaseConfigurations::HashConfig.new(env_name: "production", config: {})
129
+ #
130
+ # One layer deep hash of connection values.
131
+ #
132
+ # DatabaseConfigurations.new({}).resolve("adapter" => "sqlite3")
133
+ # # => DatabaseConfigurations::HashConfig.new(config: {"adapter" => "sqlite3"})
134
+ #
135
+ # Connection URL.
136
+ #
137
+ # DatabaseConfigurations.new({}).resolve("postgresql://localhost/foo")
138
+ # # => DatabaseConfigurations::UrlConfig.new(config: {"adapter" => "postgresql", "host" => "localhost", "database" => "foo"})
139
+ def resolve(config) # :nodoc:
140
+ return config if DatabaseConfigurations::DatabaseConfig === config
141
+
142
+ case config
143
+ when Symbol
144
+ resolve_symbol_connection(config)
145
+ when Hash, String
146
+ build_db_config_from_raw_config(default_env, "primary", config)
147
+ else
148
+ raise TypeError, "Invalid type for configuration. Expected Symbol, String, or Hash. Got #{config.inspect}"
149
+ end
107
150
  end
108
151
 
109
152
  private
153
+ def default_env
154
+ ActiveRecord::ConnectionHandling::DEFAULT_ENV.call.to_s
155
+ end
156
+
110
157
  def env_with_configs(env = nil)
111
158
  if env
112
159
  configurations.select { |db_config| db_config.env_name == env }
@@ -127,107 +174,100 @@ module ActiveRecord
127
174
  end
128
175
  end
129
176
 
130
- current_env = ActiveRecord::ConnectionHandling::DEFAULT_ENV.call.to_s
131
-
132
177
  unless db_configs.find(&:for_current_env?)
133
- db_configs << environment_url_config(current_env, "primary", {})
178
+ db_configs << environment_url_config(default_env, "primary", {})
134
179
  end
135
180
 
136
- merge_db_environment_variables(current_env, db_configs.compact)
181
+ merge_db_environment_variables(default_env, db_configs.compact)
137
182
  end
138
183
 
139
184
  def walk_configs(env_name, config)
140
- config.map do |spec_name, sub_config|
141
- build_db_config_from_raw_config(env_name, spec_name.to_s, sub_config)
185
+ config.map do |name, sub_config|
186
+ build_db_config_from_raw_config(env_name, name.to_s, sub_config)
142
187
  end
143
188
  end
144
189
 
145
- def build_db_config_from_raw_config(env_name, spec_name, config)
190
+ def resolve_symbol_connection(name)
191
+ if db_config = find_db_config(name)
192
+ db_config
193
+ else
194
+ raise AdapterNotSpecified, <<~MSG
195
+ The `#{name}` database is not configured for the `#{default_env}` environment.
196
+
197
+ Available databases configurations are:
198
+
199
+ #{build_configuration_sentence}
200
+ MSG
201
+ end
202
+ end
203
+
204
+ def build_configuration_sentence
205
+ configs = configs_for(include_replicas: true)
206
+
207
+ configs.group_by(&:env_name).map do |env, config|
208
+ names = config.map(&:name)
209
+ if names.size > 1
210
+ "#{env}: #{names.join(", ")}"
211
+ else
212
+ env
213
+ end
214
+ end.join("\n")
215
+ end
216
+
217
+ def build_db_config_from_raw_config(env_name, name, config)
146
218
  case config
147
219
  when String
148
- build_db_config_from_string(env_name, spec_name, config)
220
+ build_db_config_from_string(env_name, name, config)
149
221
  when Hash
150
- build_db_config_from_hash(env_name, spec_name, config.stringify_keys)
222
+ build_db_config_from_hash(env_name, name, config.symbolize_keys)
151
223
  else
152
224
  raise InvalidConfigurationError, "'{ #{env_name} => #{config} }' is not a valid configuration. Expected '#{config}' to be a URL string or a Hash."
153
225
  end
154
226
  end
155
227
 
156
- def build_db_config_from_string(env_name, spec_name, config)
228
+ def build_db_config_from_string(env_name, name, config)
157
229
  url = config
158
230
  uri = URI.parse(url)
159
231
  if uri.scheme
160
- ActiveRecord::DatabaseConfigurations::UrlConfig.new(env_name, spec_name, url)
232
+ UrlConfig.new(env_name, name, url)
161
233
  else
162
234
  raise InvalidConfigurationError, "'{ #{env_name} => #{config} }' is not a valid configuration. Expected '#{config}' to be a URL string or a Hash."
163
235
  end
164
236
  end
165
237
 
166
- def build_db_config_from_hash(env_name, spec_name, config)
167
- if config.has_key?("url")
168
- url = config["url"]
238
+ def build_db_config_from_hash(env_name, name, config)
239
+ if config.has_key?(:url)
240
+ url = config[:url]
169
241
  config_without_url = config.dup
170
- config_without_url.delete "url"
242
+ config_without_url.delete :url
171
243
 
172
- ActiveRecord::DatabaseConfigurations::UrlConfig.new(env_name, spec_name, url, config_without_url)
244
+ UrlConfig.new(env_name, name, url, config_without_url)
173
245
  else
174
- ActiveRecord::DatabaseConfigurations::HashConfig.new(env_name, spec_name, config)
246
+ HashConfig.new(env_name, name, config)
175
247
  end
176
248
  end
177
249
 
178
250
  def merge_db_environment_variables(current_env, configs)
179
251
  configs.map do |config|
180
- next config if config.url_config? || config.env_name != current_env
252
+ next config if config.is_a?(UrlConfig) || config.env_name != current_env
181
253
 
182
- url_config = environment_url_config(current_env, config.spec_name, config.config)
254
+ url_config = environment_url_config(current_env, config.name, config.configuration_hash)
183
255
  url_config || config
184
256
  end
185
257
  end
186
258
 
187
- def environment_url_config(env, spec_name, config)
188
- url = environment_value_for(spec_name)
259
+ def environment_url_config(env, name, config)
260
+ url = environment_value_for(name)
189
261
  return unless url
190
262
 
191
- ActiveRecord::DatabaseConfigurations::UrlConfig.new(env, spec_name, url, config)
263
+ UrlConfig.new(env, name, url, config)
192
264
  end
193
265
 
194
- def environment_value_for(spec_name)
195
- spec_env_key = "#{spec_name.upcase}_DATABASE_URL"
196
- url = ENV[spec_env_key]
197
- url ||= ENV["DATABASE_URL"] if spec_name == "primary"
266
+ def environment_value_for(name)
267
+ name_env_key = "#{name.upcase}_DATABASE_URL"
268
+ url = ENV[name_env_key]
269
+ url ||= ENV["DATABASE_URL"] if name == "primary"
198
270
  url
199
271
  end
200
-
201
- def method_missing(method, *args, &blk)
202
- case method
203
- when :fetch
204
- throw_getter_deprecation(method)
205
- configs_for(env_name: args.first)
206
- when :values
207
- throw_getter_deprecation(method)
208
- configurations.map(&:config)
209
- when :[]=
210
- throw_setter_deprecation(method)
211
-
212
- env_name = args[0]
213
- config = args[1]
214
-
215
- remaining_configs = configurations.reject { |db_config| db_config.env_name == env_name }
216
- new_config = build_configs(env_name => config)
217
- new_configs = remaining_configs + new_config
218
-
219
- ActiveRecord::Base.configurations = new_configs
220
- else
221
- raise NotImplementedError, "`ActiveRecord::Base.configurations` in Rails 6 now returns an object instead of a hash. The `#{method}` method is not supported. Please use `configs_for` or consult the documentation for supported methods."
222
- end
223
- end
224
-
225
- def throw_setter_deprecation(method)
226
- ActiveSupport::Deprecation.warn("Setting `ActiveRecord::Base.configurations` with `#{method}` is deprecated. Use `ActiveRecord::Base.configurations=` directly to set the configurations instead.")
227
- end
228
-
229
- def throw_getter_deprecation(method)
230
- ActiveSupport::Deprecation.warn("`ActiveRecord::Base.configurations` no longer returns a hash. Methods that act on the hash like `#{method}` are deprecated and will be removed in Rails 6.1. Use the `configs_for` method to collect and iterate over the database configurations.")
231
- end
232
272
  end
233
273
  end