activerecord 7.0.8 → 7.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (231) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1536 -1454
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +16 -16
  5. data/lib/active_record/aggregations.rb +16 -13
  6. data/lib/active_record/association_relation.rb +1 -1
  7. data/lib/active_record/associations/association.rb +20 -4
  8. data/lib/active_record/associations/association_scope.rb +16 -9
  9. data/lib/active_record/associations/belongs_to_association.rb +14 -6
  10. data/lib/active_record/associations/builder/association.rb +3 -3
  11. data/lib/active_record/associations/builder/belongs_to.rb +21 -8
  12. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
  13. data/lib/active_record/associations/builder/singular_association.rb +4 -0
  14. data/lib/active_record/associations/collection_association.rb +15 -9
  15. data/lib/active_record/associations/collection_proxy.rb +15 -10
  16. data/lib/active_record/associations/foreign_association.rb +10 -3
  17. data/lib/active_record/associations/has_many_association.rb +20 -13
  18. data/lib/active_record/associations/has_many_through_association.rb +10 -6
  19. data/lib/active_record/associations/has_one_association.rb +10 -3
  20. data/lib/active_record/associations/join_dependency.rb +10 -8
  21. data/lib/active_record/associations/preloader/association.rb +31 -7
  22. data/lib/active_record/associations/preloader.rb +13 -10
  23. data/lib/active_record/associations/singular_association.rb +1 -1
  24. data/lib/active_record/associations/through_association.rb +22 -11
  25. data/lib/active_record/associations.rb +313 -217
  26. data/lib/active_record/attribute_assignment.rb +0 -2
  27. data/lib/active_record/attribute_methods/before_type_cast.rb +17 -0
  28. data/lib/active_record/attribute_methods/dirty.rb +52 -34
  29. data/lib/active_record/attribute_methods/primary_key.rb +76 -24
  30. data/lib/active_record/attribute_methods/query.rb +28 -16
  31. data/lib/active_record/attribute_methods/read.rb +18 -5
  32. data/lib/active_record/attribute_methods/serialization.rb +150 -31
  33. data/lib/active_record/attribute_methods/write.rb +3 -3
  34. data/lib/active_record/attribute_methods.rb +105 -21
  35. data/lib/active_record/attributes.rb +3 -3
  36. data/lib/active_record/autosave_association.rb +55 -9
  37. data/lib/active_record/base.rb +7 -2
  38. data/lib/active_record/callbacks.rb +10 -24
  39. data/lib/active_record/coders/column_serializer.rb +61 -0
  40. data/lib/active_record/coders/json.rb +1 -1
  41. data/lib/active_record/coders/yaml_column.rb +70 -42
  42. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +163 -88
  43. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +2 -0
  44. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +3 -1
  45. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +74 -51
  46. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
  47. data/lib/active_record/connection_adapters/abstract/database_statements.rb +129 -31
  48. data/lib/active_record/connection_adapters/abstract/query_cache.rb +62 -23
  49. data/lib/active_record/connection_adapters/abstract/quoting.rb +41 -6
  50. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  51. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +18 -4
  52. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -11
  53. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +289 -124
  54. data/lib/active_record/connection_adapters/abstract/transaction.rb +287 -58
  55. data/lib/active_record/connection_adapters/abstract_adapter.rb +511 -91
  56. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +207 -108
  57. data/lib/active_record/connection_adapters/column.rb +9 -0
  58. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  59. data/lib/active_record/connection_adapters/mysql/database_statements.rb +22 -143
  60. data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -12
  61. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  62. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +6 -0
  63. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  64. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +18 -13
  65. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
  66. data/lib/active_record/connection_adapters/mysql2_adapter.rb +98 -53
  67. data/lib/active_record/connection_adapters/pool_config.rb +14 -5
  68. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  69. data/lib/active_record/connection_adapters/postgresql/column.rb +14 -3
  70. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +74 -40
  71. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  72. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +11 -2
  73. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +1 -1
  74. data/lib/active_record/connection_adapters/postgresql/quoting.rb +10 -6
  75. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +3 -9
  76. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -6
  77. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +131 -2
  78. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +53 -0
  79. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +361 -60
  80. data/lib/active_record/connection_adapters/postgresql_adapter.rb +353 -192
  81. data/lib/active_record/connection_adapters/schema_cache.rb +287 -59
  82. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  83. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +52 -39
  84. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +4 -3
  85. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +1 -0
  86. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +26 -7
  87. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +209 -79
  88. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  89. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  90. data/lib/active_record/connection_adapters/trilogy_adapter.rb +262 -0
  91. data/lib/active_record/connection_adapters.rb +3 -1
  92. data/lib/active_record/connection_handling.rb +72 -95
  93. data/lib/active_record/core.rb +175 -153
  94. data/lib/active_record/counter_cache.rb +46 -25
  95. data/lib/active_record/database_configurations/database_config.rb +9 -3
  96. data/lib/active_record/database_configurations/hash_config.rb +22 -12
  97. data/lib/active_record/database_configurations/url_config.rb +17 -11
  98. data/lib/active_record/database_configurations.rb +86 -33
  99. data/lib/active_record/delegated_type.rb +9 -4
  100. data/lib/active_record/deprecator.rb +7 -0
  101. data/lib/active_record/destroy_association_async_job.rb +2 -0
  102. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  103. data/lib/active_record/encryption/cipher/aes256_gcm.rb +4 -1
  104. data/lib/active_record/encryption/config.rb +25 -1
  105. data/lib/active_record/encryption/configurable.rb +12 -19
  106. data/lib/active_record/encryption/context.rb +10 -3
  107. data/lib/active_record/encryption/contexts.rb +5 -1
  108. data/lib/active_record/encryption/derived_secret_key_provider.rb +8 -2
  109. data/lib/active_record/encryption/encryptable_record.rb +42 -18
  110. data/lib/active_record/encryption/encrypted_attribute_type.rb +21 -6
  111. data/lib/active_record/encryption/extended_deterministic_queries.rb +66 -69
  112. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +3 -3
  113. data/lib/active_record/encryption/key_generator.rb +12 -1
  114. data/lib/active_record/encryption/message_serializer.rb +2 -0
  115. data/lib/active_record/encryption/properties.rb +3 -3
  116. data/lib/active_record/encryption/scheme.rb +19 -22
  117. data/lib/active_record/encryption.rb +1 -0
  118. data/lib/active_record/enum.rb +112 -28
  119. data/lib/active_record/errors.rb +112 -18
  120. data/lib/active_record/explain.rb +23 -3
  121. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  122. data/lib/active_record/fixture_set/render_context.rb +2 -0
  123. data/lib/active_record/fixture_set/table_row.rb +29 -8
  124. data/lib/active_record/fixtures.rb +135 -71
  125. data/lib/active_record/future_result.rb +31 -5
  126. data/lib/active_record/gem_version.rb +3 -3
  127. data/lib/active_record/inheritance.rb +30 -16
  128. data/lib/active_record/insert_all.rb +57 -10
  129. data/lib/active_record/integration.rb +8 -8
  130. data/lib/active_record/internal_metadata.rb +120 -30
  131. data/lib/active_record/locking/pessimistic.rb +5 -2
  132. data/lib/active_record/log_subscriber.rb +29 -12
  133. data/lib/active_record/marshalling.rb +56 -0
  134. data/lib/active_record/message_pack.rb +124 -0
  135. data/lib/active_record/middleware/database_selector/resolver.rb +4 -0
  136. data/lib/active_record/middleware/database_selector.rb +6 -8
  137. data/lib/active_record/middleware/shard_selector.rb +3 -1
  138. data/lib/active_record/migration/command_recorder.rb +104 -5
  139. data/lib/active_record/migration/compatibility.rb +139 -5
  140. data/lib/active_record/migration/default_strategy.rb +23 -0
  141. data/lib/active_record/migration/execution_strategy.rb +19 -0
  142. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  143. data/lib/active_record/migration.rb +219 -111
  144. data/lib/active_record/model_schema.rb +64 -44
  145. data/lib/active_record/nested_attributes.rb +24 -6
  146. data/lib/active_record/normalization.rb +167 -0
  147. data/lib/active_record/persistence.rb +188 -37
  148. data/lib/active_record/promise.rb +84 -0
  149. data/lib/active_record/query_cache.rb +3 -21
  150. data/lib/active_record/query_logs.rb +77 -52
  151. data/lib/active_record/query_logs_formatter.rb +41 -0
  152. data/lib/active_record/querying.rb +15 -2
  153. data/lib/active_record/railtie.rb +109 -47
  154. data/lib/active_record/railties/controller_runtime.rb +12 -6
  155. data/lib/active_record/railties/databases.rake +142 -148
  156. data/lib/active_record/railties/job_runtime.rb +23 -0
  157. data/lib/active_record/readonly_attributes.rb +32 -5
  158. data/lib/active_record/reflection.rb +174 -44
  159. data/lib/active_record/relation/batches/batch_enumerator.rb +5 -3
  160. data/lib/active_record/relation/batches.rb +190 -61
  161. data/lib/active_record/relation/calculations.rb +187 -63
  162. data/lib/active_record/relation/delegation.rb +23 -9
  163. data/lib/active_record/relation/finder_methods.rb +77 -16
  164. data/lib/active_record/relation/merger.rb +2 -0
  165. data/lib/active_record/relation/predicate_builder/association_query_value.rb +11 -2
  166. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -6
  167. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  168. data/lib/active_record/relation/predicate_builder.rb +26 -14
  169. data/lib/active_record/relation/query_attribute.rb +2 -1
  170. data/lib/active_record/relation/query_methods.rb +352 -63
  171. data/lib/active_record/relation/spawn_methods.rb +18 -1
  172. data/lib/active_record/relation.rb +91 -35
  173. data/lib/active_record/result.rb +19 -5
  174. data/lib/active_record/runtime_registry.rb +24 -1
  175. data/lib/active_record/sanitization.rb +51 -11
  176. data/lib/active_record/schema.rb +2 -3
  177. data/lib/active_record/schema_dumper.rb +46 -7
  178. data/lib/active_record/schema_migration.rb +68 -33
  179. data/lib/active_record/scoping/default.rb +15 -5
  180. data/lib/active_record/scoping/named.rb +2 -2
  181. data/lib/active_record/scoping.rb +2 -1
  182. data/lib/active_record/secure_password.rb +60 -0
  183. data/lib/active_record/secure_token.rb +21 -3
  184. data/lib/active_record/signed_id.rb +7 -5
  185. data/lib/active_record/store.rb +8 -8
  186. data/lib/active_record/suppressor.rb +3 -1
  187. data/lib/active_record/table_metadata.rb +10 -1
  188. data/lib/active_record/tasks/database_tasks.rb +127 -105
  189. data/lib/active_record/tasks/mysql_database_tasks.rb +15 -6
  190. data/lib/active_record/tasks/postgresql_database_tasks.rb +16 -13
  191. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  192. data/lib/active_record/test_fixtures.rb +113 -96
  193. data/lib/active_record/timestamp.rb +27 -15
  194. data/lib/active_record/token_for.rb +113 -0
  195. data/lib/active_record/touch_later.rb +11 -6
  196. data/lib/active_record/transactions.rb +36 -10
  197. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  198. data/lib/active_record/type/internal/timezone.rb +7 -2
  199. data/lib/active_record/type/time.rb +4 -0
  200. data/lib/active_record/validations/absence.rb +1 -1
  201. data/lib/active_record/validations/numericality.rb +5 -4
  202. data/lib/active_record/validations/presence.rb +5 -28
  203. data/lib/active_record/validations/uniqueness.rb +47 -2
  204. data/lib/active_record/validations.rb +8 -4
  205. data/lib/active_record/version.rb +1 -1
  206. data/lib/active_record.rb +121 -16
  207. data/lib/arel/errors.rb +10 -0
  208. data/lib/arel/factory_methods.rb +4 -0
  209. data/lib/arel/nodes/binary.rb +6 -1
  210. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  211. data/lib/arel/nodes/cte.rb +36 -0
  212. data/lib/arel/nodes/fragments.rb +35 -0
  213. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  214. data/lib/arel/nodes/leading_join.rb +8 -0
  215. data/lib/arel/nodes/node.rb +111 -2
  216. data/lib/arel/nodes/sql_literal.rb +6 -0
  217. data/lib/arel/nodes/table_alias.rb +4 -0
  218. data/lib/arel/nodes.rb +4 -0
  219. data/lib/arel/predications.rb +2 -0
  220. data/lib/arel/table.rb +9 -5
  221. data/lib/arel/visitors/mysql.rb +8 -1
  222. data/lib/arel/visitors/to_sql.rb +81 -17
  223. data/lib/arel/visitors/visitor.rb +2 -2
  224. data/lib/arel.rb +16 -2
  225. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  226. data/lib/rails/generators/active_record/migration.rb +3 -1
  227. data/lib/rails/generators/active_record/model/USAGE +113 -0
  228. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  229. metadata +47 -11
  230. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  231. data/lib/active_record/null_relation.rb +0 -63
