activerecord 6.1.7.10 → 7.0.0.alpha1

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 (220) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +726 -1404
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/association_relation.rb +0 -10
  7. data/lib/active_record/associations/association.rb +31 -9
  8. data/lib/active_record/associations/association_scope.rb +1 -3
  9. data/lib/active_record/associations/belongs_to_association.rb +15 -4
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +8 -2
  12. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  13. data/lib/active_record/associations/builder/collection_association.rb +1 -1
  14. data/lib/active_record/associations/builder/has_many.rb +3 -2
  15. data/lib/active_record/associations/builder/has_one.rb +2 -1
  16. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  17. data/lib/active_record/associations/collection_association.rb +14 -23
  18. data/lib/active_record/associations/collection_proxy.rb +8 -3
  19. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  20. data/lib/active_record/associations/has_many_association.rb +1 -1
  21. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  22. data/lib/active_record/associations/has_one_association.rb +10 -7
  23. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  24. data/lib/active_record/associations/preloader/association.rb +161 -47
  25. data/lib/active_record/associations/preloader/batch.rb +51 -0
  26. data/lib/active_record/associations/preloader/branch.rb +147 -0
  27. data/lib/active_record/associations/preloader/through_association.rb +37 -11
  28. data/lib/active_record/associations/preloader.rb +46 -110
  29. data/lib/active_record/associations/singular_association.rb +8 -2
  30. data/lib/active_record/associations/through_association.rb +1 -1
  31. data/lib/active_record/associations.rb +76 -81
  32. data/lib/active_record/asynchronous_queries_tracker.rb +57 -0
  33. data/lib/active_record/attribute_assignment.rb +1 -1
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  35. data/lib/active_record/attribute_methods/dirty.rb +41 -16
  36. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  37. data/lib/active_record/attribute_methods/query.rb +2 -2
  38. data/lib/active_record/attribute_methods/read.rb +7 -5
  39. data/lib/active_record/attribute_methods/serialization.rb +66 -12
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  41. data/lib/active_record/attribute_methods/write.rb +7 -10
  42. data/lib/active_record/attribute_methods.rb +6 -9
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +3 -18
  45. data/lib/active_record/base.rb +19 -1
  46. data/lib/active_record/callbacks.rb +2 -2
  47. data/lib/active_record/coders/yaml_column.rb +2 -14
  48. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +312 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +31 -558
  52. data/lib/active_record/connection_adapters/abstract/database_statements.rb +45 -21
  53. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  54. data/lib/active_record/connection_adapters/abstract/quoting.rb +12 -14
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +3 -3
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +112 -66
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
  61. data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -23
  62. data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
  63. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
  64. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  65. data/lib/active_record/connection_adapters/pool_config.rb +1 -3
  66. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -14
  67. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  68. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  69. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  70. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  71. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
  73. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  74. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  75. data/lib/active_record/connection_adapters/postgresql/quoting.rb +6 -32
  76. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
  77. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
  78. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
  79. data/lib/active_record/connection_adapters/postgresql_adapter.rb +159 -102
  80. data/lib/active_record/connection_adapters/schema_cache.rb +36 -37
  81. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -19
  82. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
  83. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
  84. data/lib/active_record/connection_adapters.rb +6 -5
  85. data/lib/active_record/connection_handling.rb +20 -38
  86. data/lib/active_record/core.rb +111 -125
  87. data/lib/active_record/database_configurations/connection_url_resolver.rb +0 -1
  88. data/lib/active_record/database_configurations/database_config.rb +12 -0
  89. data/lib/active_record/database_configurations/hash_config.rb +27 -1
  90. data/lib/active_record/database_configurations/url_config.rb +2 -2
  91. data/lib/active_record/database_configurations.rb +17 -9
  92. data/lib/active_record/delegated_type.rb +33 -11
  93. data/lib/active_record/destroy_association_async_job.rb +1 -1
  94. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  95. data/lib/active_record/dynamic_matchers.rb +1 -1
  96. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  97. data/lib/active_record/encryption/cipher.rb +53 -0
  98. data/lib/active_record/encryption/config.rb +44 -0
  99. data/lib/active_record/encryption/configurable.rb +61 -0
  100. data/lib/active_record/encryption/context.rb +35 -0
  101. data/lib/active_record/encryption/contexts.rb +72 -0
  102. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  103. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  104. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  105. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  106. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  107. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  108. data/lib/active_record/encryption/encryptor.rb +155 -0
  109. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  110. data/lib/active_record/encryption/errors.rb +15 -0
  111. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  112. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +29 -0
  113. data/lib/active_record/encryption/key.rb +28 -0
  114. data/lib/active_record/encryption/key_generator.rb +42 -0
  115. data/lib/active_record/encryption/key_provider.rb +46 -0
  116. data/lib/active_record/encryption/message.rb +33 -0
  117. data/lib/active_record/encryption/message_serializer.rb +80 -0
  118. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  119. data/lib/active_record/encryption/properties.rb +76 -0
  120. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  121. data/lib/active_record/encryption/scheme.rb +99 -0
  122. data/lib/active_record/encryption.rb +55 -0
  123. data/lib/active_record/enum.rb +41 -41
  124. data/lib/active_record/errors.rb +66 -3
  125. data/lib/active_record/fixture_set/file.rb +15 -1
  126. data/lib/active_record/fixture_set/table_row.rb +40 -5
  127. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  128. data/lib/active_record/fixtures.rb +16 -11
  129. data/lib/active_record/future_result.rb +139 -0
  130. data/lib/active_record/gem_version.rb +4 -4
  131. data/lib/active_record/inheritance.rb +55 -17
  132. data/lib/active_record/insert_all.rb +34 -5
  133. data/lib/active_record/integration.rb +1 -1
  134. data/lib/active_record/internal_metadata.rb +1 -5
  135. data/lib/active_record/locking/optimistic.rb +10 -9
  136. data/lib/active_record/log_subscriber.rb +6 -2
  137. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  138. data/lib/active_record/middleware/database_selector.rb +8 -3
  139. data/lib/active_record/migration/command_recorder.rb +4 -4
  140. data/lib/active_record/migration/compatibility.rb +89 -10
  141. data/lib/active_record/migration/join_table.rb +1 -1
  142. data/lib/active_record/migration.rb +109 -79
  143. data/lib/active_record/model_schema.rb +45 -31
  144. data/lib/active_record/nested_attributes.rb +3 -3
  145. data/lib/active_record/no_touching.rb +2 -2
  146. data/lib/active_record/null_relation.rb +2 -6
  147. data/lib/active_record/persistence.rb +134 -45
  148. data/lib/active_record/query_cache.rb +2 -2
  149. data/lib/active_record/query_logs.rb +203 -0
  150. data/lib/active_record/querying.rb +15 -5
  151. data/lib/active_record/railtie.rb +117 -17
  152. data/lib/active_record/railties/controller_runtime.rb +1 -1
  153. data/lib/active_record/railties/databases.rake +72 -48
  154. data/lib/active_record/readonly_attributes.rb +11 -0
  155. data/lib/active_record/reflection.rb +45 -44
  156. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  157. data/lib/active_record/relation/batches.rb +3 -3
  158. data/lib/active_record/relation/calculations.rb +39 -26
  159. data/lib/active_record/relation/delegation.rb +6 -6
  160. data/lib/active_record/relation/finder_methods.rb +31 -22
  161. data/lib/active_record/relation/merger.rb +20 -13
  162. data/lib/active_record/relation/predicate_builder.rb +1 -6
  163. data/lib/active_record/relation/query_attribute.rb +5 -11
  164. data/lib/active_record/relation/query_methods.rb +230 -49
  165. data/lib/active_record/relation/record_fetch_warning.rb +2 -2
  166. data/lib/active_record/relation/spawn_methods.rb +2 -2
  167. data/lib/active_record/relation/where_clause.rb +8 -4
  168. data/lib/active_record/relation.rb +166 -77
  169. data/lib/active_record/result.rb +17 -2
  170. data/lib/active_record/runtime_registry.rb +2 -4
  171. data/lib/active_record/sanitization.rb +11 -7
  172. data/lib/active_record/schema_dumper.rb +3 -3
  173. data/lib/active_record/schema_migration.rb +0 -4
  174. data/lib/active_record/scoping/default.rb +61 -12
  175. data/lib/active_record/scoping/named.rb +3 -11
  176. data/lib/active_record/scoping.rb +40 -22
  177. data/lib/active_record/serialization.rb +1 -1
  178. data/lib/active_record/signed_id.rb +1 -1
  179. data/lib/active_record/store.rb +1 -6
  180. data/lib/active_record/tasks/database_tasks.rb +106 -22
  181. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  182. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
  183. data/lib/active_record/test_databases.rb +1 -1
  184. data/lib/active_record/test_fixtures.rb +9 -13
  185. data/lib/active_record/timestamp.rb +3 -4
  186. data/lib/active_record/transactions.rb +9 -14
  187. data/lib/active_record/translation.rb +2 -2
  188. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  189. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  190. data/lib/active_record/type/internal/timezone.rb +2 -2
  191. data/lib/active_record/type/serialized.rb +1 -1
  192. data/lib/active_record/type/type_map.rb +17 -20
  193. data/lib/active_record/type.rb +1 -2
  194. data/lib/active_record/validations/associated.rb +1 -1
  195. data/lib/active_record.rb +170 -2
  196. data/lib/arel/attributes/attribute.rb +0 -8
  197. data/lib/arel/crud.rb +18 -22
  198. data/lib/arel/delete_manager.rb +2 -4
  199. data/lib/arel/insert_manager.rb +2 -3
  200. data/lib/arel/nodes/casted.rb +1 -1
  201. data/lib/arel/nodes/delete_statement.rb +8 -13
  202. data/lib/arel/nodes/insert_statement.rb +2 -2
  203. data/lib/arel/nodes/select_core.rb +2 -2
  204. data/lib/arel/nodes/select_statement.rb +2 -2
  205. data/lib/arel/nodes/update_statement.rb +3 -2
  206. data/lib/arel/predications.rb +1 -1
  207. data/lib/arel/select_manager.rb +10 -4
  208. data/lib/arel/table.rb +0 -1
  209. data/lib/arel/tree_manager.rb +0 -12
  210. data/lib/arel/update_manager.rb +2 -4
  211. data/lib/arel/visitors/dot.rb +80 -90
  212. data/lib/arel/visitors/mysql.rb +6 -1
  213. data/lib/arel/visitors/postgresql.rb +0 -10
  214. data/lib/arel/visitors/to_sql.rb +43 -2
  215. data/lib/arel.rb +1 -1
  216. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  217. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  218. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  219. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  220. metadata +52 -14
