activerecord 6.1.7 → 7.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2030 -1020
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +18 -18
  5. data/lib/active_record/aggregations.rb +17 -14
  6. data/lib/active_record/association_relation.rb +1 -11
  7. data/lib/active_record/associations/association.rb +51 -19
  8. data/lib/active_record/associations/association_scope.rb +17 -12
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +11 -5
  12. data/lib/active_record/associations/builder/belongs_to.rb +40 -14
  13. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  14. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
  15. data/lib/active_record/associations/builder/has_many.rb +3 -2
  16. data/lib/active_record/associations/builder/has_one.rb +2 -1
  17. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  18. data/lib/active_record/associations/collection_association.rb +39 -35
  19. data/lib/active_record/associations/collection_proxy.rb +30 -15
  20. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  21. data/lib/active_record/associations/foreign_association.rb +10 -3
  22. data/lib/active_record/associations/has_many_association.rb +28 -18
  23. data/lib/active_record/associations/has_many_through_association.rb +12 -7
  24. data/lib/active_record/associations/has_one_association.rb +20 -10
  25. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  26. data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
  27. data/lib/active_record/associations/join_dependency.rb +28 -20
  28. data/lib/active_record/associations/preloader/association.rb +210 -52
  29. data/lib/active_record/associations/preloader/batch.rb +48 -0
  30. data/lib/active_record/associations/preloader/branch.rb +147 -0
  31. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  32. data/lib/active_record/associations/preloader.rb +50 -121
  33. data/lib/active_record/associations/singular_association.rb +9 -3
  34. data/lib/active_record/associations/through_association.rb +25 -14
  35. data/lib/active_record/associations.rb +446 -306
  36. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  37. data/lib/active_record/attribute_assignment.rb +1 -3
  38. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  39. data/lib/active_record/attribute_methods/dirty.rb +73 -22
  40. data/lib/active_record/attribute_methods/primary_key.rb +78 -26
  41. data/lib/active_record/attribute_methods/query.rb +31 -19
  42. data/lib/active_record/attribute_methods/read.rb +27 -12
  43. data/lib/active_record/attribute_methods/serialization.rb +194 -37
  44. data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
  45. data/lib/active_record/attribute_methods/write.rb +12 -15
  46. data/lib/active_record/attribute_methods.rb +161 -40
  47. data/lib/active_record/attributes.rb +27 -38
  48. data/lib/active_record/autosave_association.rb +65 -31
  49. data/lib/active_record/base.rb +25 -2
  50. data/lib/active_record/callbacks.rb +18 -34
  51. data/lib/active_record/coders/column_serializer.rb +61 -0
  52. data/lib/active_record/coders/json.rb +1 -1
  53. data/lib/active_record/coders/yaml_column.rb +70 -46
  54. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +367 -141
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
  70. data/lib/active_record/connection_adapters/column.rb +13 -0
  71. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +39 -14
  78. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
  80. data/lib/active_record/connection_adapters/pool_config.rb +20 -11
  81. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  89. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  91. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  97. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
  101. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
  103. data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
  104. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  105. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
  106. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
  107. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  108. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
  109. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
  110. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  111. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  112. data/lib/active_record/connection_adapters/trilogy_adapter.rb +258 -0
  113. data/lib/active_record/connection_adapters.rb +9 -6
  114. data/lib/active_record/connection_handling.rb +108 -137
  115. data/lib/active_record/core.rb +242 -233
  116. data/lib/active_record/counter_cache.rb +52 -27
  117. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
  118. data/lib/active_record/database_configurations/database_config.rb +21 -12
  119. data/lib/active_record/database_configurations/hash_config.rb +88 -16
  120. data/lib/active_record/database_configurations/url_config.rb +18 -12
  121. data/lib/active_record/database_configurations.rb +95 -59
  122. data/lib/active_record/delegated_type.rb +66 -20
  123. data/lib/active_record/deprecator.rb +7 -0
  124. data/lib/active_record/destroy_association_async_job.rb +4 -2
  125. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  126. data/lib/active_record/dynamic_matchers.rb +1 -1
  127. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  128. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  129. data/lib/active_record/encryption/cipher.rb +53 -0
  130. data/lib/active_record/encryption/config.rb +68 -0
  131. data/lib/active_record/encryption/configurable.rb +60 -0
  132. data/lib/active_record/encryption/context.rb +42 -0
  133. data/lib/active_record/encryption/contexts.rb +76 -0
  134. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  135. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  136. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  137. data/lib/active_record/encryption/encrypted_attribute_type.rb +155 -0
  138. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  139. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  140. data/lib/active_record/encryption/encryptor.rb +155 -0
  141. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  142. data/lib/active_record/encryption/errors.rb +15 -0
  143. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  144. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  145. data/lib/active_record/encryption/key.rb +28 -0
  146. data/lib/active_record/encryption/key_generator.rb +53 -0
  147. data/lib/active_record/encryption/key_provider.rb +46 -0
  148. data/lib/active_record/encryption/message.rb +33 -0
  149. data/lib/active_record/encryption/message_serializer.rb +92 -0
  150. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  151. data/lib/active_record/encryption/properties.rb +76 -0
  152. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  153. data/lib/active_record/encryption/scheme.rb +100 -0
  154. data/lib/active_record/encryption.rb +58 -0
  155. data/lib/active_record/enum.rb +154 -63
  156. data/lib/active_record/errors.rb +172 -15
  157. data/lib/active_record/explain.rb +23 -3
  158. data/lib/active_record/explain_registry.rb +11 -6
  159. data/lib/active_record/explain_subscriber.rb +1 -1
  160. data/lib/active_record/fixture_set/file.rb +15 -1
  161. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  162. data/lib/active_record/fixture_set/render_context.rb +2 -0
  163. data/lib/active_record/fixture_set/table_row.rb +70 -14
  164. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  165. data/lib/active_record/fixtures.rb +147 -86
  166. data/lib/active_record/future_result.rb +174 -0
  167. data/lib/active_record/gem_version.rb +3 -3
  168. data/lib/active_record/inheritance.rb +81 -29
  169. data/lib/active_record/insert_all.rb +135 -22
  170. data/lib/active_record/integration.rb +11 -10
  171. data/lib/active_record/internal_metadata.rb +119 -33
  172. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  173. data/lib/active_record/locking/optimistic.rb +37 -22
  174. data/lib/active_record/locking/pessimistic.rb +15 -6
  175. data/lib/active_record/log_subscriber.rb +52 -19
  176. data/lib/active_record/marshalling.rb +59 -0
  177. data/lib/active_record/message_pack.rb +124 -0
  178. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  179. data/lib/active_record/middleware/database_selector.rb +23 -13
  180. data/lib/active_record/middleware/shard_selector.rb +62 -0
  181. data/lib/active_record/migration/command_recorder.rb +112 -14
  182. data/lib/active_record/migration/compatibility.rb +233 -46
  183. data/lib/active_record/migration/default_strategy.rb +23 -0
  184. data/lib/active_record/migration/execution_strategy.rb +19 -0
  185. data/lib/active_record/migration/join_table.rb +1 -1
  186. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  187. data/lib/active_record/migration.rb +361 -173
  188. data/lib/active_record/model_schema.rb +125 -101
  189. data/lib/active_record/nested_attributes.rb +50 -20
  190. data/lib/active_record/no_touching.rb +3 -3
  191. data/lib/active_record/normalization.rb +167 -0
  192. data/lib/active_record/persistence.rb +409 -88
  193. data/lib/active_record/promise.rb +84 -0
  194. data/lib/active_record/query_cache.rb +4 -22
  195. data/lib/active_record/query_logs.rb +174 -0
  196. data/lib/active_record/query_logs_formatter.rb +41 -0
  197. data/lib/active_record/querying.rb +29 -6
  198. data/lib/active_record/railtie.rb +220 -44
  199. data/lib/active_record/railties/controller_runtime.rb +15 -10
  200. data/lib/active_record/railties/databases.rake +188 -252
  201. data/lib/active_record/railties/job_runtime.rb +23 -0
  202. data/lib/active_record/readonly_attributes.rb +41 -3
  203. data/lib/active_record/reflection.rb +248 -81
  204. data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
  205. data/lib/active_record/relation/batches.rb +192 -63
  206. data/lib/active_record/relation/calculations.rb +246 -90
  207. data/lib/active_record/relation/delegation.rb +28 -14
  208. data/lib/active_record/relation/finder_methods.rb +108 -51
  209. data/lib/active_record/relation/merger.rb +22 -13
  210. data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
  211. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  212. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  213. data/lib/active_record/relation/predicate_builder.rb +27 -20
  214. data/lib/active_record/relation/query_attribute.rb +30 -12
  215. data/lib/active_record/relation/query_methods.rb +670 -129
  216. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  217. data/lib/active_record/relation/spawn_methods.rb +20 -3
  218. data/lib/active_record/relation/where_clause.rb +10 -19
  219. data/lib/active_record/relation.rb +287 -120
  220. data/lib/active_record/result.rb +37 -11
  221. data/lib/active_record/runtime_registry.rb +32 -13
  222. data/lib/active_record/sanitization.rb +65 -20
  223. data/lib/active_record/schema.rb +36 -22
  224. data/lib/active_record/schema_dumper.rb +73 -24
  225. data/lib/active_record/schema_migration.rb +68 -33
  226. data/lib/active_record/scoping/default.rb +72 -15
  227. data/lib/active_record/scoping/named.rb +5 -13
  228. data/lib/active_record/scoping.rb +65 -34
  229. data/lib/active_record/secure_password.rb +60 -0
  230. data/lib/active_record/secure_token.rb +21 -3
  231. data/lib/active_record/serialization.rb +6 -1
  232. data/lib/active_record/signed_id.rb +10 -8
  233. data/lib/active_record/store.rb +10 -10
  234. data/lib/active_record/suppressor.rb +13 -15
  235. data/lib/active_record/table_metadata.rb +16 -3
  236. data/lib/active_record/tasks/database_tasks.rb +251 -140
  237. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  238. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  239. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  240. data/lib/active_record/test_databases.rb +1 -1
  241. data/lib/active_record/test_fixtures.rb +117 -96
  242. data/lib/active_record/timestamp.rb +32 -19
  243. data/lib/active_record/token_for.rb +113 -0
  244. data/lib/active_record/touch_later.rb +11 -6
  245. data/lib/active_record/transactions.rb +48 -27
  246. data/lib/active_record/translation.rb +3 -3
  247. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  248. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  249. data/lib/active_record/type/internal/timezone.rb +7 -2
  250. data/lib/active_record/type/serialized.rb +9 -5
  251. data/lib/active_record/type/time.rb +4 -0
  252. data/lib/active_record/type/type_map.rb +17 -20
  253. data/lib/active_record/type.rb +1 -2
  254. data/lib/active_record/validations/absence.rb +1 -1
  255. data/lib/active_record/validations/associated.rb +4 -4
  256. data/lib/active_record/validations/numericality.rb +5 -4
  257. data/lib/active_record/validations/presence.rb +5 -28
  258. data/lib/active_record/validations/uniqueness.rb +51 -6
  259. data/lib/active_record/validations.rb +8 -4
  260. data/lib/active_record/version.rb +1 -1
  261. data/lib/active_record.rb +335 -32
  262. data/lib/arel/attributes/attribute.rb +0 -8
  263. data/lib/arel/crud.rb +28 -22
  264. data/lib/arel/delete_manager.rb +18 -4
  265. data/lib/arel/errors.rb +10 -0
  266. data/lib/arel/factory_methods.rb +4 -0
  267. data/lib/arel/filter_predications.rb +9 -0
  268. data/lib/arel/insert_manager.rb +2 -3
  269. data/lib/arel/nodes/and.rb +4 -0
  270. data/lib/arel/nodes/binary.rb +6 -1
  271. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  272. data/lib/arel/nodes/casted.rb +1 -1
  273. data/lib/arel/nodes/cte.rb +36 -0
  274. data/lib/arel/nodes/delete_statement.rb +12 -13
  275. data/lib/arel/nodes/filter.rb +10 -0
  276. data/lib/arel/nodes/fragments.rb +35 -0
  277. data/lib/arel/nodes/function.rb +1 -0
  278. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  279. data/lib/arel/nodes/insert_statement.rb +2 -2
  280. data/lib/arel/nodes/leading_join.rb +8 -0
  281. data/lib/arel/nodes/node.rb +111 -2
  282. data/lib/arel/nodes/select_core.rb +2 -2
  283. data/lib/arel/nodes/select_statement.rb +2 -2
  284. data/lib/arel/nodes/sql_literal.rb +6 -0
  285. data/lib/arel/nodes/table_alias.rb +4 -0
  286. data/lib/arel/nodes/update_statement.rb +8 -3
  287. data/lib/arel/nodes.rb +5 -0
  288. data/lib/arel/predications.rb +13 -3
  289. data/lib/arel/select_manager.rb +10 -4
  290. data/lib/arel/table.rb +9 -6
  291. data/lib/arel/tree_manager.rb +5 -13
  292. data/lib/arel/update_manager.rb +18 -4
  293. data/lib/arel/visitors/dot.rb +80 -90
  294. data/lib/arel/visitors/mysql.rb +16 -3
  295. data/lib/arel/visitors/postgresql.rb +0 -10
  296. data/lib/arel/visitors/to_sql.rb +141 -20
  297. data/lib/arel/visitors/visitor.rb +2 -2
  298. data/lib/arel.rb +18 -3
  299. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  300. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  301. data/lib/rails/generators/active_record/migration.rb +3 -1
  302. data/lib/rails/generators/active_record/model/USAGE +113 -0
  303. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  304. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  305. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  306. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  307. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  308. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  309. metadata +96 -16
  310. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  311. data/lib/active_record/null_relation.rb +0 -67