@@ -6,14 +6,16 @@ module ActiveRecord
6
6
  module Tasks # :nodoc:
7
7
  class DatabaseNotSupported < StandardError; end # :nodoc:
8
8
 
9
+ # = Active Record \DatabaseTasks
10
+ #
9
11
  # ActiveRecord::Tasks::DatabaseTasks is a utility class, which encapsulates
10
12
  # logic behind common tasks used to manage database and migrations.
11
13
  #
12
- # The tasks defined here are used with Rails commands provided by Active Record.
14
+ # The tasks defined here are used with \Rails commands provided by Active Record.
13
15
  #
14
16
  # In order to use DatabaseTasks, a few config values need to be set. All the needed
15
- # config values are set by Rails already, so it's necessary to do it only if you
16
- # want to change the defaults or when you want to use Active Record outside of Rails
17
+ # config values are set by \Rails already, so it's necessary to do it only if you
18
+ # want to change the defaults or when you want to use Active Record outside of \Rails
17
19
  # (in such case after configuring the database tasks, you can also use the rake tasks
18
20
  # defined in Active Record).
19
21
  #
@@ -27,7 +29,7 @@ module ActiveRecord
27
29
  # * +seed_loader+: an object which will load seeds, it needs to respond to the +load_seed+ method.
28
30
  # * +root+: a path to the root of the application.