@@ -11,8 +11,6 @@ module ActiveRecord
11
11
 
12
12
  def write_query?(sql) # :nodoc:
13
13
  !READ_QUERY.match?(sql)
14
- rescue ArgumentError # Invalid encoding
15
- !READ_QUERY.match?(sql.b)
16
14
  end
17
15
 
18
16
  def explain(arel, binds = [])
@@ -20,10 +18,9 @@ module ActiveRecord
20
18
  SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
21
19
  end
22
20
 
23
- def execute(sql, name = nil) #:nodoc:
24
- if preventing_writes? && write_query?(sql)
25
- raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
26
- end
21
+ def execute(sql, name = nil) # :nodoc:
22
+ sql = transform_query(sql)
23
+ check_if_write_query(sql)
27
24
 
28
25
  materialize_transactions
29
26
  mark_transaction_written_if_write(sql)
@@ -35,17 +32,16 @@ module ActiveRecord
35
32
  end
36
33
  end
37
34
 
38
- def exec_query(sql, name = nil, binds = [], prepare: false)
39
- if preventing_writes? && write_query?(sql)
40
- raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
41
- end
35
+ def exec_query(sql, name = nil, binds = [], prepare: false, async: false) # :nodoc:
36
+ sql = transform_query(sql)
37
+ check_if_write_query(sql)
42
38
 
