activerecord 6.0.0 → 6.1.7.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (270) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1413 -614
  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 +30 -10
  7. data/lib/active_record/associations/alias_tracker.rb +19 -16
  8. data/lib/active_record/associations/association.rb +55 -29
  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 +77 -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 +13 -8
  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 +120 -13
  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 +63 -44
  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 +202 -138
  50. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +87 -38
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +5 -10
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +44 -35
  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 +76 -79
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -115
  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 +32 -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 +23 -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 +30 -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 +84 -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 +40 -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 +61 -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 +219 -81
  114. data/lib/active_record/core.rb +283 -71
  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 +3 -3
  135. data/lib/active_record/inheritance.rb +40 -21
  136. data/lib/active_record/insert_all.rb +43 -10
  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 +14 -14
  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 +120 -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 +55 -17
  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 +346 -181
  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 -82
  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 +26 -73
  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 +15 -12
  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 +31 -27
  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