29
31
  #
30
- # Example usage of DatabaseTasks outside Rails could look as such:
32
+ # Example usage of DatabaseTasks outside \Rails could look as such:
31
33
  #
32
34
  # include ActiveRecord::Tasks
33
35
  # DatabaseTasks.database_configuration = YAML.load_file('my_database_config.yml')
@@ -60,20 +62,12 @@ module ActiveRecord
60
62
 
61
63
  LOCAL_HOSTS = ["127.0.0.1", "localhost"]
62
64
 
63
- def check_protected_environments!
64
- unless ENV["DISABLE_DATABASE_ENVIRONMENT_CHECK"]
65
- current = ActiveRecord::Base.connection.migration_context.current_environment
66
- stored = ActiveRecord::Base.connection.migration_context.last_stored_environment
67
-
68
- if ActiveRecord::Base.connection.migration_context.protected_environment?
69
- raise ActiveRecord::ProtectedEnvironmentError.new(stored)
70
- end
65
+ def check_protected_environments!(environment = env)
66
+ return if ENV["DISABLE_DATABASE_ENVIRONMENT_CHECK"]
71
67
 
72
- if stored && stored != current
73
- raise ActiveRecord::EnvironmentMismatchError.new(current: current, stored: stored)
74
- end
68
+ configs_for(env_name: environment).each do |db_config|
69
+ check_current_protected_environment!(db_config)
75
70
  end