@@ -4,8 +4,234 @@ require "active_support/core_ext/file/atomic"
4
4
 
5
5
  module ActiveRecord
6
6
  module ConnectionAdapters
7
+ class SchemaReflection
8
+ class << self
9
+ attr_accessor :use_schema_cache_dump
10
+ attr_accessor :check_schema_cache_dump_version
11
+ end
12
+
13
+ self.use_schema_cache_dump = true
14
+ self.check_schema_cache_dump_version = true
15
+
16
+ def initialize(cache_path, cache = nil)
17
+ @cache = cache
18
+ @cache_path = cache_path
19
+ end
20
+
21
+ def set_schema_cache(cache)
22
+ @cache = cache
23
+ end
24
+
25
+ def clear!
26
+ @cache = empty_cache
27
+
28
+ nil
29
+ end
30
+
31
+ def load!(connection)
32
+ cache(connection)
33
+
34
+ self
35
+ end
36
+
37
+ def primary_keys(connection, table_name)
38
+ cache(connection).primary_keys(connection, table_name)
39
+ end
40
+
41
+ def data_source_exists?(connection, name)
42
+ cache(connection).data_source_exists?(connection, name)
43
+ end
44
+
45
+ def add(connection, name)
46
+ cache(connection).add(connection, name)
47
+ end
48
+
49
+ def data_sources(connection, name)
50
+ cache(connection).data_sources(connection, name)
51
+ end
52
+
53
+ def columns(connection, table_name)
54
+ cache(connection).columns(connection, table_name)
55
+ end
56
+
57
+ def columns_hash(connection, table_name)
58
+ cache(connection).columns_hash(connection, table_name)
59
+ end
60
+
61
+ def columns_hash?(connection, table_name)
62
+ cache(connection).columns_hash?(connection, table_name)
63
+ end
64
+
65
+ def indexes(connection, table_name)
66
+ cache(connection).indexes(connection, table_name)
67
+ end
68
+
69
+ def database_version(connection) # :nodoc:
70
+ cache(connection).database_version(connection)
71
+ end
72
+
73
+ def version(connection)
74
+ cache(connection).version(connection)
75
+ end
76
+
77
+ def size(connection)
78
+ cache(connection).size
79
+ end
80
+
81
+ def clear_data_source_cache!(connection, name)
82
+ return if @cache.nil? && !possible_cache_available?
83
+
84
+ cache(connection).clear_data_source_cache!(connection, name)
85
+ end
86
+
87
+ def cached?(table_name)
88
+ if @cache.nil?
89
+ # If `check_schema_cache_dump_version` is enabled we can't load
90
+ # the schema cache dump without connecting to the database.
91
+ unless self.class.check_schema_cache_dump_version
92
+ @cache = load_cache(nil)
93
+ end
94
+ end
95
+
96
+ @cache&.cached?(table_name)
97
+ end
98
+
99
+ def dump_to(connection, filename)
100
+ fresh_cache = empty_cache
101
+ fresh_cache.add_all(connection)
102
+ fresh_cache.dump_to(filename)
103
+
104
+ @cache = fresh_cache
105
+ end
106
+
107
+ private
108
+ def empty_cache
109
+ new_cache = SchemaCache.allocate
110
+ new_cache.send(:initialize)
111
+ new_cache
112
+ end
113
+
114
+ def cache(connection)
115
+ @cache ||= load_cache(connection) || empty_cache
116
+ end
117
+
118
+ def possible_cache_available?
119
+ self.class.use_schema_cache_dump &&
120
+ @cache_path &&
121
+ File.file?(@cache_path)
122
+ end
123
+
124
+ def load_cache(connection)
125
+ # Can't load if schema dumps are disabled
126
+ return unless possible_cache_available?
127
+
128
+ # Check we can find one
129
+ return unless new_cache = SchemaCache._load_from(@cache_path)
130
+
131
+ if self.class.check_schema_cache_dump_version
132
+ begin
133
+ current_version = connection.schema_version
134
+
135
+ if new_cache.version(connection) != current_version
136
+ warn "Ignoring #{@cache_path} because it has expired. The current schema version is #{current_version}, but the one in the schema cache file is #{new_cache.schema_version}."
137
+ return
138
+ end
139
+ rescue ActiveRecordError => error
140
+ warn "Failed to validate the schema cache because of #{error.class}: #{error.message}"
141
+ return
142
+ end
143
+ end
144
+
145
+ new_cache
146
+ end
147
+ end
148
+
149
+ class BoundSchemaReflection
150
+ def initialize(abstract_schema_reflection, connection)
151
+ @schema_reflection = abstract_schema_reflection
152
+ @connection = connection
153
+ end
154
+
155
+ def clear!
156
+ @schema_reflection.clear!
157
+ end
158
+
159
+ def load!
160
+ @schema_reflection.load!(@connection)
161
+ end
162
+
163
+ def cached?(table_name)
164
+ @schema_reflection.cached?(table_name)
165
+ end
166
+
167
+ def primary_keys(table_name)
168
+ @schema_reflection.primary_keys(@connection, table_name)
169
+ end
170
+
171
+ def data_source_exists?(name)
172
+ @schema_reflection.data_source_exists?(@connection, name)
173
+ end
174
+
175
+ def add(name)
176
+ @schema_reflection.add(@connection, name)
177
+ end
178
+
179
+ def data_sources(name)
180
+ @schema_reflection.data_sources(@connection, name)
181
+ end
182
+
183
+ def columns(table_name)
184
+ @schema_reflection.columns(@connection, table_name)
185
+ end
186
+
187
+ def columns_hash(table_name)
188
+ @schema_reflection.columns_hash(@connection, table_name)
189
+ end
190
+
191
+ def columns_hash?(table_name)
192
+ @schema_reflection.columns_hash?(@connection, table_name)
193
+ end
194
+
195
+ def indexes(table_name)
196
+ @schema_reflection.indexes(@connection, table_name)
197
+ end
198
+
199
+ def database_version # :nodoc:
200
+ @schema_reflection.database_version(@connection)
201
+ end
202
+
203
+ def version
204
+ @schema_reflection.version(@connection)
205
+ end
206
+
207
+ def size
208
+ @schema_reflection.size(@connection)
209
+ end
210
+
211
+ def clear_data_source_cache!(name)
212
+ @schema_reflection.clear_data_source_cache!(@connection, name)
213
+ end
214
+
215
+ def dump_to(filename)
216
+ @schema_reflection.dump_to(@connection, filename)
217
+ end
218
+ end
219
+
220
+ # = Active Record Connection Adapters Schema Cache
7
221
  class SchemaCache
