activerecord 6.1.3.2 → 7.0.0.alpha2

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 (229) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +734 -1058
  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 +35 -7
  8. data/lib/active_record/associations/association_scope.rb +1 -3
  9. data/lib/active_record/associations/belongs_to_association.rb +16 -6
  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 +24 -25
  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 -49
  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 +11 -1
  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 +14 -7
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +5 -18
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -9
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +17 -6
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +115 -69
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
  61. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +6 -2
  62. data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -21
  63. data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
  64. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +3 -0
  65. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  66. data/lib/active_record/connection_adapters/pool_config.rb +1 -3
  67. data/lib/active_record/connection_adapters/pool_manager.rb +5 -1
  68. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
  69. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  70. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  72. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  73. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  74. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  76. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  77. data/lib/active_record/connection_adapters/postgresql/quoting.rb +6 -6
  78. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
  79. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
  80. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
  81. data/lib/active_record/connection_adapters/postgresql_adapter.rb +157 -100
  82. data/lib/active_record/connection_adapters/schema_cache.rb +35 -4
  83. data/lib/active_record/connection_adapters/sql_type_metadata.rb +0 -2
  84. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -17
  85. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
  86. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
  87. data/lib/active_record/connection_adapters.rb +8 -5
  88. data/lib/active_record/connection_handling.rb +20 -38
  89. data/lib/active_record/core.rb +129 -117
  90. data/lib/active_record/database_configurations/database_config.rb +12 -0
  91. data/lib/active_record/database_configurations/hash_config.rb +27 -1
  92. data/lib/active_record/database_configurations/url_config.rb +2 -2
  93. data/lib/active_record/database_configurations.rb +18 -9
  94. data/lib/active_record/delegated_type.rb +33 -11
  95. data/lib/active_record/destroy_association_async_job.rb +1 -1
  96. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  97. data/lib/active_record/dynamic_matchers.rb +1 -1
  98. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  99. data/lib/active_record/encryption/cipher.rb +53 -0
  100. data/lib/active_record/encryption/config.rb +44 -0
  101. data/lib/active_record/encryption/configurable.rb +61 -0
  102. data/lib/active_record/encryption/context.rb +35 -0
  103. data/lib/active_record/encryption/contexts.rb +72 -0
  104. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  105. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  106. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  107. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  108. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  109. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  110. data/lib/active_record/encryption/encryptor.rb +155 -0
  111. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  112. data/lib/active_record/encryption/errors.rb +15 -0
  113. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  114. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +29 -0
  115. data/lib/active_record/encryption/key.rb +28 -0
  116. data/lib/active_record/encryption/key_generator.rb +42 -0
  117. data/lib/active_record/encryption/key_provider.rb +46 -0
  118. data/lib/active_record/encryption/message.rb +33 -0
  119. data/lib/active_record/encryption/message_serializer.rb +80 -0
  120. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  121. data/lib/active_record/encryption/properties.rb +76 -0
  122. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  123. data/lib/active_record/encryption/scheme.rb +99 -0
  124. data/lib/active_record/encryption.rb +55 -0
  125. data/lib/active_record/enum.rb +44 -46
  126. data/lib/active_record/errors.rb +66 -3
  127. data/lib/active_record/fixture_set/file.rb +15 -1
  128. data/lib/active_record/fixture_set/table_row.rb +40 -5
  129. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  130. data/lib/active_record/fixtures.rb +16 -11
  131. data/lib/active_record/future_result.rb +139 -0
  132. data/lib/active_record/gem_version.rb +4 -4
  133. data/lib/active_record/inheritance.rb +55 -17
  134. data/lib/active_record/insert_all.rb +39 -6
  135. data/lib/active_record/integration.rb +1 -1
  136. data/lib/active_record/internal_metadata.rb +3 -5
  137. data/lib/active_record/legacy_yaml_adapter.rb +1 -1
  138. data/lib/active_record/locking/optimistic.rb +10 -9
  139. data/lib/active_record/log_subscriber.rb +6 -2
  140. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  141. data/lib/active_record/middleware/database_selector.rb +8 -3
  142. data/lib/active_record/migration/command_recorder.rb +4 -4
  143. data/lib/active_record/migration/compatibility.rb +83 -1
  144. data/lib/active_record/migration/join_table.rb +1 -1
  145. data/lib/active_record/migration.rb +109 -79
  146. data/lib/active_record/model_schema.rb +46 -32
  147. data/lib/active_record/nested_attributes.rb +3 -3
  148. data/lib/active_record/no_touching.rb +2 -2
  149. data/lib/active_record/null_relation.rb +2 -6
  150. data/lib/active_record/persistence.rb +134 -45
  151. data/lib/active_record/query_cache.rb +2 -2
  152. data/lib/active_record/query_logs.rb +203 -0
  153. data/lib/active_record/querying.rb +15 -5
  154. data/lib/active_record/railtie.rb +117 -17
  155. data/lib/active_record/railties/controller_runtime.rb +1 -1
  156. data/lib/active_record/railties/databases.rake +83 -58
  157. data/lib/active_record/readonly_attributes.rb +11 -0
  158. data/lib/active_record/reflection.rb +45 -44
  159. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  160. data/lib/active_record/relation/batches.rb +3 -3
  161. data/lib/active_record/relation/calculations.rb +42 -25
  162. data/lib/active_record/relation/delegation.rb +6 -6
  163. data/lib/active_record/relation/finder_methods.rb +32 -23
  164. data/lib/active_record/relation/merger.rb +20 -13
  165. data/lib/active_record/relation/predicate_builder.rb +1 -6
  166. data/lib/active_record/relation/query_attribute.rb +5 -11
  167. data/lib/active_record/relation/query_methods.rb +233 -50
  168. data/lib/active_record/relation/record_fetch_warning.rb +2 -2
  169. data/lib/active_record/relation/spawn_methods.rb +2 -2
  170. data/lib/active_record/relation/where_clause.rb +22 -15
  171. data/lib/active_record/relation.rb +170 -87
  172. data/lib/active_record/result.rb +17 -2
  173. data/lib/active_record/runtime_registry.rb +2 -4
  174. data/lib/active_record/sanitization.rb +11 -7
  175. data/lib/active_record/schema_dumper.rb +3 -3
  176. data/lib/active_record/schema_migration.rb +0 -4
  177. data/lib/active_record/scoping/default.rb +62 -15
  178. data/lib/active_record/scoping/named.rb +3 -11
  179. data/lib/active_record/scoping.rb +40 -22
  180. data/lib/active_record/serialization.rb +1 -1
  181. data/lib/active_record/signed_id.rb +1 -1
  182. data/lib/active_record/statement_cache.rb +2 -2
  183. data/lib/active_record/tasks/database_tasks.rb +107 -23
  184. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  185. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
  186. data/lib/active_record/test_databases.rb +1 -1
  187. data/lib/active_record/test_fixtures.rb +45 -4
  188. data/lib/active_record/timestamp.rb +3 -4
  189. data/lib/active_record/transactions.rb +9 -14
  190. data/lib/active_record/translation.rb +2 -2
  191. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  192. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  193. data/lib/active_record/type/internal/timezone.rb +2 -2
  194. data/lib/active_record/type/serialized.rb +1 -1
  195. data/lib/active_record/type/type_map.rb +17 -20
  196. data/lib/active_record/type.rb +1 -2
  197. data/lib/active_record/validations/associated.rb +1 -1
  198. data/lib/active_record/validations/numericality.rb +1 -1
  199. data/lib/active_record.rb +170 -2
  200. data/lib/arel/attributes/attribute.rb +0 -8
  201. data/lib/arel/collectors/bind.rb +2 -2
  202. data/lib/arel/collectors/composite.rb +3 -3
  203. data/lib/arel/collectors/sql_string.rb +1 -1
  204. data/lib/arel/collectors/substitute_binds.rb +1 -1
  205. data/lib/arel/crud.rb +18 -22
  206. data/lib/arel/delete_manager.rb +2 -4
  207. data/lib/arel/insert_manager.rb +2 -3
  208. data/lib/arel/nodes/casted.rb +1 -1
  209. data/lib/arel/nodes/delete_statement.rb +8 -13
  210. data/lib/arel/nodes/homogeneous_in.rb +4 -0
  211. data/lib/arel/nodes/insert_statement.rb +2 -2
  212. data/lib/arel/nodes/select_core.rb +2 -2
  213. data/lib/arel/nodes/select_statement.rb +2 -2
  214. data/lib/arel/nodes/update_statement.rb +3 -2
  215. data/lib/arel/predications.rb +3 -3
  216. data/lib/arel/select_manager.rb +10 -4
  217. data/lib/arel/table.rb +0 -1
  218. data/lib/arel/tree_manager.rb +0 -12
  219. data/lib/arel/update_manager.rb +2 -4
  220. data/lib/arel/visitors/dot.rb +80 -90
  221. data/lib/arel/visitors/mysql.rb +6 -1
  222. data/lib/arel/visitors/postgresql.rb +0 -10
  223. data/lib/arel/visitors/to_sql.rb +44 -3
  224. data/lib/arel.rb +1 -1
  225. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  226. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  227. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  228. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  229. metadata +55 -16