43
39
  materialize_transactions
44
40
  mark_transaction_written_if_write(sql)
45
41
 
46
42
  type_casted_binds = type_casted_binds(binds)
47
43
 
48
- log(sql, name, binds, type_casted_binds) do
44
+ log(sql, name, binds, type_casted_binds, async: async) do
49
45
  ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
50
46
  # Don't cache statements if they are not prepared
51
47
  unless prepare
@@ -72,13 +68,13 @@ module ActiveRecord
72
68
  end
73
69
  end
74
70
 
75
- def exec_delete(sql, name = "SQL", binds = [])
71
+ def exec_delete(sql, name = "SQL", binds = []) # :nodoc:
76
72
  exec_query(sql, name, binds)
77
73
  @connection.changes
78
74
  end
79
75
  alias :exec_update :exec_delete
80
76
 
81
- def begin_isolated_db_transaction(isolation) #:nodoc
77
+ def begin_isolated_db_transaction(isolation) # :nodoc:
82
78
  raise TransactionIsolationError, "SQLite3 only supports the `read_uncommitted` transaction isolation level" if isolation != :read_uncommitted
83
79
  raise StandardError, "You need to enable the shared-cache mode in SQLite mode before attempting to change the transaction isolation level" unless shared_cache?
84
80
 
@@ -87,20 +83,29 @@ module ActiveRecord
87
83
  begin_db_transaction