8
- def self.load_from(filename)
222
+ class << self
223
+ def new(connection)
224
+ BoundSchemaReflection.new(SchemaReflection.new(nil), connection)
225
+ end
226
+ deprecate new: "use ActiveRecord::ConnectionAdapters::SchemaReflection instead", deprecator: ActiveRecord.deprecator
227
+
228
+ def load_from(filename) # :nodoc:
229
+ BoundSchemaReflection.new(SchemaReflection.new(filename), nil)
230
+ end
231
+ deprecate load_from: "use ActiveRecord::ConnectionAdapters::SchemaReflection instead", deprecator: ActiveRecord.deprecator
232
+ end
233
+
234
+ def self._load_from(filename) # :nodoc:
9
235
  return unless File.file?(filename)
10
236
 
11
237
  read(filename) do |file|
@@ -32,20 +258,17 @@ module ActiveRecord
32
258
  end
33
259
  private_class_method :read
34
260
 
35
- attr_reader :version
36
- attr_accessor :connection
37
-
38
- def initialize(conn)
39
- @connection = conn
40
-
261
+ def initialize
41
262
  @columns = {}
42
263
  @columns_hash = {}
43
264
  @primary_keys = {}
44
265
  @data_sources = {}
45
266
  @indexes = {}
267
+ @database_version = nil
268
+ @version = nil
46
269
  end