@@ -9,7 +9,15 @@ module ActiveRecord
9
9
  return unless File.file?(filename)
10
10
 
11
11
  read(filename) do |file|
12
- filename.include?(".dump") ? Marshal.load(file) : YAML.load(file)
12
+ if filename.include?(".dump")
13
+ Marshal.load(file)
14
+ else
15
+ if YAML.respond_to?(:unsafe_load)
16
+ YAML.unsafe_load(file)
17
+ else
18
+ YAML.load(file)
19
+ end
20
+ end
13
21
  end
14
22
  end
15
23
 
@@ -78,6 +86,7 @@ module ActiveRecord
78
86
 
79
87
  # A cached lookup for table existence.
80
88
  def data_source_exists?(name)
89
+ return if ignored_table?(name)
81
90
  prepare_data_sources if @data_sources.empty?
82
91
  return @data_sources[name] if @data_sources.key? name
83
92
 
@@ -100,6 +109,10 @@ module ActiveRecord
100
109
 
101
110
  # Get the columns for a table
102
111
  def columns(table_name)
112
+ if ignored_table?(table_name)
113
+ raise ActiveRecord::StatementInvalid, "Table '#{table_name}' doesn't exist"
114
+ end
115
+
103
116
  @columns.fetch(table_name) do
104
117
  @columns[deep_deduplicate(table_name)] = deep_deduplicate(connection.columns(table_name))