88
84
  end
89
85
 
90
- def begin_db_transaction #:nodoc:
86
+ def begin_db_transaction # :nodoc:
91
87
  log("begin transaction", "TRANSACTION") { @connection.transaction }
92
88
  end
93
89
 
94
- def commit_db_transaction #:nodoc:
90
+ def commit_db_transaction # :nodoc:
95
91
  log("commit transaction", "TRANSACTION") { @connection.commit }
96
92
  reset_read_uncommitted
97
93
  end
98
94
 
99
- def exec_rollback_db_transaction #:nodoc:
95
+ def exec_rollback_db_transaction # :nodoc:
100
96
  log("rollback transaction", "TRANSACTION") { @connection.rollback }
101
97
  reset_read_uncommitted
102
98
  end
103
99
 
100
+ # https://stackoverflow.com/questions/17574784
101
+ # https://www.sqlite.org/lang_datefunc.html
102
+ HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')").freeze # :nodoc:
103
+ private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
104
+
105
+ def high_precision_current_timestamp
106
+ HIGH_PRECISION_CURRENT_TIMESTAMP
107
+ end
108
+
104
109
  private
105
110
  def reset_read_uncommitted
106
111
  read_uncommitted = Thread.current.thread_variable_get("read_uncommitted")
@@ -110,11 +115,10 @@ module ActiveRecord
110
115
  end
111
116
 
112
117
  def execute_batch(statements, name = nil)
118
+ statements = statements.map { |sql| transform_query(sql) }
113
119
  sql = combine_multi_statements(statements)
114
120
 
115
- if preventing_writes? && write_query?(sql)
116
- raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
117
- end
121
+ check_if_write_query(sql)
118
122
 
119
123
  materialize_transactions
120
124
  mark_transaction_written_if_write(sql)
@@ -6,7 +6,7 @@ module ActiveRecord
6
6
  module SchemaStatements # :nodoc:
7
7
  # Returns an array of indexes for the given table.
8
8
  def indexes(table_name)
9
- exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").map do |row|
9
+ exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").filter_map do |row|
10
10
  # Indexes SQLite creates implicitly for internal use start with "sqlite_".
11
11
  # See https://www.sqlite.org/fileformat2.html#intschema
12
12
  next if row["name"].start_with?("sqlite_")