76
- rescue ActiveRecord::NoDatabaseError
77
71
  end
78
72
 
79
73
  def register_task(pattern, task)
@@ -82,6 +76,7 @@ module ActiveRecord
82
76
  end
83
77
 
84
78
  register_task(/mysql/, "ActiveRecord::Tasks::MySQLDatabaseTasks")
79
+ register_task(/trilogy/, "ActiveRecord::Tasks::MySQLDatabaseTasks")
85
80
  register_task(/postgresql/, "ActiveRecord::Tasks::PostgreSQLDatabaseTasks")
86
81
  register_task(/sqlite/, "ActiveRecord::Tasks::SQLiteDatabaseTasks")
87
82
 
@@ -130,28 +125,20 @@ module ActiveRecord
130
125
  end
131
126
 
132
127
  def create_all
133
- old_pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(ActiveRecord::Base.connection_specification_name)
134
- each_local_configuration { |db_config| create(db_config) }
135
- if old_pool
136
- ActiveRecord::Base.connection_handler.establish_connection(old_pool.db_config)
128
+ each_local_configuration do |db_config|
129
+ with_temporary_connection(db_config) do
130
+ create(db_config)
131
+ end
137
132
  end
138
133
  end
139
134
 
140
- def setup_initial_database_yaml
135
+ def setup_initial_database_yaml # :nodoc:
141
136
  return {} unless defined?(Rails)
142
137
 
143
- begin
144
- Rails.application.config.load_database_yaml
145
- rescue
146
- unless ActiveRecord.suppress_multiple_database_warning
147
- $stderr.puts "Rails couldn't infer whether you are using multiple databases from your database.yml and can't generate the tasks for the non-primary databases. If you'd like to use this feature, please simplify your ERB."
148
- end
149
-
150
- {}
151
- end
138
+ Rails.application.config.load_database_yaml
152
139
  end
153
140
 
154
- def for_each(databases)
141
+ def for_each(databases) # :nodoc:
155
142
  return {} unless defined?(Rails)
156
143
 
157
144
  database_configs = ActiveRecord::DatabaseConfigurations.new(databases).configs_for(env_name: Rails.env)
@@ -166,7 +153,7 @@ module ActiveRecord
166
153
  end
167
154
  end
168
155
 
169
- def raise_for_multi_db(environment = env, command:)
156
+ def raise_for_multi_db(environment = env, command:) # :nodoc:
170
157
  db_configs = configs_for(env_name: environment)
171
158
 
172
159
  if db_configs.count > 1
@@ -182,40 +169,35 @@ module ActiveRecord
182
169
 
183
170
  def create_current(environment = env, name = nil)
184
171
  each_current_configuration(environment, name) { |db_config| create(db_config) }
185
- ActiveRecord::Base.establish_connection(environment.to_sym)
172
+
173
+ migration_class.establish_connection(environment.to_sym)
186
174
  end
187
175
 
188
176
  def prepare_all
189
177
  seed = false
190
178
 
191
179
  each_current_configuration(env) do |db_config|
192
- ActiveRecord::Base.establish_connection(db_config)
193
-
194
- begin
195
- # Skipped when no database
196
- migrate
197
-
198
- if ActiveRecord.dump_schema_after_migration
199
- dump_schema(db_config, ActiveRecord.schema_format)
180
+ with_temporary_pool(db_config) do
181
+ begin
182
+ database_initialized = migration_connection.schema_migration.table_exists?
183
+ rescue ActiveRecord::NoDatabaseError
184
+ create(db_config)
185
+ retry
200
186
  end
201
- rescue ActiveRecord::NoDatabaseError
202
- create(db_config)
203
187
 
204
- if File.exist?(schema_dump_path(db_config))
205
- load_schema(
206
- db_config,
207
- ActiveRecord.schema_format,
208
- nil
209
- )
210
- else
211
- migrate
188
+ unless database_initialized
189
+ if File.exist?(schema_dump_path(db_config))
190
+ load_schema(db_config, ActiveRecord.schema_format, nil)
191
+ end
192
+
193
+ seed = true
212
194
  end
