activerecord 6.1.7 → 7.2.0

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 (332) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +520 -1385
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +31 -31
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record/aggregations.rb +17 -14
  7. data/lib/active_record/association_relation.rb +2 -12
  8. data/lib/active_record/associations/alias_tracker.rb +25 -19
  9. data/lib/active_record/associations/association.rb +60 -21
  10. data/lib/active_record/associations/association_scope.rb +17 -12
  11. data/lib/active_record/associations/belongs_to_association.rb +37 -11
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -4
  13. data/lib/active_record/associations/builder/association.rb +11 -5
  14. data/lib/active_record/associations/builder/belongs_to.rb +41 -14
  15. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
  17. data/lib/active_record/associations/builder/has_many.rb +4 -4
  18. data/lib/active_record/associations/builder/has_one.rb +4 -4
  19. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  20. data/lib/active_record/associations/collection_association.rb +46 -36
  21. data/lib/active_record/associations/collection_proxy.rb +44 -16
  22. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  23. data/lib/active_record/associations/errors.rb +265 -0
  24. data/lib/active_record/associations/foreign_association.rb +10 -3
  25. data/lib/active_record/associations/has_many_association.rb +29 -19
  26. data/lib/active_record/associations/has_many_through_association.rb +12 -7
  27. data/lib/active_record/associations/has_one_association.rb +20 -10
  28. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  29. data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
  30. data/lib/active_record/associations/join_dependency.rb +23 -15
  31. data/lib/active_record/associations/nested_error.rb +47 -0
  32. data/lib/active_record/associations/preloader/association.rb +212 -53
  33. data/lib/active_record/associations/preloader/batch.rb +48 -0
  34. data/lib/active_record/associations/preloader/branch.rb +153 -0
  35. data/lib/active_record/associations/preloader/through_association.rb +50 -16
  36. data/lib/active_record/associations/preloader.rb +50 -121
  37. data/lib/active_record/associations/singular_association.rb +15 -3
  38. data/lib/active_record/associations/through_association.rb +25 -14
  39. data/lib/active_record/associations.rb +404 -509
  40. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  41. data/lib/active_record/attribute_assignment.rb +2 -14
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  43. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  44. data/lib/active_record/attribute_methods/dirty.rb +73 -22
  45. data/lib/active_record/attribute_methods/primary_key.rb +47 -27
  46. data/lib/active_record/attribute_methods/query.rb +31 -19
  47. data/lib/active_record/attribute_methods/read.rb +14 -11
  48. data/lib/active_record/attribute_methods/serialization.rb +174 -37
  49. data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -9
  50. data/lib/active_record/attribute_methods/write.rb +12 -15
  51. data/lib/active_record/attribute_methods.rb +164 -52
  52. data/lib/active_record/attributes.rb +51 -49
  53. data/lib/active_record/autosave_association.rb +74 -57
  54. data/lib/active_record/base.rb +27 -5
  55. data/lib/active_record/callbacks.rb +18 -34
  56. data/lib/active_record/coders/column_serializer.rb +61 -0
  57. data/lib/active_record/coders/json.rb +1 -1
  58. data/lib/active_record/coders/yaml_column.rb +70 -46
  59. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +327 -612
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -60
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +201 -64
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -131
  67. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  68. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  69. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  70. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  71. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +377 -142
  72. data/lib/active_record/connection_adapters/abstract/transaction.rb +361 -76
  73. data/lib/active_record/connection_adapters/abstract_adapter.rb +624 -163
  74. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +345 -166
  75. data/lib/active_record/connection_adapters/column.rb +13 -0
  76. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  77. data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -130
  78. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -55
  79. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  81. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  82. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +45 -14
  83. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
  84. data/lib/active_record/connection_adapters/mysql2_adapter.rb +107 -68
  85. data/lib/active_record/connection_adapters/pool_config.rb +26 -16
  86. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  87. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  88. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +114 -54
  89. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  94. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  96. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  97. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  100. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
  101. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  102. data/lib/active_record/connection_adapters/postgresql/quoting.rb +137 -104
  103. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  104. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  105. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +173 -3
  106. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  107. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +401 -77
  108. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  109. data/lib/active_record/connection_adapters/postgresql_adapter.rb +518 -251
  110. data/lib/active_record/connection_adapters/schema_cache.rb +326 -102
  111. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  112. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +78 -55
  113. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +68 -54
  114. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  115. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
  116. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  117. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +66 -22
  118. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +372 -130
  119. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  120. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  121. data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
  122. data/lib/active_record/connection_adapters.rb +130 -6
  123. data/lib/active_record/connection_handling.rb +132 -146
  124. data/lib/active_record/core.rb +276 -251
  125. data/lib/active_record/counter_cache.rb +68 -34
  126. data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -3
  127. data/lib/active_record/database_configurations/database_config.rb +34 -10
  128. data/lib/active_record/database_configurations/hash_config.rb +107 -31
  129. data/lib/active_record/database_configurations/url_config.rb +38 -13
  130. data/lib/active_record/database_configurations.rb +96 -60
  131. data/lib/active_record/delegated_type.rb +90 -20
  132. data/lib/active_record/deprecator.rb +7 -0
  133. data/lib/active_record/destroy_association_async_job.rb +4 -2
  134. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  135. data/lib/active_record/dynamic_matchers.rb +3 -3
  136. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  137. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  138. data/lib/active_record/encryption/cipher.rb +53 -0
  139. data/lib/active_record/encryption/config.rb +68 -0
  140. data/lib/active_record/encryption/configurable.rb +60 -0
  141. data/lib/active_record/encryption/context.rb +42 -0
  142. data/lib/active_record/encryption/contexts.rb +76 -0
  143. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  144. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  145. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  146. data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
  147. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  148. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  149. data/lib/active_record/encryption/encryptor.rb +170 -0
  150. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  151. data/lib/active_record/encryption/errors.rb +15 -0
  152. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  153. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  154. data/lib/active_record/encryption/key.rb +28 -0
  155. data/lib/active_record/encryption/key_generator.rb +53 -0
  156. data/lib/active_record/encryption/key_provider.rb +46 -0
  157. data/lib/active_record/encryption/message.rb +33 -0
  158. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  159. data/lib/active_record/encryption/message_serializer.rb +96 -0
  160. data/lib/active_record/encryption/null_encryptor.rb +25 -0
  161. data/lib/active_record/encryption/properties.rb +76 -0
  162. data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
  163. data/lib/active_record/encryption/scheme.rb +100 -0
  164. data/lib/active_record/encryption.rb +56 -0
  165. data/lib/active_record/enum.rb +163 -63
  166. data/lib/active_record/errors.rb +210 -27
  167. data/lib/active_record/explain.rb +21 -12
  168. data/lib/active_record/explain_registry.rb +11 -6
  169. data/lib/active_record/explain_subscriber.rb +1 -1
  170. data/lib/active_record/fixture_set/file.rb +15 -1
  171. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  172. data/lib/active_record/fixture_set/render_context.rb +2 -0
  173. data/lib/active_record/fixture_set/table_row.rb +70 -14
  174. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  175. data/lib/active_record/fixtures.rb +179 -112
  176. data/lib/active_record/future_result.rb +178 -0
  177. data/lib/active_record/gem_version.rb +4 -4
  178. data/lib/active_record/inheritance.rb +85 -31
  179. data/lib/active_record/insert_all.rb +148 -32
  180. data/lib/active_record/integration.rb +14 -10
  181. data/lib/active_record/internal_metadata.rb +123 -23
  182. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  183. data/lib/active_record/locking/optimistic.rb +43 -27
  184. data/lib/active_record/locking/pessimistic.rb +15 -6
  185. data/lib/active_record/log_subscriber.rb +41 -29
  186. data/lib/active_record/marshalling.rb +56 -0
  187. data/lib/active_record/message_pack.rb +124 -0
  188. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  189. data/lib/active_record/middleware/database_selector.rb +23 -13
  190. data/lib/active_record/middleware/shard_selector.rb +62 -0
  191. data/lib/active_record/migration/command_recorder.rb +113 -16
  192. data/lib/active_record/migration/compatibility.rb +235 -46
  193. data/lib/active_record/migration/default_strategy.rb +22 -0
  194. data/lib/active_record/migration/execution_strategy.rb +19 -0
  195. data/lib/active_record/migration/join_table.rb +1 -1
  196. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  197. data/lib/active_record/migration.rb +374 -177
  198. data/lib/active_record/model_schema.rb +143 -159
  199. data/lib/active_record/nested_attributes.rb +48 -21
  200. data/lib/active_record/no_touching.rb +3 -3
  201. data/lib/active_record/normalization.rb +163 -0
  202. data/lib/active_record/persistence.rb +282 -283
  203. data/lib/active_record/promise.rb +84 -0
  204. data/lib/active_record/query_cache.rb +19 -25
  205. data/lib/active_record/query_logs.rb +189 -0
  206. data/lib/active_record/query_logs_formatter.rb +41 -0
  207. data/lib/active_record/querying.rb +44 -9
  208. data/lib/active_record/railtie.rb +234 -71
  209. data/lib/active_record/railties/controller_runtime.rb +25 -11
  210. data/lib/active_record/railties/databases.rake +189 -256
  211. data/lib/active_record/railties/job_runtime.rb +23 -0
  212. data/lib/active_record/readonly_attributes.rb +41 -3
  213. data/lib/active_record/reflection.rb +325 -103
  214. data/lib/active_record/relation/batches/batch_enumerator.rb +38 -9
  215. data/lib/active_record/relation/batches.rb +198 -63
  216. data/lib/active_record/relation/calculations.rb +300 -111
  217. data/lib/active_record/relation/delegation.rb +33 -22
  218. data/lib/active_record/relation/finder_methods.rb +123 -52
  219. data/lib/active_record/relation/merger.rb +26 -19
  220. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  221. data/lib/active_record/relation/predicate_builder/association_query_value.rb +38 -4
  222. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  223. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  224. data/lib/active_record/relation/predicate_builder.rb +29 -22
  225. data/lib/active_record/relation/query_attribute.rb +30 -12
  226. data/lib/active_record/relation/query_methods.rb +842 -150
  227. data/lib/active_record/relation/record_fetch_warning.rb +10 -9
  228. data/lib/active_record/relation/spawn_methods.rb +7 -6
  229. data/lib/active_record/relation/where_clause.rb +15 -36
  230. data/lib/active_record/relation.rb +736 -145
  231. data/lib/active_record/result.rb +67 -54
  232. data/lib/active_record/runtime_registry.rb +71 -13
  233. data/lib/active_record/sanitization.rb +84 -34
  234. data/lib/active_record/schema.rb +39 -23
  235. data/lib/active_record/schema_dumper.rb +90 -31
  236. data/lib/active_record/schema_migration.rb +74 -23
  237. data/lib/active_record/scoping/default.rb +72 -15
  238. data/lib/active_record/scoping/named.rb +5 -13
  239. data/lib/active_record/scoping.rb +65 -34
  240. data/lib/active_record/secure_password.rb +60 -0
  241. data/lib/active_record/secure_token.rb +21 -3
  242. data/lib/active_record/serialization.rb +6 -1
  243. data/lib/active_record/signed_id.rb +30 -9
  244. data/lib/active_record/statement_cache.rb +7 -7
  245. data/lib/active_record/store.rb +10 -10
  246. data/lib/active_record/suppressor.rb +13 -15
  247. data/lib/active_record/table_metadata.rb +7 -3
  248. data/lib/active_record/tasks/database_tasks.rb +277 -149
  249. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  250. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  251. data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
  252. data/lib/active_record/test_databases.rb +1 -1
  253. data/lib/active_record/test_fixtures.rb +173 -155
  254. data/lib/active_record/testing/query_assertions.rb +121 -0
  255. data/lib/active_record/timestamp.rb +32 -19
  256. data/lib/active_record/token_for.rb +123 -0
  257. data/lib/active_record/touch_later.rb +12 -7
  258. data/lib/active_record/transaction.rb +132 -0
  259. data/lib/active_record/transactions.rb +118 -41
  260. data/lib/active_record/translation.rb +3 -5
  261. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  262. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  263. data/lib/active_record/type/internal/timezone.rb +7 -2
  264. data/lib/active_record/type/serialized.rb +9 -7
  265. data/lib/active_record/type/time.rb +4 -0
  266. data/lib/active_record/type/type_map.rb +17 -20
  267. data/lib/active_record/type.rb +1 -2
  268. data/lib/active_record/type_caster/connection.rb +4 -4
  269. data/lib/active_record/validations/absence.rb +1 -1
  270. data/lib/active_record/validations/associated.rb +13 -7
  271. data/lib/active_record/validations/numericality.rb +5 -4
  272. data/lib/active_record/validations/presence.rb +5 -28
  273. data/lib/active_record/validations/uniqueness.rb +64 -15
  274. data/lib/active_record/validations.rb +12 -5
  275. data/lib/active_record/version.rb +1 -1
  276. data/lib/active_record.rb +444 -32
  277. data/lib/arel/alias_predication.rb +1 -1
  278. data/lib/arel/attributes/attribute.rb +0 -8
  279. data/lib/arel/collectors/bind.rb +2 -0
  280. data/lib/arel/collectors/composite.rb +7 -0
  281. data/lib/arel/collectors/sql_string.rb +1 -1
  282. data/lib/arel/collectors/substitute_binds.rb +1 -1
  283. data/lib/arel/crud.rb +28 -22
  284. data/lib/arel/delete_manager.rb +18 -4
  285. data/lib/arel/errors.rb +10 -0
  286. data/lib/arel/factory_methods.rb +4 -0
  287. data/lib/arel/filter_predications.rb +9 -0
  288. data/lib/arel/insert_manager.rb +2 -3
  289. data/lib/arel/nodes/binary.rb +6 -7
  290. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  291. data/lib/arel/nodes/casted.rb +1 -1
  292. data/lib/arel/nodes/cte.rb +36 -0
  293. data/lib/arel/nodes/delete_statement.rb +12 -13
  294. data/lib/arel/nodes/filter.rb +10 -0
  295. data/lib/arel/nodes/fragments.rb +35 -0
  296. data/lib/arel/nodes/function.rb +1 -0
  297. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  298. data/lib/arel/nodes/insert_statement.rb +2 -2
  299. data/lib/arel/nodes/leading_join.rb +8 -0
  300. data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
  301. data/lib/arel/nodes/node.rb +115 -5
  302. data/lib/arel/nodes/select_core.rb +2 -2
  303. data/lib/arel/nodes/select_statement.rb +2 -2
  304. data/lib/arel/nodes/sql_literal.rb +13 -0
  305. data/lib/arel/nodes/table_alias.rb +4 -0
  306. data/lib/arel/nodes/update_statement.rb +8 -3
  307. data/lib/arel/nodes.rb +7 -2
  308. data/lib/arel/predications.rb +14 -4
  309. data/lib/arel/select_manager.rb +11 -5
  310. data/lib/arel/table.rb +9 -6
  311. data/lib/arel/tree_manager.rb +8 -15
  312. data/lib/arel/update_manager.rb +20 -5
  313. data/lib/arel/visitors/dot.rb +81 -90
  314. data/lib/arel/visitors/mysql.rb +23 -5
  315. data/lib/arel/visitors/postgresql.rb +1 -22
  316. data/lib/arel/visitors/to_sql.rb +170 -36
  317. data/lib/arel/visitors/visitor.rb +2 -2
  318. data/lib/arel.rb +23 -4
  319. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  320. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  321. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
  322. data/lib/rails/generators/active_record/migration.rb +3 -1
  323. data/lib/rails/generators/active_record/model/USAGE +113 -0
  324. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  325. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  326. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  327. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  328. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  329. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  330. metadata +100 -14
  331. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  332. data/lib/active_record/null_relation.rb +0 -67