47
270
 
48
- def initialize_dup(other)
271
+ def initialize_dup(other) # :nodoc:
49
272
  super
50
273
  @columns = @columns.dup
51
274
  @columns_hash = @columns_hash.dup
@@ -54,60 +277,71 @@ module ActiveRecord
54
277
  @indexes = @indexes.dup
55
278
  end
56
279
 
57
- def encode_with(coder)
58
- reset_version!
59
-
60
- coder["columns"] = @columns
61
- coder["primary_keys"] = @primary_keys
62
- coder["data_sources"] = @data_sources
63
- coder["indexes"] = @indexes
280
+ def encode_with(coder) # :nodoc:
281
+ coder["columns"] = @columns.sort.to_h
282
+ coder["primary_keys"] = @primary_keys.sort.to_h
283
+ coder["data_sources"] = @data_sources.sort.to_h
284
+ coder["indexes"] = @indexes.sort.to_h
64
285
  coder["version"] = @version
65
- coder["database_version"] = database_version
286
+ coder["database_version"] = @database_version
66
287
  end
67
288
 
68
289
  def init_with(coder)
69
290
  @columns = coder["columns"]
291
+ @columns_hash = coder["columns_hash"]
70
292
  @primary_keys = coder["primary_keys"]
71
293
  @data_sources = coder["data_sources"]