213
195
 
214
- seed = true
196
+ migrate
197
+ dump_schema(db_config) if ActiveRecord.dump_schema_after_migration
215
198
  end
216
199
  end
217
200
 
218
- ActiveRecord::Base.establish_connection
219
201
  load_seed if seed
220
202
  end
221
203
 
@@ -240,10 +222,9 @@ module ActiveRecord
240
222
  end
241
223
 
242
224
  def truncate_tables(db_config)
243
- ActiveRecord::Base.establish_connection(db_config)
244
-
245
- connection = ActiveRecord::Base.connection
246
- connection.truncate_tables(*connection.tables)
225
+ with_temporary_connection(db_config) do |conn|
226
+ conn.truncate_tables(*conn.tables)
227
+ end
247
228
  end
248
229
  private :truncate_tables
249
230
 
@@ -254,12 +235,12 @@ module ActiveRecord
254
235
  end
255
236
 
256
237
  def migrate(version = nil)
257
- check_target_version
258
-
259
238
  scope = ENV["SCOPE"]
260
239
  verbose_was, Migration.verbose = Migration.verbose, verbose?
261
240
 
262
- Base.connection.migration_context.migrate(target_version) do |migration|
241
+ check_target_version
242
+
243
+ migration_connection.migration_context.migrate(target_version) do |migration|
263
244
  if version.blank?
264
245
  scope.blank? || scope == migration.scope
265
246
  else
@@ -269,7 +250,7 @@ module ActiveRecord
269
250
  Migration.write("No migrations ran. (using #{scope} scope)") if scope.present? && migrations_ran.empty?
270
251
  end
271
252
 
272
- ActiveRecord::Base.clear_cache!
253
+ migration_connection.schema_cache.clear!
273
254
  ensure
274
255
  Migration.verbose = verbose_was
275
256
  end
@@ -277,9 +258,9 @@ module ActiveRecord
277
258
  def db_configs_with_versions(db_configs) # :nodoc:
278
259
  db_configs_with_versions = Hash.new { |h, k| h[k] = [] }
279
260
 
280
- db_configs.each do |db_config|
281
- ActiveRecord::Base.establish_connection(db_config)
282
- versions_to_run = ActiveRecord::Base.connection.migration_context.pending_migration_versions
261
+ with_temporary_connection_for_each do |conn|
262
+ db_config = conn.pool.db_config
263
+ versions_to_run = conn.migration_context.pending_migration_versions
283
264
  target_version = ActiveRecord::Tasks::DatabaseTasks.target_version
284
265
 
285
266
  versions_to_run.each do |version|
@@ -292,22 +273,22 @@ module ActiveRecord
292
273
  end
293
274
 
294
275
  def migrate_status
295
- unless ActiveRecord::Base.connection.schema_migration.table_exists?
276
+ unless migration_connection.schema_migration.table_exists?
296
277
  Kernel.abort "Schema migrations table does not exist yet."
297
278
  end
298
279
 
299
280
  # output
300
- puts "\ndatabase: #{ActiveRecord::Base.connection_db_config.database}\n\n"
281
+ puts "\ndatabase: #{migration_connection.pool.db_config.database}\n\n"
301
282
  puts "#{'Status'.center(8)} #{'Migration ID'.ljust(14)} Migration Name"
302
283
  puts "-" * 50
303
- ActiveRecord::Base.connection.migration_context.migrations_status.each do |status, version, name|
284
+ migration_connection.migration_context.migrations_status.each do |status, version, name|
304
285
  puts "#{status.center(8)} #{version.ljust(14)} #{name}"
305
286
  end
306
287
  puts
307
288
  end
308
289
 
309
290
  def check_target_version
310
- if target_version && !(Migration::MigrationFilenameRegexp.match?(ENV["VERSION"]) || /\A\d+\z/.match?(ENV["VERSION"]))
291
+ if target_version && !Migration.valid_version_format?(ENV["VERSION"])
311
292
  raise "Invalid format of target version: `VERSION=#{ENV['VERSION']}`"
312
293
  end
313
294
  end
@@ -347,7 +328,8 @@ module ActiveRecord
347
328
 
348
329
  def purge_current(environment = env)
349
330
  each_current_configuration(environment) { |db_config| purge(db_config) }
350
- ActiveRecord::Base.establish_connection(environment.to_sym)
331
+
332
+ migration_class.establish_connection(environment.to_sym)
351
333
  end
352
334
 
353
335
  def structure_dump(configuration, *arguments)
@@ -370,7 +352,6 @@ module ActiveRecord
370
352
 
371
353
  verbose_was, Migration.verbose = Migration.verbose, verbose? && ENV["VERBOSE"]
372
354
  check_schema_file(file)
373
- ActiveRecord::Base.establish_connection(db_config)
374
355
 
375
356
  case format
376
357
  when :ruby