@@ -49,7 +49,7 @@ module ActiveRecord
49
49
  where: where,
50
50
  orders: orders
51
51
  )
52
- end.compact
52
+ end
53
53
  end
54
54
 
55
55
  def add_foreign_key(from_table, to_table, **options)
@@ -60,6 +60,8 @@ module ActiveRecord
60
60
  end
61
61
 
62
62
  def remove_foreign_key(from_table, to_table = nil, **options)
63
+ return if options[:if_exists] == true && !foreign_key_exists?(from_table, to_table)
64
+
63
65
  to_table ||= options[:to_table]
64
66
  options = options.except(:name, :to_table, :validate)
65
67
  foreign_keys = foreign_keys(from_table)
@@ -47,7 +47,7 @@ module ActiveRecord
47
47
  end
48
48
  end
49
49
 
50
- module ConnectionAdapters #:nodoc:
50
+ module ConnectionAdapters # :nodoc:
51
51
  # The SQLite3 adapter works with the sqlite3-ruby drivers
52
52
  # (available as gem from https://rubygems.org/gems/sqlite3).
53
53
  #
@@ -84,6 +84,7 @@ module ActiveRecord
84
84
  end
85
85
 
86
86
  def initialize(connection, logger, connection_options, config)
87
+ @memory_database = config[:database] == ":memory:"
87
88
  super(connection, logger, config)
88
89
  configure_connection
89
90
  end
@@ -153,6 +154,10 @@ module ActiveRecord
153
154
  alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
154
155
  alias supports_insert_conflict_target? supports_insert_on_conflict?
155
156
 
157
+ def supports_concurrent_connections?
158
+ !@memory_database
159
+ end
160
+
156
161
  def active?
157
162
  !@connection.closed?
158
163
  end
@@ -173,11 +178,11 @@ module ActiveRecord
173
178
  true
174
179
  end
175
180
 
176
- def native_database_types #:nodoc:
181
+ def native_database_types # :nodoc:
177
182
  NATIVE_DATABASE_TYPES
178
183
  end
179
184
 
180
- # Returns the current database encoding format as a string, eg: 'UTF-8'
185
+ # Returns the current database encoding format as a string, e.g. 'UTF-8'
181
186
  def encoding
182
187
  @connection.encoding.to_s
183
188
  end
@@ -206,6 +211,10 @@ module ActiveRecord
206
211
  end
207
212
  end
208
213
 
214
+ def all_foreign_keys_valid? # :nodoc:
215
+ execute("PRAGMA foreign_key_check").blank?
216
+ end
217
+
209
218
  # SCHEMA STATEMENTS ========================================
210
219
 
211
220
  def primary_keys(table_name) # :nodoc:
@@ -232,7 +241,7 @@ module ActiveRecord
232
241
  rename_table_indexes(table_name, new_name)
233
242
  end
234
243
 
235
- def add_column(table_name, column_name, type, **options) #:nodoc:
244
+ def add_column(table_name, column_name, type, **options) # :nodoc:
236
245
  if invalid_alter_table_type?(type, options)
237
246
  alter_table(table_name) do |definition|
238
247
  definition.column(column_name, type, **options)
@@ -242,16 +251,24 @@ module ActiveRecord
242
251
  end
243
252
  end
244
253
 
245
- def remove_column(table_name, column_name, type = nil, **options) #:nodoc:
254
+ def remove_column(table_name, column_name, type = nil, **options) # :nodoc:
246
255
  alter_table(table_name) do |definition|
247
256
  definition.remove_column column_name
248
- definition.foreign_keys.delete_if do |_, fk_options|
249
- fk_options[:column] == column_name.to_s
257
+ definition.foreign_keys.delete_if { |fk| fk.column == column_name.to_s }
258
+ end
259
+ end
260
+
261
+ def remove_columns(table_name, *column_names, type: nil, **options) # :nodoc:
262
+ alter_table(table_name) do |definition|
263
+ column_names.each do |column_name|
264
+ definition.remove_column column_name
250
265
  end