72
294
  @indexes = coder["indexes"] || {}
73
295
  @version = coder["version"]
74
296
  @database_version = coder["database_version"]
75
297
 
76
- derive_columns_hash_and_deduplicate_values
298
+ unless coder["deduplicated"]
299
+ derive_columns_hash_and_deduplicate_values
300
+ end
77
301
  end
78
302
 
79
- def primary_keys(table_name)
303
+ def cached?(table_name)
304
+ @columns.key?(table_name)
305
+ end
306
+
307
+ def primary_keys(connection, table_name)
80
308
  @primary_keys.fetch(table_name) do
81
- if data_source_exists?(table_name)
309
+ if data_source_exists?(connection, table_name)
82
310
  @primary_keys[deep_deduplicate(table_name)] = deep_deduplicate(connection.primary_key(table_name))
83
311
  end
84
312
  end
85
313
  end
86
314
 
87
315
  # A cached lookup for table existence.
88
- def data_source_exists?(name)
89
- prepare_data_sources if @data_sources.empty?
316
+ def data_source_exists?(connection, name)
317
+ return if ignored_table?(name)
318
+ prepare_data_sources(connection) if @data_sources.empty?
90
319
  return @data_sources[name] if @data_sources.key? name
91
320
 
92
321
  @data_sources[deep_deduplicate(name)] = connection.data_source_exists?(name)