105
118
  end
@@ -120,7 +133,11 @@ module ActiveRecord
120
133
 
121
134
  def indexes(table_name)
122
135
  @indexes.fetch(table_name) do
123
- @indexes[deep_deduplicate(table_name)] = deep_deduplicate(connection.indexes(table_name))
136
+ if data_source_exists?(table_name)
137
+ @indexes[deep_deduplicate(table_name)] = deep_deduplicate(connection.indexes(table_name))
138
+ else
139
+ []
140
+ end
124
141
  end
125
142
  end
126
143
 
@@ -154,7 +171,7 @@ module ActiveRecord
154
171
 
155
172
  def dump_to(filename)
156
173
  clear!
157
- connection.data_sources.each { |table| add(table) }
174
+ tables_to_cache.each { |table| add(table) }
158
175
  open(filename) { |f|
159
176
  if filename.include?(".dump")
160
177
  f.write(Marshal.dump(self))
@@ -178,6 +195,18 @@ module ActiveRecord
178
195
  end
179
196
 
180
197
  private
198
+ def tables_to_cache
199
+ connection.data_sources.reject do |table|
200
+ ignored_table?(table)
201
+ end
202
+ end
203
+
204
+ def ignored_table?(table_name)
205
+ ActiveRecord.schema_cache_ignored_tables.any? do |ignored|
206
+ ignored === table_name
207
+ end
208
+ end
209
+
181
210
  def reset_version!
182
211
  @version = connection.migration_context.current_version
183
212
  end
@@ -204,7 +233,9 @@ module ActiveRecord
204
233
  end
205
234
 
206
235
  def prepare_data_sources
207
- connection.data_sources.each { |source| @data_sources[source] = true }
236
+ tables_to_cache.each do |source|
237
+ @data_sources[source] = true
238
+ end
208
239
  end
209
240
 
210
241
  def open(filename)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_record/connection_adapters/deduplicable"
4
-
5
3
  module ActiveRecord
6
4
  # :stopdoc:
7
5
  module ConnectionAdapters
@@ -18,10 +18,9 @@ module ActiveRecord
18
18
  SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
19
19
  end
20
20
 
21
- def execute(sql, name = nil) #:nodoc:
22
- if preventing_writes? && write_query?(sql)
23
- raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
24
- end
21
+ def execute(sql, name = nil) # :nodoc:
22
+ sql = transform_query(sql)
23
+ check_if_write_query(sql)
25
24
 
26
25
  materialize_transactions
27
26
  mark_transaction_written_if_write(sql)
@@ -33,17 +32,16 @@ module ActiveRecord
33
32
  end
34
33
  end
35
34
 
36
- def exec_query(sql, name = nil, binds = [], prepare: false)
37
- if preventing_writes? && write_query?(sql)
38
- raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
39
- 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)
40
38
 