@@ -380,9 +361,8 @@ module ActiveRecord
380
361
  else
381
362
  raise ArgumentError, "unknown format #{format.inspect}"
382
363
  end
383
- ActiveRecord::InternalMetadata.create_table
384
- ActiveRecord::InternalMetadata[:environment] = db_config.env_name
385
- ActiveRecord::InternalMetadata[:schema_sha1] = schema_sha1(file)
364
+
365
+ migration_connection.internal_metadata.create_table_and_set_flags(db_config.env_name, schema_sha1(file))
386
366
  ensure
387
367
  Migration.verbose = verbose_was
388
368
  end
@@ -394,12 +374,12 @@ module ActiveRecord
394
374
 
395
375
  return true unless file && File.exist?(file)
396
376
 
397
- ActiveRecord::Base.establish_connection(db_config)
398
-
399
- return false unless ActiveRecord::InternalMetadata.enabled?
400
- return false unless ActiveRecord::InternalMetadata.table_exists?
377
+ with_temporary_connection(db_config) do |connection|
378
+ return false unless connection.internal_metadata.enabled?
379
+ return false unless connection.internal_metadata.table_exists?
401
380
 
402
- ActiveRecord::InternalMetadata[:schema_sha1] == schema_sha1(file)
381
+ connection.internal_metadata[:schema_sha1] == schema_sha1(file)
382
+ end
403
383
  end
404
384
 
405
385
  def reconstruct_from_schema(db_config, format = ActiveRecord.schema_format, file = nil) # :nodoc:
@@ -407,53 +387,43 @@ module ActiveRecord
407
387
 
408
388
  check_schema_file(file) if file
409
389
 
410
- ActiveRecord::Base.establish_connection(db_config)
411
-
412
- if schema_up_to_date?(db_config, format, file)
413
- truncate_tables(db_config)
414
- else
415
- purge(db_config)
390
+ with_temporary_pool(db_config, clobber: true) do
391
+ if schema_up_to_date?(db_config, format, file)
392
+ truncate_tables(db_config)
393
+ else
394
+ purge(db_config)
395
+ load_schema(db_config, format, file)
396
+ end
397
+ rescue ActiveRecord::NoDatabaseError
398
+ create(db_config)
416
399
  load_schema(db_config, format, file)
417
400
  end
418
- rescue ActiveRecord::NoDatabaseError
419
- create(db_config)
420
- load_schema(db_config, format, file)
421
401
  end
422
402
 
423
403
  def dump_schema(db_config, format = ActiveRecord.schema_format) # :nodoc:
404
+ return unless db_config.schema_dump
405
+
424
406
  require "active_record/schema_dumper"
425
407
  filename = schema_dump_path(db_config, format)
426
408
  return unless filename
427
409
 
428
- connection = ActiveRecord::Base.connection
429
-
430
410
  FileUtils.mkdir_p(db_dir)
431
411
  case format
432
412
  when :ruby
433
413
  File.open(filename, "w:utf-8") do |file|
434
- ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
414
+ ActiveRecord::SchemaDumper.dump(migration_connection, file)
435
415
  end
436
416
  when :sql
437
417
  structure_dump(db_config, filename)
438
- if connection.schema_migration.table_exists?
418
+ if migration_connection.schema_migration.table_exists?
439
419
  File.open(filename, "a") do |f|
440
- f.puts connection.dump_schema_information
420
+ f.puts migration_connection.dump_schema_information
441
421
  f.print "\n"
442
422
  end
443
423
  end
444
424
  end
445
425
  end
446
426
 
447
- def schema_file_type(format = ActiveRecord.schema_format)
448
- case format
449
- when :ruby
450
- "schema.rb"
451
- when :sql
452
- "structure.sql"
453
- end
454
- end
455
- deprecate :schema_file_type
456
-
457
427
  def schema_dump_path(db_config, format = ActiveRecord.schema_format)
458
428
  return ENV["SCHEMA"] if ENV["SCHEMA"]
459
429
 
@@ -479,9 +449,10 @@ module ActiveRecord
479
449
 
480
450
  def load_schema_current(format = ActiveRecord.schema_format, file = nil, environment = env)
481
451
  each_current_configuration(environment) do |db_config|
482
- load_schema(db_config, format, file)
452
+ with_temporary_connection(db_config) do
453
+ load_schema(db_config, format, file)
454
+ end
483
455
  end
484
- ActiveRecord::Base.establish_connection(environment.to_sym)
485
456
  end
486
457
 
487
458
  def check_schema_file(filename)
@@ -504,7 +475,7 @@ module ActiveRecord
504
475
 
505
476
  # Dumps the schema cache in YAML format for the connection into the file
506
477
  #
507
- # ==== Examples:
478
+ # ==== Examples
508
479
  # ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(ActiveRecord::Base.connection, "tmp/schema_dump.yaml")
509
480
  def dump_schema_cache(conn, filename)
510
481
  conn.schema_cache.dump_to(filename)
@@ -514,7 +485,41 @@ module ActiveRecord
514
485
  FileUtils.rm_f filename, verbose: false