93
322
  end
94
323
 
95
324
  # Add internal cache for table with +table_name+.
96
- def add(table_name)
97
- if data_source_exists?(table_name)
98
- primary_keys(table_name)
99
- columns(table_name)
100
- columns_hash(table_name)
101
- indexes(table_name)
325
+ def add(connection, table_name)
326
+ if data_source_exists?(connection, table_name)
327
+ primary_keys(connection, table_name)
328
+ columns(connection, table_name)
329
+ columns_hash(connection, table_name)
330
+ indexes(connection, table_name)
102
331
  end
103
332
  end
104
333
 
105
- def data_sources(name)
334
+ def data_sources(_connection, name) # :nodoc:
106
335
  @data_sources[name]
107
336
  end
337
+ deprecate data_sources: :data_source_exists?, deprecator: ActiveRecord.deprecator
108
338
 
109
339
  # Get the columns for a table
110
- def columns(table_name)
340
+ def columns(connection, table_name)
341
+ if ignored_table?(table_name)
342
+ raise ActiveRecord::StatementInvalid, "Table '#{table_name}' doesn't exist"
343
+ end
344
+
111
345
  @columns.fetch(table_name) do
112
346
  @columns[deep_deduplicate(table_name)] = deep_deduplicate(connection.columns(table_name))