@@ -7,14 +7,13 @@ module ActiveRecord
7
7
  #
8
8
  # This class is used to dump the database schema for some connection to some
9
9
  # output format (i.e., ActiveRecord::Schema).
10
- class SchemaDumper #:nodoc:
10
+ class SchemaDumper # :nodoc:
11
11
  private_class_method :new
12
12
 
13
13
  ##
14
14
  # :singleton-method:
15
15
  # A list of tables which should not be dumped to the schema.
16
- # Acceptable values are strings as well as regexp if ActiveRecord::Base.schema_format == :ruby.
17
- # Only strings are accepted if ActiveRecord::Base.schema_format == :sql.
16
+ # Acceptable values are strings and regexps.
18
17
  cattr_accessor :ignore_tables, default: []
19
18
 
20
19
  ##
@@ -29,9 +28,23 @@ module ActiveRecord
29
28
  # should not be dumped to db/schema.rb.
30
29
  cattr_accessor :chk_ignore_pattern, default: /^chk_rails_[0-9a-f]{10}$/
31
30
 
31
+ ##
32
+ # :singleton-method:
33
+ # Specify a custom regular expression matching exclusion constraints which name
34
+ # should not be dumped to db/schema.rb.
35
+ cattr_accessor :excl_ignore_pattern, default: /^excl_rails_[0-9a-f]{10}$/
36
+
37
+ ##
38
+ # :singleton-method:
39
+ # Specify a custom regular expression matching unique constraints which name
40
+ # should not be dumped to db/schema.rb.
41
+ cattr_accessor :unique_ignore_pattern, default: /^uniq_rails_[0-9a-f]{10}$/
42
+
32
43
  class << self