41
39
  materialize_transactions
42
40
  mark_transaction_written_if_write(sql)
43
41
 
44
42
  type_casted_binds = type_casted_binds(binds)
45
43
 
46
- log(sql, name, binds, type_casted_binds) do
44
+ log(sql, name, binds, type_casted_binds, async: async) do
47
45
  ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
48
46
  # Don't cache statements if they are not prepared
49
47
  unless prepare
@@ -70,13 +68,13 @@ module ActiveRecord
70
68
  end
71
69
  end
72
70
 
73
- def exec_delete(sql, name = "SQL", binds = [])
71
+ def exec_delete(sql, name = "SQL", binds = []) # :nodoc:
74
72
  exec_query(sql, name, binds)
75
73
  @connection.changes
76
74
  end
77
75
  alias :exec_update :exec_delete
78
76
 
79
- def begin_isolated_db_transaction(isolation) #:nodoc
77
+ def begin_isolated_db_transaction(isolation) # :nodoc:
80
78
  raise TransactionIsolationError, "SQLite3 only supports the `read_uncommitted` transaction isolation level" if isolation != :read_uncommitted
81
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?
82
80
 
@@ -85,20 +83,29 @@ module ActiveRecord
85
83
  begin_db_transaction
86
84
  end
87
85
 
88
- def begin_db_transaction #:nodoc:
86
+ def begin_db_transaction # :nodoc:
89
87
  log("begin transaction", "TRANSACTION") { @connection.transaction }
90
88
  end
91
89
 
92
- def commit_db_transaction #:nodoc:
90
+ def commit_db_transaction # :nodoc:
93
91
  log("commit transaction", "TRANSACTION") { @connection.commit }
94
92
  reset_read_uncommitted
95
93
  end
96
94
 
97
- def exec_rollback_db_transaction #:nodoc:
95
+ def exec_rollback_db_transaction # :nodoc:
98
96
  log("rollback transaction", "TRANSACTION") { @connection.rollback }
99
97
  reset_read_uncommitted
100
98
  end
101
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
+
102
109
  private
103
110
  def reset_read_uncommitted
104
111
  read_uncommitted = Thread.current.thread_variable_get("read_uncommitted")
@@ -108,11 +115,10 @@ module ActiveRecord
108
115
  end
109
116
 
110
117
  def execute_batch(statements, name = nil)
118
+ statements = statements.map { |sql| transform_query(sql) }
111
119
  sql = combine_multi_statements(statements)
112
120
 
113
- if preventing_writes? && write_query?(sql)
114
- raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
115
- end
121
+ check_if_write_query(sql)
116
122
 
117
123
  materialize_transactions
118
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
@@ -12,6 +12,8 @@ module ActiveRecord
12
12
  autoload :PoolConfig
13
13
  autoload :PoolManager
14
14
  autoload :LegacyPoolManager
15
+ autoload :SchemaCache
16
+ autoload :Deduplicable
15
17
 
16
18
  autoload_at "active_record/connection_adapters/abstract/schema_definitions" do
17
19
  autoload :IndexDefinition
@@ -25,20 +27,21 @@ module ActiveRecord
25
27
  autoload :ReferenceDefinition
26
28
  end
27
29
 
28
- autoload_at "active_record/connection_adapters/abstract/connection_pool" do
29
- autoload :ConnectionHandler
30
- end
31
-
32
30
  autoload_under "abstract" do
33
31
  autoload :SchemaStatements
34
32
  autoload :DatabaseStatements
35
33
  autoload :DatabaseLimits
36
34
  autoload :Quoting
37
- autoload :ConnectionPool
35
+ autoload :ConnectionHandler
38
36
  autoload :QueryCache
39
37
  autoload :Savepoints
40
38
  end
41
39
 
40
+ autoload_at "active_record/connection_adapters/abstract/connection_pool" do
41
+ autoload :ConnectionPool
42
+ autoload :NullPool
43
+ end
44
+
42
45
  autoload_at "active_record/connection_adapters/abstract/transaction" do
43
46
  autoload :TransactionManager
44
47
  autoload :NullTransaction