113
347
  end
@@ -115,36 +349,37 @@ module ActiveRecord
115
349
 
116
350
  # Get the columns for a table as a hash, key is the column name
117
351
  # value is the column object.
118
- def columns_hash(table_name)
352
+ def columns_hash(connection, table_name)
119
353
  @columns_hash.fetch(table_name) do
120
- @columns_hash[deep_deduplicate(table_name)] = columns(table_name).index_by(&:name).freeze
354
+ @columns_hash[deep_deduplicate(table_name)] = columns(connection, table_name).index_by(&:name).freeze
121
355
  end
122
356
  end
123
357
 
124
358
  # Checks whether the columns hash is already cached for a table.
125
- def columns_hash?(table_name)
359
+ def columns_hash?(connection, table_name)
126
360
  @columns_hash.key?(table_name)
127
361
  end
128
362
 
129
- def indexes(table_name)
363
+ def indexes(connection, table_name)
130
364
  @indexes.fetch(table_name) do
131
- @indexes[deep_deduplicate(table_name)] = deep_deduplicate(connection.indexes(table_name))
365
+ if data_source_exists?(connection, table_name)
366
+ @indexes[deep_deduplicate(table_name)] = deep_deduplicate(connection.indexes(table_name))
367
+ else
368
+ []
369
+ end
132
370
  end
133
371
  end
134
372
 
135
- def database_version # :nodoc:
373
+ def database_version(connection) # :nodoc:
136
374
  @database_version ||= connection.get_database_version
137
375
  end
138
376
 
139
- # Clears out internal caches
140
- def clear!
141
- @columns.clear
142
- @columns_hash.clear
143
- @primary_keys.clear
144
- @data_sources.clear
145
- @indexes.clear
146
- @version = nil
147
- @database_version = nil
377
+ def version(connection)
378
+ @version ||= connection.schema_version
379
+ end
380
+
381
+ def schema_version
382
+ @version
148
383
  end
149
384
 
150
385
  def size
@@ -152,7 +387,7 @@ module ActiveRecord
152
387
  end
153
388
 
154
389
  # Clear out internal caches for the data source +name+.
155
- def clear_data_source_cache!(name)
390
+ def clear_data_source_cache!(_connection, name)
156
391
  @columns.delete name
157
392
  @columns_hash.delete name
158
393
  @primary_keys.delete name
@@ -160,9 +395,16 @@ module ActiveRecord
160
395
  @indexes.delete name
161
396
  end
162
397
 
398
+ def add_all(connection) # :nodoc:
399
+ tables_to_cache(connection).each do |table|
400
+ add(connection, table)
401
+ end
402
+
403
+ version(connection)
404
+ database_version(connection)
405
+ end
406
+
163
407
  def dump_to(filename)
164
- clear!
165
- connection.data_sources.each { |table| add(table) }
166
408
  open(filename) { |f|
167
409
  if filename.include?(".dump")
168
410
  f.write(Marshal.dump(self))
@@ -172,13 +414,11 @@ module ActiveRecord
172
414
  }
173
415
  end
174
416
 
175
- def marshal_dump
176
- reset_version!
177
-
178
- [@version, @columns, {}, @primary_keys, @data_sources, @indexes, database_version]
417
+ def marshal_dump # :nodoc:
418
+ [@version, @columns, {}, @primary_keys, @data_sources, @indexes, @database_version]
179
419
  end
180
420
 
181
- def marshal_load(array)
421
+ def marshal_load(array) # :nodoc:
182
422
  @version, @columns, _columns_hash, @primary_keys, @data_sources, @indexes, @database_version = array
183
423
  @indexes ||= {}