33
- def dump(connection = ActiveRecord::Base.connection, stream = STDOUT, config = ActiveRecord::Base)
34
- connection.create_schema_dumper(generate_options(config)).dump(stream)
44
+ def dump(pool = ActiveRecord::Base.connection_pool, stream = $stdout, config = ActiveRecord::Base)
45
+ pool.with_connection do |connection|
46
+ connection.create_schema_dumper(generate_options(config)).dump(stream)
47
+ end
35
48
  stream
36
49
  end
37
50
 
@@ -46,7 +59,9 @@ module ActiveRecord
46
59
 
47
60
  def dump(stream)
48
61
  header(stream)
62
+ schemas(stream)
49
63
  extensions(stream)
64
+ types(stream)
50
65
  tables(stream)
51
66
  trailer(stream)
52
67
  stream
@@ -57,8 +72,13 @@ module ActiveRecord
57
72
 
58
73
  def initialize(connection, options = {})
59
74
  @connection = connection
60
- @version = connection.migration_context.current_version rescue nil
75
+ @version = connection.pool.migration_context.current_version rescue nil
61
76
  @options = options
77
+ @ignore_tables = [
78
+ ActiveRecord::Base.schema_migrations_table_name,
79
+ ActiveRecord::Base.internal_metadata_table_name,
80
+ self.class.ignore_tables
81
+ ].flatten
62
82
  end
