activerecord 6.0.6.1 → 6.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

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