515
486
  end
516
487
 
488
+ def with_temporary_connection_for_each(env: ActiveRecord::Tasks::DatabaseTasks.env, name: nil, clobber: false, &block) # :nodoc:
489
+ if name
490
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: env, name: name)
491
+ with_temporary_connection(db_config, clobber: clobber, &block)
492
+ else
493
+ ActiveRecord::Base.configurations.configs_for(env_name: env, name: name).each do |db_config|
494
+ with_temporary_connection(db_config, clobber: clobber, &block)
495
+ end
496
+ end
497
+ end
498
+
499
+ def with_temporary_connection(db_config, clobber: false) # :nodoc:
500
+ with_temporary_pool(db_config, clobber: clobber) do |pool|
501
+ yield pool.connection
502
+ end
503
+ end
504
+
505
+ def migration_class # :nodoc:
506
+ ActiveRecord::Base
507
+ end
508
+
509
+ def migration_connection # :nodoc:
510
+ migration_class.connection
511
+ end
512
+
517
513
  private
514
+ def with_temporary_pool(db_config, clobber: false)
515
+ original_db_config = migration_class.connection_db_config
516
+ pool = migration_class.connection_handler.establish_connection(db_config, clobber: clobber)
517
+
518
+ yield pool
519
+ ensure
520
+ migration_class.connection_handler.establish_connection(original_db_config, clobber: clobber)
521
+ end
522
+
518
523
  def configs_for(**options)
519
524
  Base.configurations.configs_for(**options)
520
525
  end
@@ -595,6 +600,23 @@ module ActiveRecord
595
600
  structure_load_flags
596
601
  end
597
602
  end
603
+
604
+ def check_current_protected_environment!(db_config)
605
+ with_temporary_pool(db_config) do |pool|
606
+ connection = pool.connection
607
+ current = connection.migration_context.current_environment
608
+ stored = connection.migration_context.last_stored_environment
609
+
610
+ if connection.migration_context.protected_environment?
611
+ raise ActiveRecord::ProtectedEnvironmentError.new(stored)
612
+ end
613
+
614
+ if stored && stored != current
615
+ raise ActiveRecord::EnvironmentMismatchError.new(current: current, stored: stored)
616
+ end
617
+ rescue ActiveRecord::NoDatabaseError
618
+ end
619
+ end
598
620
  end
599
621
  end
600
622
  end
@@ -5,8 +5,6 @@ module ActiveRecord
5
5
  class MySQLDatabaseTasks # :nodoc:
6
6
  ER_DB_CREATE_EXISTS = 1007
7
7
 
8
- delegate :connection, :establish_connection, to: ActiveRecord::Base
9
-
10
8
  def self.using_database_configurations?
11
9
  true
12
10
  end
@@ -19,17 +17,18 @@ module ActiveRecord
19
17
  def create
20
18
  establish_connection(configuration_hash_without_database)
21
19
  connection.create_database(db_config.database, creation_options)
22
- establish_connection(db_config)
20
+ establish_connection
23
21
  end
24
22
 
25
23
  def drop
26
- establish_connection(db_config)
24
+ establish_connection
27
25
  connection.drop_database(db_config.database)
28
26
  end
29
27
 
30
28
  def purge
31
- establish_connection(db_config)
29
+ establish_connection(configuration_hash_without_database)
32
30
  connection.recreate_database(db_config.database, creation_options)
31
+ establish_connection
33
32
  end
34
33
 
35
34
  def charset
@@ -49,6 +48,7 @@ module ActiveRecord
49
48
 
50
49
  ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
51
50
  if ignore_tables.any?
51
+ ignore_tables = connection.data_sources.select { |table| ignore_tables.any? { |pattern| pattern === table } }
52
52
  args += ignore_tables.map { |table| "--ignore-table=#{db_config.database}.#{table}" }
53
53
  end
54
54
 
@@ -70,6 +70,14 @@ module ActiveRecord
70
70
  private
71
71
  attr_reader :db_config, :configuration_hash
72
72
 
73
+ def connection
74
+ ActiveRecord::Base.connection
75
+ end
76
+
77
+ def establish_connection(config = db_config)
78
+ ActiveRecord::Base.establish_connection(config)
79
+ end
80
+
73
81
  def configuration_hash_without_database
74
82
  configuration_hash.merge(database: nil)
75
83
  end
@@ -93,7 +101,8 @@ module ActiveRecord
93
101
  sslcert: "--ssl-cert",
94
102
  sslcapath: "--ssl-capath",
95
103
  sslcipher: "--ssl-cipher",
96
- sslkey: "--ssl-key"
104
+ sslkey: "--ssl-key",
105
+ ssl_mode: "--ssl-mode"
97
106
  }.filter_map { |opt, arg| "#{arg}=#{configuration_hash[opt]}" if configuration_hash[opt] }
98
107
 
99
108
  args
@@ -9,9 +9,6 @@ module ActiveRecord
9
9
  ON_ERROR_STOP_1 = "ON_ERROR_STOP=1"