63
83
 
64
84
  # turns 20170404131909 into "2017_04_04_131909"
@@ -73,22 +93,21 @@ module ActiveRecord
73
93
  end
74
94
 
75
95
  def header(stream)
76
- stream.puts <<HEADER
77
- # This file is auto-generated from the current state of the database. Instead
78
- # of editing this file, please use the migrations feature of Active Record to
79
- # incrementally modify your database, and then regenerate this schema definition.
80
- #
81
- # This file is the source Rails uses to define your schema when running `bin/rails
82
- # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
83
- # be faster and is potentially less error prone than running all of your
84
- # migrations from scratch. Old migrations may fail to apply correctly if those
85
- # migrations use external dependencies or application code.
86
- #
87
- # It's strongly recommended that you check this file into your version control system.
88
-
89
- ActiveRecord::Schema.define(#{define_params}) do
90
-
91
- HEADER
96
+ stream.puts <<~HEADER
97
+ # This file is auto-generated from the current state of the database. Instead
98
+ # of editing this file, please use the migrations feature of Active Record to
99
+ # incrementally modify your database, and then regenerate this schema definition.
100
+ #
101
+ # This file is the source Rails uses to define your schema when running `bin/rails
102
+ # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
103
+ # be faster and is potentially less error prone than running all of your
104
+ # migrations from scratch. Old migrations may fail to apply correctly if those
105
+ # migrations use external dependencies or application code.
106
+ #
107
+ # It's strongly recommended that you check this file into your version control system.
108
+
109
+ ActiveRecord::Schema[#{ActiveRecord::Migration.current_version}].define(#{define_params}) do
110
+ HEADER
92
111
  end
93
112
 
94
113
  def trailer(stream)
@@ -99,18 +118,35 @@ HEADER
99
118
  def extensions(stream)
100
119
  end
101
120
 
121
+ # (enum) types are only supported by PostgreSQL
122
+ def types(stream)
123
+ end
124
+
125
+ # schemas are only supported by PostgreSQL
126
+ def schemas(stream)
127
+ end
128
+
102
129
  def tables(stream)
103
130
  sorted_tables = @connection.tables.sort
104
131
 
105
- sorted_tables.each do |table_name|
106
- table(table_name, stream) unless ignored?(table_name)
132
+ not_ignored_tables = sorted_tables.reject { |table_name| ignored?(table_name) }
133
+
134
+ not_ignored_tables.each_with_index do |table_name, index|
135
+ table(table_name, stream)
136
+ stream.puts if index < not_ignored_tables.count - 1
107
137
  end
108
138
 
109
139
  # dump foreign keys at the end to make sure all dependent tables exist.
110
140
  if @connection.supports_foreign_keys?
111
- sorted_tables.each do |tbl|
112
- foreign_keys(tbl, stream) unless ignored?(tbl)
141
+ foreign_keys_stream = StringIO.new
142
+ not_ignored_tables.each do |tbl|
143
+ foreign_keys(tbl, foreign_keys_stream)
113
144
  end
145
+
146
+ foreign_keys_string = foreign_keys_stream.string
147
+ stream.puts if foreign_keys_string.length > 0
148
+
149
+ stream.print foreign_keys_string
114
150
  end
115
151
  end
116
152
 
@@ -154,6 +190,7 @@ HEADER
154
190
  columns.each do |column|
155
191
  raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" unless @connection.valid_type?(column.type)
156
192
  next if column.name == pk
193
+
157
194
  type, colspec = column_spec(column)
158
195
  if type.is_a?(Symbol)
159
196
  tbl.print " t.#{type} #{column.name.inspect}"
@@ -166,12 +203,12 @@ HEADER
166
203
 
167
204
  indexes_in_create(table, tbl)
168
205
  check_constraints_in_create(table, tbl) if @connection.supports_check_constraints?
206
+ exclusion_constraints_in_create(table, tbl) if @connection.supports_exclusion_constraints?
207
+ unique_constraints_in_create(table, tbl) if @connection.supports_unique_constraints?
169
208
 
170
209
  tbl.puts " end"
171
- tbl.puts
172
210
 
173
- tbl.rewind
174
- stream.print tbl.read
211
+ stream.print tbl.string
175
212
  rescue => e
176
213
  stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
177
214
  stream.puts "# #{e.message}"
@@ -196,6 +233,18 @@ HEADER
196
233
 
197
234
  def indexes_in_create(table, stream)
198
235
  if (indexes = @connection.indexes(table)).any?
236
+ if @connection.supports_exclusion_constraints? && (exclusion_constraints = @connection.exclusion_constraints(table)).any?
237
+ exclusion_constraint_names = exclusion_constraints.collect(&:name)
238
+
239
+ indexes = indexes.reject { |index| exclusion_constraint_names.include?(index.name) }
240
+ end
241
+
242
+ if @connection.supports_unique_constraints? && (unique_constraints = @connection.unique_constraints(table)).any?
243
+ unique_constraint_names = unique_constraints.collect(&:name)
244
+
245
+ indexes = indexes.reject { |index| unique_constraint_names.include?(index.name) }
246
+ end
247
+
199
248
  index_statements = indexes.map do |index|
200
249
  " t.index #{index_parts(index).join(', ')}"
201
250
  end
@@ -214,6 +263,8 @@ HEADER
214
263
  index_parts << "opclass: #{format_index_parts(index.opclasses)}" if index.opclasses.present?
215
264
  index_parts << "where: #{index.where.inspect}" if index.where
216
265
  index_parts << "using: #{index.using.inspect}" if !@connection.default_index_type?(index)
266
+ index_parts << "include: #{index.include.inspect}" if index.include
267
+ index_parts << "nulls_not_distinct: #{index.nulls_not_distinct.inspect}" if index.nulls_not_distinct
217
268
  index_parts << "type: #{index.type.inspect}" if index.type
218
269
  index_parts << "comment: #{index.comment.inspect}" if index.comment
219
270
  index_parts
@@ -230,6 +281,8 @@ HEADER
230
281
  parts << "name: #{check_constraint.name.inspect}"
231
282
  end
232
283
 
284
+ parts << "validate: #{check_constraint.validate?.inspect}" unless check_constraint.validate?
285
+
233
286
  " #{parts.join(', ')}"
234
287
  end
235
288
 
@@ -245,7 +298,7 @@ HEADER
245
298
  remove_prefix_and_suffix(foreign_key.to_table).inspect,
246
299
  ]
247
300
 
248
- if foreign_key.column != @connection.foreign_key_column_for(foreign_key.to_table)
301
+ if foreign_key.column != @connection.foreign_key_column_for(foreign_key.to_table, "id")
249
302
  parts << "column: #{foreign_key.column.inspect}"
250
303
  end
251
304
 
@@ -259,6 +312,8 @@ HEADER
259
312
 
260
313
  parts << "on_update: #{foreign_key.on_update.inspect}" if foreign_key.on_update
261
314
  parts << "on_delete: #{foreign_key.on_delete.inspect}" if foreign_key.on_delete
315
+ parts << "deferrable: #{foreign_key.deferrable.inspect}" if foreign_key.deferrable
316
+ parts << "validate: #{foreign_key.validate?.inspect}" unless foreign_key.validate?
262
317
 
263
318
  " #{parts.join(', ')}"
264
319
  end
@@ -286,13 +341,17 @@ HEADER
286
341
  end
287
342
 
288
343
  def remove_prefix_and_suffix(table)
344
+ # This method appears at the top when profiling active_record test cases run.
345
+ # Avoid costly calculation when there are no prefix and suffix.
346
+ return table if @options[:table_name_prefix].blank? && @options[:table_name_suffix].blank?
347
+
289
348
  prefix = Regexp.escape(@options[:table_name_prefix].to_s)
290
349
  suffix = Regexp.escape(@options[:table_name_suffix].to_s)
291
350
  table.sub(/\A#{prefix}(.+)#{suffix}\z/, "\\1")
292
351
  end
293
352
 
294
353
  def ignored?(table_name)
295
- [ActiveRecord::Base.schema_migrations_table_name, ActiveRecord::Base.internal_metadata_table_name, ignore_tables].flatten.any? do |ignored|
354
+ @ignore_tables.any? do |ignored|
296
355
  ignored === remove_prefix_and_suffix(table_name)
297
356
  end
298
357
  end
@@ -1,54 +1,105 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_record/scoping/default"
4
- require "active_record/scoping/named"
5
-
6
3
  module ActiveRecord
7
4
  # This class is used to create a table that keeps track of which migrations
8
5
  # have been applied to a given database. When a migration is run, its schema
9
- # number is inserted in to the `SchemaMigration.table_name` so it doesn't need
6
+ # number is inserted in to the schema migrations table so it doesn't need
10
7
  # to be executed the next time.
11
- class SchemaMigration < ActiveRecord::Base # :nodoc:
12
- class << self
13
- def _internal?
14
- true
8
+ class SchemaMigration # :nodoc:
9
+ class NullSchemaMigration # :nodoc:
10
+ end
11
+
12
+ attr_reader :arel_table
13
+
14
+ def initialize(pool)
15
+ @pool = pool
16
+ @arel_table = Arel::Table.new(table_name)
17
+ end
18
+
19
+ def create_version(version)
20
+ im = Arel::InsertManager.new(arel_table)
21
+ im.insert(arel_table[primary_key] => version)
22
+ @pool.with_connection do |connection|
23
+ connection.insert(im, "#{self.class} Create", primary_key, version)
15
24
  end
25
+ end
16
26
 
17
- def primary_key
18
- "version"
27
+ def delete_version(version)
28
+ dm = Arel::DeleteManager.new(arel_table)
29
+ dm.wheres = [arel_table[primary_key].eq(version)]
30
+
31
+ @pool.with_connection do |connection|
32
+ connection.delete(dm, "#{self.class} Destroy")
19
33
  end
34
+ end
20
35
 
21
- def table_name
22
- "#{table_name_prefix}#{schema_migrations_table_name}#{table_name_suffix}"
36
+ def delete_all_versions
37
+ @pool.with_connection do |connection|
38
+ versions.each do |version|
39
+ delete_version(version)
40
+ end
23
41
  end
42
+ end
24
43
 
25
- def create_table
44
+ def primary_key
45
+ "version"
46
+ end
47
+
48
+ def table_name
49
+ "#{ActiveRecord::Base.table_name_prefix}#{ActiveRecord::Base.schema_migrations_table_name}#{ActiveRecord::Base.table_name_suffix}"
50
+ end
51
+
52
+ def create_table
53
+ @pool.with_connection do |connection|
26
54
  unless connection.table_exists?(table_name)
27
55
  connection.create_table(table_name, id: false) do |t|
28
56
  t.string :version, **connection.internal_string_options_for_primary_key
29
57
  end
30
58
  end
31
59
  end
60
+ end
32
61
 
33
- def drop_table
62
+ def drop_table
63
+ @pool.with_connection do |connection|
34
64
  connection.drop_table table_name, if_exists: true
35
65
  end
66
+ end
36
67
 
37
- def normalize_migration_number(number)
38
- "%.3d" % number.to_i
39
- end
68
+ def normalize_migration_number(number)
69
+ "%.3d" % number.to_i
70
+ end
71
+
72
+ def normalized_versions
73
+ versions.map { |v| normalize_migration_number v }
74
+ end
40
75
 
41
- def normalized_versions
42
- all_versions.map { |v| normalize_migration_number v }
76
+ def versions
77
+ sm = Arel::SelectManager.new(arel_table)
78
+ sm.project(arel_table[primary_key])
79
+ sm.order(arel_table[primary_key].asc)
80
+
81
+ @pool.with_connection do |connection|
82
+ connection.select_values(sm, "#{self.class} Load")
43
83
  end
84
+ end
85
+
86
+ def integer_versions
87
+ versions.map(&:to_i)
88
+ end
89
+
90
+ def count
91
+ sm = Arel::SelectManager.new(arel_table)
92
+ sm.project(*Arel::Nodes::Count.new([Arel.star]))
44
93
 
45
- def all_versions
46
- order(:version).pluck(:version)
94
+ @pool.with_connection do |connection|
95
+ connection.select_values(sm, "#{self.class} Count").first
47
96
  end
48
97
  end
49
98
 
50
- def version
51
- super.to_i
99
+ def table_exists?
100
+ @pool.with_connection do |connection|
101
+ connection.data_source_exists?(table_name)
102
+ end
52
103
  end
53
104
  end
54
105
  end
@@ -2,6 +2,15 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Scoping
5
+ class DefaultScope # :nodoc:
6
+ attr_reader :scope, :all_queries
7
+
8
+ def initialize(scope, all_queries = nil)
9
+ @scope = scope
10
+ @all_queries = all_queries
11
+ end
12
+ end
13
+
5
14
  module Default
6
15
  extend ActiveSupport::Concern
7
16
 
@@ -15,14 +24,22 @@ module ActiveRecord
15
24
  # Returns a scope for the model without the previously set scopes.
16
25
  #
17
26
  # class Post < ActiveRecord::Base
27
+ # belongs_to :user
28
+ #
18
29
  # def self.default_scope
19
30
  # where(published: true)
20
31
  # end
21
32
  # end
22
33
  #
34
+ # class User < ActiveRecord::Base
35
+ # has_many :posts
36
+ # end
37
+ #
23
38
  # Post.all # Fires "SELECT * FROM posts WHERE published = true"
24
39
  # Post.unscoped.all # Fires "SELECT * FROM posts"
25
40
  # Post.where(published: false).unscoped.all # Fires "SELECT * FROM posts"
41
+ # User.find(1).posts # Fires "SELECT * FROM posts WHERE published = true AND posts.user_id = 1"
42
+ # User.find(1).posts.unscoped # Fires "SELECT * FROM posts"
26
43
  #
27
44
  # This method also accepts a block. All queries inside the block will
28
45
  # not use the previously set scopes.
@@ -30,8 +47,8 @@ module ActiveRecord
30
47
  # Post.unscoped {
31
48
  # Post.limit(10) # Fires "SELECT * FROM posts LIMIT 10"
32
49
  # }
33
- def unscoped
34
- block_given? ? relation.scoping { yield } : relation
50
+ def unscoped(&block)
51
+ block_given? ? relation.scoping(&block) : relation
35
52
  end
36
53
 
37
54
  # Are there attributes associated with this scope?
@@ -39,8 +56,15 @@ module ActiveRecord
39
56
  super || default_scopes.any? || respond_to?(:default_scope)
40
57
  end
41
58
 
42
- def before_remove_const #:nodoc:
43
- self.current_scope = nil
59
+ # Checks if the model has any default scopes. If all_queries
60
+ # is set to true, the method will check if there are any
61
+ # default_scopes for the model where +all_queries+ is true.
62
+ def default_scopes?(all_queries: false)
63
+ if all_queries
64
+ self.default_scopes.any?(&:all_queries)
65
+ else
66
+ self.default_scopes.any?
67
+ end
44
68
  end
45
69
 
46
70
  private
@@ -51,14 +75,30 @@ module ActiveRecord
51
75
  # default_scope { where(published: true) }
52
76
  # end
53
77
  #
54
- # Article.all # => SELECT * FROM articles WHERE published = true
78
+ # Article.all
79
+ # # SELECT * FROM articles WHERE published = true
55
80
  #
56
81
  # The #default_scope is also applied while creating/building a record.
57
- # It is not applied while updating a record.
82
+ # It is not applied while updating or deleting a record.
58
83
  #
59
84
  # Article.new.published # => true
60
85
  # Article.create.published # => true
61
86
  #
87
+ # To apply a #default_scope when updating or deleting a record, add
88
+ # <tt>all_queries: true</tt>:
89
+ #
90
+ # class Article < ActiveRecord::Base
91
+ # default_scope -> { where(blog_id: 1) }, all_queries: true
92
+ # end
93
+ #
94
+ # Applying a default scope to all queries will ensure that records
95
+ # are always queried by the additional conditions. Note that only
96
+ # where clauses apply, as it does not make sense to add order to
97
+ # queries that return a single object by primary key.
98
+ #
99
+ # Article.find(1).destroy
100
+ # # DELETE ... FROM `articles` where ID = 1 AND blog_id = 1;
101
+ #
62
102
  # (You can also pass any object which responds to +call+ to the
63
103
  # +default_scope+ macro, and it will be called when building the
64
104
  # default scope.)
@@ -71,7 +111,8 @@ module ActiveRecord
71
111
  # default_scope { where(rating: 'G') }
72
112
  # end
73
113
  #
74
- # Article.all # => SELECT * FROM articles WHERE published = true AND rating = 'G'
114
+ # Article.all
115
+ # # SELECT * FROM articles WHERE published = true AND rating = 'G'
75
116
  #
76
117
  # This is also the case with inheritance and module includes where the
77
118
  # parent or module defines a #default_scope and the child or including
@@ -85,7 +126,7 @@ module ActiveRecord
85
126
  # # Should return a scope, you can call 'super' here etc.
86
127
  # end
87
128
  # end
88
- def default_scope(scope = nil, &block) # :doc:
129
+ def default_scope(scope = nil, all_queries: nil, &block) # :doc:
89
130
  scope = block if block_given?
90
131
 
91
132
  if scope.is_a?(Relation) || !scope.respond_to?(:call)
@@ -96,10 +137,12 @@ module ActiveRecord
96
137
  "self.default_scope.)"
97
138
  end
98
139
 
99
- self.default_scopes += [scope]
140
+ default_scope = DefaultScope.new(scope, all_queries)
141
+
142
+ self.default_scopes += [default_scope]
100
143
  end
101
144
 
102
- def build_default_scope(relation = relation())
145
+ def build_default_scope(relation = relation(), all_queries: nil)
103
146
  return if abstract_class?
104
147
 
105
148
  if default_scope_override.nil?
@@ -113,20 +156,34 @@ module ActiveRecord
113
156
  end
114
157
  elsif default_scopes.any?
115
158
  evaluate_default_scope do
116
- default_scopes.inject(relation) do |default_scope, scope|
117
- scope = scope.respond_to?(:to_proc) ? scope : scope.method(:call)
118
- default_scope.instance_exec(&scope) || default_scope
159
+ default_scopes.inject(relation) do |combined_scope, scope_obj|
160
+ if execute_scope?(all_queries, scope_obj)
161
+ scope = scope_obj.scope.respond_to?(:to_proc) ? scope_obj.scope : scope_obj.scope.method(:call)
162
+
163
+ combined_scope.instance_exec(&scope) || combined_scope
164
+ else
165
+ combined_scope
166
+ end
119
167
  end
120
168
  end
121
169
  end
122
170
  end
123
171
 
172
+ # If all_queries is nil, only execute on select and insert queries.
173
+ #
174
+ # If all_queries is true, check if the default_scope object has
175
+ # all_queries set, then execute on all queries; select, insert, update,
176
+ # delete, and reload.
177
+ def execute_scope?(all_queries, default_scope_obj)
178
+ all_queries.nil? || all_queries && default_scope_obj.all_queries
179
+ end
180
+
124
181
  def ignore_default_scope?
125
- ScopeRegistry.value_for(:ignore_default_scope, base_class)
182
+ ScopeRegistry.ignore_default_scope(base_class)
126
183
  end
127
184
 
128
185
  def ignore_default_scope=(ignore)
129
- ScopeRegistry.set_value_for(:ignore_default_scope, base_class, ignore)
186
+ ScopeRegistry.set_ignore_default_scope(base_class, ignore)
130
187
  end
131
188
 
132
189
  # The ignore_default_scope flag is used to prevent an infinite recursion
@@ -19,7 +19,7 @@ module ActiveRecord
19
19
  #
20
20
  # You can define a scope that applies to all finders using
21
21
  # {default_scope}[rdoc-ref:Scoping::Default::ClassMethods#default_scope].
22
- def all
22
+ def all(all_queries: nil)
23
23
  scope = current_scope
24
24
 
25
25
  if scope
@@ -29,7 +29,7 @@ module ActiveRecord
29
29
  relation.merge!(scope)
30
30
  end
31
31
  else
32
- default_scoped
32
+ default_scoped(all_queries: all_queries)
33
33
  end
34
34
  end
35
35
 
@@ -42,8 +42,8 @@ module ActiveRecord
42
42
  end
43
43
 
44
44
  # Returns a scope for the model with default scopes.
45
- def default_scoped(scope = relation)
46
- build_default_scope(scope) || scope
45
+ def default_scoped(scope = relation, all_queries: nil)
46
+ build_default_scope(scope, all_queries: all_queries) || scope
47
47
  end
48
48
 
49
49
  def default_extensions # :nodoc:
@@ -168,7 +168,6 @@ module ActiveRecord
168
168
  "an instance method with the same name."
169
169
  end
170
170
 
171
- valid_scope_name?(name)
172
171
  extension = Module.new(&block) if block
173
172
 
174
173
  if body.respond_to?(:to_proc)
@@ -184,7 +183,7 @@ module ActiveRecord
184
183
  scope
185
184
  end
186
185
  end
187
- singleton_class.send(:ruby2_keywords, name) if respond_to?(:ruby2_keywords, true)
186
+ singleton_class.send(:ruby2_keywords, name)
188
187
 
189
188
  generate_relation_method(name)
190
189
  end
@@ -193,13 +192,6 @@ module ActiveRecord
193
192
  def singleton_method_added(name)
194
193
  generate_relation_method(name) if Kernel.respond_to?(name) && !ActiveRecord::Relation.method_defined?(name)
195
194
  end
196
-
197
- def valid_scope_name?(name)
198
- if respond_to?(name, true) && logger
199
- logger.warn "Creating scope :#{name}. " \
200
- "Overwriting existing method #{self.name}.#{name}."
201
- end
202
- end
203
195
  end
204
196
  end
205
197
  end