266
+ column_names = column_names.map(&:to_s)
267
+ definition.foreign_keys.delete_if { |fk| column_names.include?(fk.column) }
251
268
  end
252
269
  end
253
270
 
254
- def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
271
+ def change_column_default(table_name, column_name, default_or_changes) # :nodoc:
255
272
  default = extract_new_default_value(default_or_changes)
256
273
 
257
274
  alter_table(table_name) do |definition|
@@ -259,7 +276,7 @@ module ActiveRecord
259
276
  end
260
277
  end
261
278
 
262
- def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
279
+ def change_column_null(table_name, column_name, null, default = nil) # :nodoc:
263
280
  unless null || default.nil?
264
281
  exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
265
282
  end
@@ -268,7 +285,7 @@ module ActiveRecord
268
285
  end
269
286
  end
270
287
 
271
- def change_column(table_name, column_name, type, **options) #:nodoc:
288
+ def change_column(table_name, column_name, type, **options) # :nodoc:
272
289
  alter_table(table_name) do |definition|
273
290
  definition[column_name].instance_eval do
274
291
  self.type = aliased_types(type.to_s, type)
@@ -277,7 +294,7 @@ module ActiveRecord
277
294
  end
278
295
  end
279
296
 
280
- def rename_column(table_name, column_name, new_column_name) #:nodoc:
297
+ def rename_column(table_name, column_name, new_column_name) # :nodoc:
281
298
  column = column_for(table_name, column_name)
282
299
  alter_table(table_name, rename: { column.name => new_column_name.to_s })
283
300
  rename_column_indexes(table_name, column.name, new_column_name)
@@ -308,8 +325,12 @@ module ActiveRecord
308
325
  sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
309
326
  elsif insert.update_duplicates?
310
327
  sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
311
- sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
312
- sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
328
+ if insert.raw_update_sql?
329
+ sql << insert.raw_update_sql
330
+ else
331
+ sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
332
+ sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
333
+ end
313
334
  end
314
335
 
315
336
  sql
@@ -329,18 +350,38 @@ module ActiveRecord
329
350
  end
330
351
  end
331
352
 
353
+ class SQLite3Integer < Type::Integer # :nodoc:
354
+ private
355
+ def _limit
356
+ # INTEGER storage class can be stored 8 bytes value.
357
+ # See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
358
+ limit || 8
359
+ end
360
+ end
361
+
362
+ ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
363
+
364
+ class << self
365
+ private
366
+ def initialize_type_map(m)
367
+ super
368
+ register_class_with_limit m, %r(int)i, SQLite3Integer
369
+ end
370
+ end
371
+
372
+ TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
373
+
332
374
  private
375
+ def type_map
376
+ TYPE_MAP
377
+ end
378
+
333
379
  # See https://www.sqlite.org/limits.html,
334
380
  # the default value is 999 when not configured.
335
381
  def bind_params_length
336
382
  999
337
383
  end
338
384
 
339
- def initialize_type_map(m = type_map)
340
- super
341
- register_class_with_limit m, %r(int)i, SQLite3Integer
342
- end
343
-
344
385
  def table_structure(table_name)
345
386
  structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
346
387
  raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
@@ -446,6 +487,7 @@ module ActiveRecord
446
487
  options = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
447
488
  options[:unique] = true if index.unique
448
489
  options[:where] = index.where if index.where
490
+ options[:order] = index.orders if index.orders
449
491
  add_index(to, columns, **options)
450
492
  end
451
493
  end
@@ -482,7 +524,7 @@ module ActiveRecord
482
524
  end
483
525
  end
484
526
 
485
- COLLATE_REGEX = /.*\"(\w+)\".*collate\s+\"(\w+)\".*/i.freeze
527
+ COLLATE_REGEX = /.*"(\w+)".*collate\s+"(\w+)".*/i.freeze
486
528
 
487
529
  def table_structure_with_collation(table_name, basic_structure)
488
530
  collation_hash = {}