10
10
  SQL_COMMENT_BEGIN = "--"
11
11
 
12
- delegate :connection, :establish_connection, :clear_active_connections!,
13
- to: ActiveRecord::Base
14
-
15
12
  def self.using_database_configurations?
16
13
  true
17
14
  end
@@ -21,14 +18,14 @@ module ActiveRecord
21
18
  @configuration_hash = db_config.configuration_hash
22
19
  end
23
20
 
24
- def create(master_established = false)
25
- establish_master_connection unless master_established
21
+ def create(connection_already_established = false)
22
+ establish_connection(public_schema_config) unless connection_already_established
26
23
  connection.create_database(db_config.database, configuration_hash.merge(encoding: encoding))
27
- establish_connection(db_config)
24
+ establish_connection
28
25
  end
29
26
 
30
27
  def drop
31
- establish_master_connection
28
+ establish_connection(public_schema_config)
32
29
  connection.drop_database(db_config.database)
33
30
  end
34
31
 
@@ -41,7 +38,7 @@ module ActiveRecord
41
38
  end
42
39
 
43
40
  def purge
44
- clear_active_connections!
41
+ ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
45
42
  drop
46
43
  create true
47
44
  end
@@ -70,6 +67,7 @@ module ActiveRecord
70
67
 
71
68
  ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
72
69
  if ignore_tables.any?
70
+ ignore_tables = connection.data_sources.select { |table| ignore_tables.any? { |pattern| pattern === table } }
73
71
  args += ignore_tables.flat_map { |table| ["-T", table] }
74
72
  end
75
73
 
@@ -89,15 +87,20 @@ module ActiveRecord
89
87
  private
90
88
  attr_reader :db_config, :configuration_hash
91
89
 
90
+ def connection
91
+ ActiveRecord::Base.connection
92
+ end
93
+
94
+ def establish_connection(config = db_config)
95
+ ActiveRecord::Base.establish_connection(config)
96
+ end
97
+
92
98
  def encoding
93
99
  configuration_hash[:encoding] || DEFAULT_ENCODING
94
100
  end
95
101
 
96
- def establish_master_connection
97
- establish_connection configuration_hash.merge(
98
- database: "postgres",
99
- schema_search_path: "public"
100
- )
102
+ def public_schema_config
103
+ configuration_hash.merge(database: "postgres", schema_search_path: "public")
101
104
  end
102
105
 
103
106
  def psql_env
@@ -3,8 +3,6 @@
3
3
  module ActiveRecord
4
4
  module Tasks # :nodoc:
5
5
  class SQLiteDatabaseTasks # :nodoc:
6
- delegate :connection, :establish_connection, to: ActiveRecord::Base
7
-
8
6
  def self.using_database_configurations?
9
7
  true
10
8
  end
@@ -17,25 +15,26 @@ module ActiveRecord
17
15
  def create
18
16
  raise DatabaseAlreadyExists if File.exist?(db_config.database)
19
17
 
20
- establish_connection(db_config)
18
+ establish_connection
21
19
  connection
22
20
  end
23
21
 
24
22
  def drop
25
- require "pathname"
26
- path = Pathname.new(db_config.database)
27
- file = path.absolute? ? path.to_s : File.join(root, path)
28
-
23
+ db_path = db_config.database
24
+ file = File.absolute_path?(db_path) ? db_path : File.join(root, db_path)
29
25
  FileUtils.rm(file)
26
+ FileUtils.rm_f(["#{file}-shm", "#{file}-wal"])
30
27
  rescue Errno::ENOENT => error
31
28
  raise NoDatabaseError.new(error.message)
32
29
  end
33
30
 
34
31
  def purge
32
+ connection.disconnect!
35
33
  drop
36
34
  rescue NoDatabaseError
37
35
  ensure
38
36
  create
37
+ connection.reconnect!
39
38
  end
40
39
 
41
40
  def charset
@@ -49,6 +48,7 @@ module ActiveRecord
49
48
 
50
49
  ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
51
50
  if ignore_tables.any?
51
+ ignore_tables = connection.data_sources.select { |table| ignore_tables.any? { |pattern| pattern === table } }
52
52
  condition = ignore_tables.map { |table| connection.quote(table) }.join(", ")
53
53
  args << "SELECT sql FROM sqlite_master WHERE tbl_name NOT IN (#{condition}) ORDER BY tbl_name, type DESC, name"
54
54
  else
@@ -65,6 +65,14 @@ module ActiveRecord
65
65
  private
66
66
  attr_reader :db_config, :root
67
67
 
68
+ def connection
69
+ ActiveRecord::Base.connection
70
+ end
71
+
72
+ def establish_connection(config = db_config)
73
+ ActiveRecord::Base.establish_connection(config)
74
+ end
75
+
68
76
  def run_cmd(cmd, args, out)
69
77
  fail run_cmd_error(cmd, args) unless Kernel.system(cmd, *args, out: out)
70
78
  end