184
424
 
@@ -186,8 +426,16 @@ module ActiveRecord
186
426
  end
187
427
 
188
428
  private
189
- def reset_version!
190
- @version = connection.migration_context.current_version
429
+ def tables_to_cache(connection)
430
+ connection.data_sources.reject do |table|
431
+ ignored_table?(table)
432
+ end
433
+ end
434
+
435
+ def ignored_table?(table_name)
436
+ ActiveRecord.schema_cache_ignored_tables.any? do |ignored|
437
+ ignored === table_name
438
+ end
191
439
  end
192
440
 
193
441
  def derive_columns_hash_and_deduplicate_values
@@ -198,51 +446,32 @@ module ActiveRecord
198
446
  @indexes = deep_deduplicate(@indexes)
199
447
  end
200
448
 
201
- if RUBY_VERSION < "2.7"
202
- def deep_deduplicate(value)
203
- case value
204
- when Hash
205
- value.transform_keys { |k| deep_deduplicate(k) }.transform_values { |v| deep_deduplicate(v) }
206
- when Array
207
- value.map { |i| deep_deduplicate(i) }
208
- when String
209
- if value.tainted?
210
- # Ruby 2.6 and 2.7 have slightly different implementations of the String#-@ method.
211
- # In Ruby 2.6, the receiver of the String#-@ method is modified under certain
212
- # circumstances, and this was later identified as a bug
213
- # (https://bugs.ruby-lang.org/issues/15926) and only fixed in Ruby 2.7.
214
- value = value.dup
215
- end
216
- -value
217
- when Deduplicable
218
- -value
219
- else
220
- value
221
- end
222
- end
223
- else
224
- def deep_deduplicate(value)
225
- case value
226
- when Hash
227
- value.transform_keys { |k| deep_deduplicate(k) }.transform_values { |v| deep_deduplicate(v) }
228
- when Array
229
- value.map { |i| deep_deduplicate(i) }
230
- when String, Deduplicable
231
- -value
232
- else
233
- value
234
- end
449
+ def deep_deduplicate(value)
450
+ case value
451
+ when Hash
452
+ value.transform_keys { |k| deep_deduplicate(k) }.transform_values { |v| deep_deduplicate(v) }
453
+ when Array
454
+ value.map { |i| deep_deduplicate(i) }
455
+ when String, Deduplicable
456
+ -value
457
+ else
458
+ value
235
459
  end
236
460
  end
237
461
 
238
- def prepare_data_sources
239
- connection.data_sources.each { |source| @data_sources[source] = true }
462
+ def prepare_data_sources(connection)
463
+ tables_to_cache(connection).each do |source|
464
+ @data_sources[source] = true
465
+ end
240
466
  end
241
467
 
242
468
  def open(filename)
469
+ FileUtils.mkdir_p(File.dirname(filename))
470
+
243
471
  File.atomic_write(filename) do |file|
244
472
  if File.extname(filename) == ".gz"
245
473
  zipper = Zlib::GzipWriter.new file
474
+ zipper.mtime = 0
246
475
  yield zipper
247
476
  zipper.flush
248
477
  zipper.close
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ module SQLite3
6
+ class Column < ConnectionAdapters::Column # :nodoc:
7
+ attr_reader :rowid
8
+
9
+ def initialize(*, auto_increment: nil, rowid: false, **)
10
+ super
11
+ @auto_increment = auto_increment
12
+ @rowid = rowid
13
+ end
14
+
15
+ def auto_increment?
16
+ @auto_increment
17
+ end
18
+
19
+ def auto_incremented_by_db?
20
+ auto_increment? || rowid
21
+ end
22
+
23
+ def init_with(coder)
24
+ @auto_increment = coder["auto_increment"]
25
+ super
26
+ end
27
+
28
+ def encode_with(coder)
29
+ coder["auto_increment"] = @auto_increment
30
+ super
31
+ end
32
+
33
+ def ==(other)
34
+ other.is_a?(Column) &&
35
+ super &&
36
+ auto_increment? == other.auto_increment?
37
+ end
38
+ alias :eql? :==
39
+
40
+ def hash
41
+ Column.hash ^
42
+ super.hash ^
43
+ auto_increment?.hash ^
44
+ rowid.hash
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end