@@ -544,17 +586,6 @@ module ActiveRecord
544
586
 
545
587
  execute("PRAGMA foreign_keys = ON", "SCHEMA")
546
588
  end
547
-
548
- class SQLite3Integer < Type::Integer # :nodoc:
549
- private
550
- def _limit
551
- # INTEGER storage class can be stored 8 bytes value.
552
- # See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
553
- limit || 8
554
- end
555
- end
556
-
557
- ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
558
589
  end
559
590
  ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
560
591
  end
@@ -27,20 +27,21 @@ module ActiveRecord
27
27
  autoload :ReferenceDefinition
28
28
  end
29
29
 
30
- autoload_at "active_record/connection_adapters/abstract/connection_pool" do
31
- autoload :ConnectionHandler
32
- end
33
-
34
30
  autoload_under "abstract" do
35
31
  autoload :SchemaStatements
36
32
  autoload :DatabaseStatements
37
33
  autoload :DatabaseLimits
38
34
  autoload :Quoting
39
- autoload :ConnectionPool
35
+ autoload :ConnectionHandler
40
36
  autoload :QueryCache
41
37
  autoload :Savepoints
42
38
  end
43
39
 
40
+ autoload_at "active_record/connection_adapters/abstract/connection_pool" do
41
+ autoload :ConnectionPool
42
+ autoload :NullPool
43
+ end
44
+
44
45
  autoload_at "active_record/connection_adapters/abstract/transaction" do
45
46
  autoload :TransactionManager
46
47
  autoload :NullTransaction
@@ -134,10 +134,8 @@ module ActiveRecord
134
134
  # ActiveRecord::Base.connected_to(role: :reading, shard: :shard_one_replica) do
135
135
  # Dog.first # finds first Dog record stored on the shard one replica
136
136
  # end
137
- #
138
- # The database kwarg is deprecated and will be removed in Rails 7.0.0 without replacement.
139
- def connected_to(database: nil, role: nil, shard: nil, prevent_writes: false, &blk)
140
- if legacy_connection_handling
137
+ def connected_to(role: nil, shard: nil, prevent_writes: false, &blk)
138
+ if ActiveRecord.legacy_connection_handling
141
139
  if self != Base
142
140
  raise NotImplementedError, "`connected_to` can only be called on ActiveRecord::Base with legacy connection handling."
143
141
  end
@@ -151,31 +149,15 @@ module ActiveRecord
151
149
  end
152
150
  end
153
151
 
154
- if database && (role || shard)
155
- raise ArgumentError, "`connected_to` cannot accept a `database` argument with any other arguments."
156
- elsif database
157
- ActiveSupport::Deprecation.warn("The database key in `connected_to` is deprecated. It will be removed in Rails 7.0.0 without replacement.")
158
-
159
- if database.is_a?(Hash)
160
- role, database = database.first
161
- role = role.to_sym
162
- end
163
-
164
- db_config, owner_name = resolve_config_for_connection(database)
165
- handler = lookup_connection_handler(role)
166
-
167
- handler.establish_connection(db_config, owner_name: owner_name, role: role)
168
-
169
- with_handler(role, &blk)
170
- elsif role || shard
171
- unless role
172
- raise ArgumentError, "`connected_to` cannot accept a `shard` argument without a `role`."
173
- end
174
-
175
- with_role_and_shard(role, shard, prevent_writes, &blk)
176
- else
152
+ unless role || shard
177
153
  raise ArgumentError, "must provide a `shard` and/or `role`."
178
154
  end
155
+
156
+ unless role
157
+ raise ArgumentError, "`connected_to` cannot accept a `shard` argument without a `role`."
158
+ end
159
+
160
+ with_role_and_shard(role, shard, prevent_writes, &blk)
179
161
  end
180
162
 
181
163
  # Connects a role and/or shard to the provided connection names. Optionally +prevent_writes+
@@ -194,7 +176,7 @@ module ActiveRecord
194
176
  def connected_to_many(*classes, role:, shard: nil, prevent_writes: false)
195
177
  classes = classes.flatten
196
178
 
197
- if legacy_connection_handling
179
+ if ActiveRecord.legacy_connection_handling
198
180
  raise NotImplementedError, "connected_to_many is not available with legacy connection handling"
199
181
  end
200
182
 
@@ -202,7 +184,7 @@ module ActiveRecord
202
184
  raise NotImplementedError, "connected_to_many can only be called on ActiveRecord::Base."
203
185
  end
204
186
 
205
- prevent_writes = true if role == reading_role
187
+ prevent_writes = true if role == ActiveRecord.reading_role
206
188
 
207
189
  connected_to_stack << { role: role, shard: shard, prevent_writes: prevent_writes, klasses: classes }
208
190
  yield
@@ -218,11 +200,11 @@ module ActiveRecord
218
200
  # It is not recommended to use this method in a request since it
219
201
  # does not yield to a block like +connected_to+.
220
202
  def connecting_to(role: default_role, shard: default_shard, prevent_writes: false)
221
- if legacy_connection_handling
203
+ if ActiveRecord.legacy_connection_handling
222
204
  raise NotImplementedError, "`connecting_to` is not available with `legacy_connection_handling`."
223
205
  end
224
206
 
225
- prevent_writes = true if role == reading_role
207
+ prevent_writes = true if role == ActiveRecord.reading_role
226
208
 
227
209
  self.connected_to_stack << { role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self] }
228
210
  end
@@ -239,7 +221,7 @@ module ActiveRecord
239
221
  # See +READ_QUERY+ for the queries that are blocked by this
240
222
  # method.
241
223
  def while_preventing_writes(enabled = true, &block)
242
- if legacy_connection_handling
224
+ if ActiveRecord.legacy_connection_handling
243
225
  connection_handler.while_preventing_writes(enabled, &block)
244
226
  else
245
227
  connected_to(role: current_role, prevent_writes: enabled, &block)
@@ -257,8 +239,8 @@ module ActiveRecord
257
239
  end
258
240
 
259
241
  def lookup_connection_handler(handler_key) # :nodoc:
260
- if ActiveRecord::Base.legacy_connection_handling
261
- handler_key ||= ActiveRecord::Base.writing_role
242
+ if ActiveRecord.legacy_connection_handling
243
+ handler_key ||= ActiveRecord.writing_role
262
244
  connection_handlers[handler_key] ||= ActiveRecord::ConnectionAdapters::ConnectionHandler.new
263
245
  else
264
246
  ActiveRecord::Base.connection_handler
@@ -267,7 +249,7 @@ module ActiveRecord
267
249
 
268
250
  # Clears the query cache for all connections associated with the current thread.
269
251
  def clear_query_caches_for_current_thread
270
- if ActiveRecord::Base.legacy_connection_handling
252
+ if ActiveRecord.legacy_connection_handling
271
253
  ActiveRecord::Base.connection_handlers.each_value do |handler|
272
254
  clear_on_handler(handler)
273
255
  end
@@ -294,7 +276,7 @@ module ActiveRecord
294
276
  end
295
277
 
296
278
  def primary_class? # :nodoc:
297
- self == Base || defined?(ApplicationRecord) && self == ApplicationRecord
279
+ self == Base || application_record_class?
298
280
  end
299
281
 
300
282
  # Returns the configuration of the associated connection as a hash:
@@ -374,9 +356,9 @@ module ActiveRecord
374
356
  end
375
357
 
376
358
  def with_role_and_shard(role, shard, prevent_writes)
377
- prevent_writes = true if role == reading_role
359
+ prevent_writes = true if role == ActiveRecord.reading_role
378
360
 
379
- if ActiveRecord::Base.legacy_connection_handling
361
+ if ActiveRecord.legacy_connection_handling
380
362
  with_handler(role.to_sym) do
381
363
  connection_handler.while_preventing_writes(prevent_writes) do
382
364
  self.connected_to_stack << { shard: shard, klasses: [self] }