omg-activerecord 8.0.0.alpha1

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 (412) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +355 -0
  3. data/MIT-LICENSE +22 -0
  4. data/README.rdoc +219 -0
  5. data/examples/performance.rb +185 -0
  6. data/examples/simple.rb +15 -0
  7. data/lib/active_record/aggregations.rb +287 -0
  8. data/lib/active_record/association_relation.rb +50 -0
  9. data/lib/active_record/associations/alias_tracker.rb +90 -0
  10. data/lib/active_record/associations/association.rb +417 -0
  11. data/lib/active_record/associations/association_scope.rb +175 -0
  12. data/lib/active_record/associations/belongs_to_association.rb +163 -0
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
  14. data/lib/active_record/associations/builder/association.rb +170 -0
  15. data/lib/active_record/associations/builder/belongs_to.rb +160 -0
  16. data/lib/active_record/associations/builder/collection_association.rb +80 -0
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +107 -0
  18. data/lib/active_record/associations/builder/has_many.rb +23 -0
  19. data/lib/active_record/associations/builder/has_one.rb +61 -0
  20. data/lib/active_record/associations/builder/singular_association.rb +48 -0
  21. data/lib/active_record/associations/collection_association.rb +535 -0
  22. data/lib/active_record/associations/collection_proxy.rb +1163 -0
  23. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  24. data/lib/active_record/associations/errors.rb +265 -0
  25. data/lib/active_record/associations/foreign_association.rb +40 -0
  26. data/lib/active_record/associations/has_many_association.rb +167 -0
  27. data/lib/active_record/associations/has_many_through_association.rb +232 -0
  28. data/lib/active_record/associations/has_one_association.rb +142 -0
  29. data/lib/active_record/associations/has_one_through_association.rb +45 -0
  30. data/lib/active_record/associations/join_dependency/join_association.rb +106 -0
  31. data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
  32. data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
  33. data/lib/active_record/associations/join_dependency.rb +301 -0
  34. data/lib/active_record/associations/nested_error.rb +47 -0
  35. data/lib/active_record/associations/preloader/association.rb +316 -0
  36. data/lib/active_record/associations/preloader/batch.rb +48 -0
  37. data/lib/active_record/associations/preloader/branch.rb +153 -0
  38. data/lib/active_record/associations/preloader/through_association.rb +150 -0
  39. data/lib/active_record/associations/preloader.rb +135 -0
  40. data/lib/active_record/associations/singular_association.rb +76 -0
  41. data/lib/active_record/associations/through_association.rb +132 -0
  42. data/lib/active_record/associations.rb +1897 -0
  43. data/lib/active_record/asynchronous_queries_tracker.rb +64 -0
  44. data/lib/active_record/attribute_assignment.rb +82 -0
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +106 -0
  46. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  47. data/lib/active_record/attribute_methods/dirty.rb +262 -0
  48. data/lib/active_record/attribute_methods/primary_key.rb +158 -0
  49. data/lib/active_record/attribute_methods/query.rb +50 -0
  50. data/lib/active_record/attribute_methods/read.rb +46 -0
  51. data/lib/active_record/attribute_methods/serialization.rb +232 -0
  52. data/lib/active_record/attribute_methods/time_zone_conversion.rb +94 -0
  53. data/lib/active_record/attribute_methods/write.rb +49 -0
  54. data/lib/active_record/attribute_methods.rb +542 -0
  55. data/lib/active_record/attributes.rb +307 -0
  56. data/lib/active_record/autosave_association.rb +586 -0
  57. data/lib/active_record/base.rb +338 -0
  58. data/lib/active_record/callbacks.rb +452 -0
  59. data/lib/active_record/coders/column_serializer.rb +61 -0
  60. data/lib/active_record/coders/json.rb +15 -0
  61. data/lib/active_record/coders/yaml_column.rb +95 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +290 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +210 -0
  64. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  65. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +923 -0
  66. data/lib/active_record/connection_adapters/abstract/database_limits.rb +31 -0
  67. data/lib/active_record/connection_adapters/abstract/database_statements.rb +747 -0
  68. data/lib/active_record/connection_adapters/abstract/query_cache.rb +319 -0
  69. data/lib/active_record/connection_adapters/abstract/quoting.rb +239 -0
  70. data/lib/active_record/connection_adapters/abstract/savepoints.rb +24 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +190 -0
  72. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +961 -0
  73. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +106 -0
  74. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1883 -0
  75. data/lib/active_record/connection_adapters/abstract/transaction.rb +676 -0
  76. data/lib/active_record/connection_adapters/abstract_adapter.rb +1218 -0
  77. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +1016 -0
  78. data/lib/active_record/connection_adapters/column.rb +122 -0
  79. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  80. data/lib/active_record/connection_adapters/mysql/column.rb +28 -0
  81. data/lib/active_record/connection_adapters/mysql/database_statements.rb +95 -0
  82. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
  83. data/lib/active_record/connection_adapters/mysql/quoting.rb +114 -0
  84. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +106 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +106 -0
  86. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +97 -0
  87. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +300 -0
  88. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
  89. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +96 -0
  90. data/lib/active_record/connection_adapters/mysql2_adapter.rb +196 -0
  91. data/lib/active_record/connection_adapters/pool_config.rb +83 -0
  92. data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
  93. data/lib/active_record/connection_adapters/postgresql/column.rb +82 -0
  94. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +231 -0
  95. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +91 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +54 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +31 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +20 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +109 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  110. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +42 -0
  112. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  113. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +74 -0
  114. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +124 -0
  115. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  116. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  117. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  118. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +125 -0
  119. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +45 -0
  120. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  121. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  122. data/lib/active_record/connection_adapters/postgresql/oid.rb +38 -0
  123. data/lib/active_record/connection_adapters/postgresql/quoting.rb +238 -0
  124. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +71 -0
  125. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +169 -0
  126. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +392 -0
  127. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +127 -0
  128. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +1162 -0
  129. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
  130. data/lib/active_record/connection_adapters/postgresql/utils.rb +79 -0
  131. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1182 -0
  132. data/lib/active_record/connection_adapters/schema_cache.rb +478 -0
  133. data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
  134. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  135. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +145 -0
  136. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  137. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +116 -0
  138. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +37 -0
  139. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +39 -0
  140. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +47 -0
  141. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +221 -0
  142. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +843 -0
  143. data/lib/active_record/connection_adapters/statement_pool.rb +67 -0
  144. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +69 -0
  145. data/lib/active_record/connection_adapters/trilogy_adapter.rb +212 -0
  146. data/lib/active_record/connection_adapters.rb +176 -0
  147. data/lib/active_record/connection_handling.rb +413 -0
  148. data/lib/active_record/core.rb +836 -0
  149. data/lib/active_record/counter_cache.rb +230 -0
  150. data/lib/active_record/database_configurations/connection_url_resolver.rb +105 -0
  151. data/lib/active_record/database_configurations/database_config.rb +104 -0
  152. data/lib/active_record/database_configurations/hash_config.rb +172 -0
  153. data/lib/active_record/database_configurations/url_config.rb +78 -0
  154. data/lib/active_record/database_configurations.rb +309 -0
  155. data/lib/active_record/delegated_type.rb +289 -0
  156. data/lib/active_record/deprecator.rb +7 -0
  157. data/lib/active_record/destroy_association_async_job.rb +38 -0
  158. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  159. data/lib/active_record/dynamic_matchers.rb +121 -0
  160. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  161. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  162. data/lib/active_record/encryption/cipher.rb +53 -0
  163. data/lib/active_record/encryption/config.rb +70 -0
  164. data/lib/active_record/encryption/configurable.rb +60 -0
  165. data/lib/active_record/encryption/context.rb +42 -0
  166. data/lib/active_record/encryption/contexts.rb +76 -0
  167. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  168. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  169. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  170. data/lib/active_record/encryption/encrypted_attribute_type.rb +184 -0
  171. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  172. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  173. data/lib/active_record/encryption/encryptor.rb +177 -0
  174. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  175. data/lib/active_record/encryption/errors.rb +15 -0
  176. data/lib/active_record/encryption/extended_deterministic_queries.rb +159 -0
  177. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  178. data/lib/active_record/encryption/key.rb +28 -0
  179. data/lib/active_record/encryption/key_generator.rb +53 -0
  180. data/lib/active_record/encryption/key_provider.rb +46 -0
  181. data/lib/active_record/encryption/message.rb +33 -0
  182. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  183. data/lib/active_record/encryption/message_serializer.rb +96 -0
  184. data/lib/active_record/encryption/null_encryptor.rb +25 -0
  185. data/lib/active_record/encryption/properties.rb +76 -0
  186. data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
  187. data/lib/active_record/encryption/scheme.rb +107 -0
  188. data/lib/active_record/encryption.rb +58 -0
  189. data/lib/active_record/enum.rb +424 -0
  190. data/lib/active_record/errors.rb +614 -0
  191. data/lib/active_record/explain.rb +63 -0
  192. data/lib/active_record/explain_registry.rb +37 -0
  193. data/lib/active_record/explain_subscriber.rb +34 -0
  194. data/lib/active_record/fixture_set/file.rb +89 -0
  195. data/lib/active_record/fixture_set/model_metadata.rb +42 -0
  196. data/lib/active_record/fixture_set/render_context.rb +19 -0
  197. data/lib/active_record/fixture_set/table_row.rb +208 -0
  198. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  199. data/lib/active_record/fixtures.rb +850 -0
  200. data/lib/active_record/future_result.rb +182 -0
  201. data/lib/active_record/gem_version.rb +17 -0
  202. data/lib/active_record/inheritance.rb +366 -0
  203. data/lib/active_record/insert_all.rb +328 -0
  204. data/lib/active_record/integration.rb +209 -0
  205. data/lib/active_record/internal_metadata.rb +164 -0
  206. data/lib/active_record/legacy_yaml_adapter.rb +15 -0
  207. data/lib/active_record/locale/en.yml +48 -0
  208. data/lib/active_record/locking/optimistic.rb +228 -0
  209. data/lib/active_record/locking/pessimistic.rb +102 -0
  210. data/lib/active_record/log_subscriber.rb +149 -0
  211. data/lib/active_record/marshalling.rb +56 -0
  212. data/lib/active_record/message_pack.rb +124 -0
  213. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  214. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  215. data/lib/active_record/middleware/database_selector.rb +87 -0
  216. data/lib/active_record/middleware/shard_selector.rb +62 -0
  217. data/lib/active_record/migration/command_recorder.rb +406 -0
  218. data/lib/active_record/migration/compatibility.rb +490 -0
  219. data/lib/active_record/migration/default_strategy.rb +22 -0
  220. data/lib/active_record/migration/execution_strategy.rb +19 -0
  221. data/lib/active_record/migration/join_table.rb +16 -0
  222. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  223. data/lib/active_record/migration.rb +1626 -0
  224. data/lib/active_record/model_schema.rb +635 -0
  225. data/lib/active_record/nested_attributes.rb +633 -0
  226. data/lib/active_record/no_touching.rb +65 -0
  227. data/lib/active_record/normalization.rb +163 -0
  228. data/lib/active_record/persistence.rb +968 -0
  229. data/lib/active_record/promise.rb +84 -0
  230. data/lib/active_record/query_cache.rb +56 -0
  231. data/lib/active_record/query_logs.rb +247 -0
  232. data/lib/active_record/query_logs_formatter.rb +30 -0
  233. data/lib/active_record/querying.rb +122 -0
  234. data/lib/active_record/railtie.rb +440 -0
  235. data/lib/active_record/railties/console_sandbox.rb +5 -0
  236. data/lib/active_record/railties/controller_runtime.rb +65 -0
  237. data/lib/active_record/railties/databases.rake +641 -0
  238. data/lib/active_record/railties/job_runtime.rb +23 -0
  239. data/lib/active_record/readonly_attributes.rb +66 -0
  240. data/lib/active_record/reflection.rb +1287 -0
  241. data/lib/active_record/relation/batches/batch_enumerator.rb +115 -0
  242. data/lib/active_record/relation/batches.rb +491 -0
  243. data/lib/active_record/relation/calculations.rb +679 -0
  244. data/lib/active_record/relation/delegation.rb +154 -0
  245. data/lib/active_record/relation/finder_methods.rb +661 -0
  246. data/lib/active_record/relation/from_clause.rb +30 -0
  247. data/lib/active_record/relation/merger.rb +192 -0
  248. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  249. data/lib/active_record/relation/predicate_builder/association_query_value.rb +76 -0
  250. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  251. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +60 -0
  252. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  253. data/lib/active_record/relation/predicate_builder/relation_handler.rb +24 -0
  254. data/lib/active_record/relation/predicate_builder.rb +181 -0
  255. data/lib/active_record/relation/query_attribute.rb +68 -0
  256. data/lib/active_record/relation/query_methods.rb +2235 -0
  257. data/lib/active_record/relation/record_fetch_warning.rb +52 -0
  258. data/lib/active_record/relation/spawn_methods.rb +78 -0
  259. data/lib/active_record/relation/where_clause.rb +218 -0
  260. data/lib/active_record/relation.rb +1495 -0
  261. data/lib/active_record/result.rb +249 -0
  262. data/lib/active_record/runtime_registry.rb +82 -0
  263. data/lib/active_record/sanitization.rb +254 -0
  264. data/lib/active_record/schema.rb +77 -0
  265. data/lib/active_record/schema_dumper.rb +364 -0
  266. data/lib/active_record/schema_migration.rb +106 -0
  267. data/lib/active_record/scoping/default.rb +205 -0
  268. data/lib/active_record/scoping/named.rb +202 -0
  269. data/lib/active_record/scoping.rb +136 -0
  270. data/lib/active_record/secure_password.rb +60 -0
  271. data/lib/active_record/secure_token.rb +66 -0
  272. data/lib/active_record/serialization.rb +29 -0
  273. data/lib/active_record/signed_id.rb +137 -0
  274. data/lib/active_record/statement_cache.rb +164 -0
  275. data/lib/active_record/store.rb +299 -0
  276. data/lib/active_record/suppressor.rb +59 -0
  277. data/lib/active_record/table_metadata.rb +85 -0
  278. data/lib/active_record/tasks/database_tasks.rb +681 -0
  279. data/lib/active_record/tasks/mysql_database_tasks.rb +120 -0
  280. data/lib/active_record/tasks/postgresql_database_tasks.rb +147 -0
  281. data/lib/active_record/tasks/sqlite_database_tasks.rb +89 -0
  282. data/lib/active_record/test_databases.rb +24 -0
  283. data/lib/active_record/test_fixtures.rb +321 -0
  284. data/lib/active_record/testing/query_assertions.rb +121 -0
  285. data/lib/active_record/timestamp.rb +177 -0
  286. data/lib/active_record/token_for.rb +123 -0
  287. data/lib/active_record/touch_later.rb +70 -0
  288. data/lib/active_record/transaction.rb +132 -0
  289. data/lib/active_record/transactions.rb +523 -0
  290. data/lib/active_record/translation.rb +22 -0
  291. data/lib/active_record/type/adapter_specific_registry.rb +144 -0
  292. data/lib/active_record/type/date.rb +9 -0
  293. data/lib/active_record/type/date_time.rb +9 -0
  294. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  295. data/lib/active_record/type/hash_lookup_type_map.rb +57 -0
  296. data/lib/active_record/type/internal/timezone.rb +22 -0
  297. data/lib/active_record/type/json.rb +30 -0
  298. data/lib/active_record/type/serialized.rb +76 -0
  299. data/lib/active_record/type/text.rb +11 -0
  300. data/lib/active_record/type/time.rb +35 -0
  301. data/lib/active_record/type/type_map.rb +58 -0
  302. data/lib/active_record/type/unsigned_integer.rb +16 -0
  303. data/lib/active_record/type.rb +83 -0
  304. data/lib/active_record/type_caster/connection.rb +33 -0
  305. data/lib/active_record/type_caster/map.rb +23 -0
  306. data/lib/active_record/type_caster.rb +9 -0
  307. data/lib/active_record/validations/absence.rb +25 -0
  308. data/lib/active_record/validations/associated.rb +65 -0
  309. data/lib/active_record/validations/length.rb +26 -0
  310. data/lib/active_record/validations/numericality.rb +36 -0
  311. data/lib/active_record/validations/presence.rb +45 -0
  312. data/lib/active_record/validations/uniqueness.rb +295 -0
  313. data/lib/active_record/validations.rb +101 -0
  314. data/lib/active_record/version.rb +10 -0
  315. data/lib/active_record.rb +616 -0
  316. data/lib/arel/alias_predication.rb +9 -0
  317. data/lib/arel/attributes/attribute.rb +33 -0
  318. data/lib/arel/collectors/bind.rb +31 -0
  319. data/lib/arel/collectors/composite.rb +46 -0
  320. data/lib/arel/collectors/plain_string.rb +20 -0
  321. data/lib/arel/collectors/sql_string.rb +27 -0
  322. data/lib/arel/collectors/substitute_binds.rb +35 -0
  323. data/lib/arel/crud.rb +48 -0
  324. data/lib/arel/delete_manager.rb +32 -0
  325. data/lib/arel/errors.rb +19 -0
  326. data/lib/arel/expressions.rb +29 -0
  327. data/lib/arel/factory_methods.rb +53 -0
  328. data/lib/arel/filter_predications.rb +9 -0
  329. data/lib/arel/insert_manager.rb +48 -0
  330. data/lib/arel/math.rb +45 -0
  331. data/lib/arel/nodes/ascending.rb +23 -0
  332. data/lib/arel/nodes/binary.rb +125 -0
  333. data/lib/arel/nodes/bind_param.rb +44 -0
  334. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  335. data/lib/arel/nodes/case.rb +55 -0
  336. data/lib/arel/nodes/casted.rb +62 -0
  337. data/lib/arel/nodes/comment.rb +29 -0
  338. data/lib/arel/nodes/count.rb +12 -0
  339. data/lib/arel/nodes/cte.rb +36 -0
  340. data/lib/arel/nodes/delete_statement.rb +44 -0
  341. data/lib/arel/nodes/descending.rb +23 -0
  342. data/lib/arel/nodes/equality.rb +15 -0
  343. data/lib/arel/nodes/extract.rb +24 -0
  344. data/lib/arel/nodes/false.rb +16 -0
  345. data/lib/arel/nodes/filter.rb +10 -0
  346. data/lib/arel/nodes/fragments.rb +35 -0
  347. data/lib/arel/nodes/full_outer_join.rb +8 -0
  348. data/lib/arel/nodes/function.rb +45 -0
  349. data/lib/arel/nodes/grouping.rb +11 -0
  350. data/lib/arel/nodes/homogeneous_in.rb +68 -0
  351. data/lib/arel/nodes/in.rb +15 -0
  352. data/lib/arel/nodes/infix_operation.rb +92 -0
  353. data/lib/arel/nodes/inner_join.rb +8 -0
  354. data/lib/arel/nodes/insert_statement.rb +37 -0
  355. data/lib/arel/nodes/join_source.rb +20 -0
  356. data/lib/arel/nodes/leading_join.rb +8 -0
  357. data/lib/arel/nodes/matches.rb +18 -0
  358. data/lib/arel/nodes/named_function.rb +23 -0
  359. data/lib/arel/nodes/nary.rb +39 -0
  360. data/lib/arel/nodes/node.rb +161 -0
  361. data/lib/arel/nodes/node_expression.rb +13 -0
  362. data/lib/arel/nodes/ordering.rb +27 -0
  363. data/lib/arel/nodes/outer_join.rb +8 -0
  364. data/lib/arel/nodes/over.rb +15 -0
  365. data/lib/arel/nodes/regexp.rb +16 -0
  366. data/lib/arel/nodes/right_outer_join.rb +8 -0
  367. data/lib/arel/nodes/select_core.rb +67 -0
  368. data/lib/arel/nodes/select_statement.rb +41 -0
  369. data/lib/arel/nodes/sql_literal.rb +32 -0
  370. data/lib/arel/nodes/string_join.rb +11 -0
  371. data/lib/arel/nodes/table_alias.rb +35 -0
  372. data/lib/arel/nodes/terminal.rb +16 -0
  373. data/lib/arel/nodes/true.rb +16 -0
  374. data/lib/arel/nodes/unary.rb +44 -0
  375. data/lib/arel/nodes/unary_operation.rb +20 -0
  376. data/lib/arel/nodes/unqualified_column.rb +22 -0
  377. data/lib/arel/nodes/update_statement.rb +46 -0
  378. data/lib/arel/nodes/values_list.rb +9 -0
  379. data/lib/arel/nodes/window.rb +126 -0
  380. data/lib/arel/nodes/with.rb +11 -0
  381. data/lib/arel/nodes.rb +75 -0
  382. data/lib/arel/order_predications.rb +13 -0
  383. data/lib/arel/predications.rb +260 -0
  384. data/lib/arel/select_manager.rb +276 -0
  385. data/lib/arel/table.rb +121 -0
  386. data/lib/arel/tree_manager.rb +65 -0
  387. data/lib/arel/update_manager.rb +49 -0
  388. data/lib/arel/visitors/dot.rb +299 -0
  389. data/lib/arel/visitors/mysql.rb +111 -0
  390. data/lib/arel/visitors/postgresql.rb +99 -0
  391. data/lib/arel/visitors/sqlite.rb +38 -0
  392. data/lib/arel/visitors/to_sql.rb +1033 -0
  393. data/lib/arel/visitors/visitor.rb +45 -0
  394. data/lib/arel/visitors.rb +13 -0
  395. data/lib/arel/window_predications.rb +9 -0
  396. data/lib/arel.rb +73 -0
  397. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  398. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  399. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  400. data/lib/rails/generators/active_record/migration/migration_generator.rb +76 -0
  401. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +29 -0
  402. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
  403. data/lib/rails/generators/active_record/migration.rb +54 -0
  404. data/lib/rails/generators/active_record/model/USAGE +113 -0
  405. data/lib/rails/generators/active_record/model/model_generator.rb +94 -0
  406. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  407. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  408. data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
  409. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  410. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  411. data/lib/rails/generators/active_record.rb +19 -0
  412. metadata +505 -0
@@ -0,0 +1,523 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ # See ActiveRecord::Transactions::ClassMethods for documentation.
5
+ module Transactions
6
+ extend ActiveSupport::Concern
7
+ # :nodoc:
8
+ ACTIONS = [:create, :destroy, :update]
9
+
10
+ included do
11
+ define_callbacks :commit, :rollback,
12
+ :before_commit,
13
+ scope: [:kind, :name]
14
+ end
15
+
16
+ attr_accessor :_new_record_before_last_commit # :nodoc:
17
+
18
+ # = Active Record \Transactions
19
+ #
20
+ # \Transactions are protective blocks where SQL statements are only permanent
21
+ # if they can all succeed as one atomic action. The classic example is a
22
+ # transfer between two accounts where you can only have a deposit if the
23
+ # withdrawal succeeded and vice versa. \Transactions enforce the integrity of
24
+ # the database and guard the data against program errors or database
25
+ # break-downs. So basically you should use transaction blocks whenever you
26
+ # have a number of statements that must be executed together or not at all.
27
+ #
28
+ # For example:
29
+ #
30
+ # ActiveRecord::Base.transaction do
31
+ # david.withdrawal(100)
32
+ # mary.deposit(100)
33
+ # end
34
+ #
35
+ # This example will only take money from David and give it to Mary if neither
36
+ # +withdrawal+ nor +deposit+ raise an exception. Exceptions will force a
37
+ # ROLLBACK that returns the database to the state before the transaction
38
+ # began. Be aware, though, that the objects will _not_ have their instance
39
+ # data returned to their pre-transactional state.
40
+ #
41
+ # == Different Active Record classes in a single transaction
42
+ #
43
+ # Though the #transaction class method is called on some Active Record class,
44
+ # the objects within the transaction block need not all be instances of
45
+ # that class. This is because transactions are per-database connection, not
46
+ # per-model.
47
+ #
48
+ # In this example a +balance+ record is transactionally saved even
49
+ # though #transaction is called on the +Account+ class:
50
+ #
51
+ # Account.transaction do
52
+ # balance.save!
53
+ # account.save!
54
+ # end
55
+ #
56
+ # The #transaction method is also available as a model instance method.
57
+ # For example, you can also do this:
58
+ #
59
+ # balance.transaction do
60
+ # balance.save!
61
+ # account.save!
62
+ # end
63
+ #
64
+ # == Transactions are not distributed across database connections
65
+ #
66
+ # A transaction acts on a single database connection. If you have
67
+ # multiple class-specific databases, the transaction will not protect
68
+ # interaction among them. One workaround is to begin a transaction
69
+ # on each class whose models you alter:
70
+ #
71
+ # Student.transaction do
72
+ # Course.transaction do
73
+ # course.enroll(student)
74
+ # student.units += course.units
75
+ # end
76
+ # end
77
+ #
78
+ # This is a poor solution, but fully distributed transactions are beyond
79
+ # the scope of Active Record.
80
+ #
81
+ # == +save+ and +destroy+ are automatically wrapped in a transaction
82
+ #
83
+ # Both {#save}[rdoc-ref:Persistence#save] and
84
+ # {#destroy}[rdoc-ref:Persistence#destroy] come wrapped in a transaction that ensures
85
+ # that whatever you do in validations or callbacks will happen under its
86
+ # protected cover. So you can use validations to check for values that
87
+ # the transaction depends on or you can raise exceptions in the callbacks
88
+ # to rollback, including <tt>after_*</tt> callbacks.
89
+ #
90
+ # As a consequence changes to the database are not seen outside your connection
91
+ # until the operation is complete. For example, if you try to update the index
92
+ # of a search engine in +after_save+ the indexer won't see the updated record.
93
+ # The #after_commit callback is the only one that is triggered once the update
94
+ # is committed. See below.
95
+ #
96
+ # == Exception handling and rolling back
97
+ #
98
+ # Also have in mind that exceptions thrown within a transaction block will
99
+ # be propagated (after triggering the ROLLBACK), so you should be ready to
100
+ # catch those in your application code.
101
+ #
102
+ # One exception is the ActiveRecord::Rollback exception, which will trigger
103
+ # a ROLLBACK when raised, but not be re-raised by the transaction block. Any
104
+ # other exception will be re-raised.
105
+ #
106
+ # *Warning*: one should not catch ActiveRecord::StatementInvalid exceptions
107
+ # inside a transaction block. ActiveRecord::StatementInvalid exceptions indicate that an
108
+ # error occurred at the database level, for example when a unique constraint
109
+ # is violated. On some database systems, such as PostgreSQL, database errors
110
+ # inside a transaction cause the entire transaction to become unusable
111
+ # until it's restarted from the beginning. Here is an example which
112
+ # demonstrates the problem:
113
+ #
114
+ # # Suppose that we have a Number model with a unique column called 'i'.
115
+ # Number.transaction do
116
+ # Number.create(i: 0)
117
+ # begin
118
+ # # This will raise a unique constraint error...
119
+ # Number.create(i: 0)
120
+ # rescue ActiveRecord::StatementInvalid
121
+ # # ...which we ignore.
122
+ # end
123
+ #
124
+ # # On PostgreSQL, the transaction is now unusable. The following
125
+ # # statement will cause a PostgreSQL error, even though the unique
126
+ # # constraint is no longer violated:
127
+ # Number.create(i: 1)
128
+ # # => "PG::Error: ERROR: current transaction is aborted, commands
129
+ # # ignored until end of transaction block"
130
+ # end
131
+ #
132
+ # One should restart the entire transaction if an
133
+ # ActiveRecord::StatementInvalid occurred.
134
+ #
135
+ # == Nested transactions
136
+ #
137
+ # #transaction calls can be nested. By default, this makes all database
138
+ # statements in the nested transaction block become part of the parent
139
+ # transaction. For example, the following behavior may be surprising:
140
+ #
141
+ # User.transaction do
142
+ # User.create(username: 'Kotori')
143
+ # User.transaction do
144
+ # User.create(username: 'Nemu')
145
+ # raise ActiveRecord::Rollback
146
+ # end
147
+ # end
148
+ #
149
+ # creates both "Kotori" and "Nemu". Reason is the ActiveRecord::Rollback
150
+ # exception in the nested block does not issue a ROLLBACK. Since these exceptions
151
+ # are captured in transaction blocks, the parent block does not see it and the
152
+ # real transaction is committed.
153
+ #
154
+ # In order to get a ROLLBACK for the nested transaction you may ask for a real
155
+ # sub-transaction by passing <tt>requires_new: true</tt>. If anything goes wrong,
156
+ # the database rolls back to the beginning of the sub-transaction without rolling
157
+ # back the parent transaction. If we add it to the previous example:
158
+ #
159
+ # User.transaction do
160
+ # User.create(username: 'Kotori')
161
+ # User.transaction(requires_new: true) do
162
+ # User.create(username: 'Nemu')
163
+ # raise ActiveRecord::Rollback
164
+ # end
165
+ # end
166
+ #
167
+ # only "Kotori" is created.
168
+ #
169
+ # Most databases don't support true nested transactions. At the time of
170
+ # writing, the only database that we're aware of that supports true nested
171
+ # transactions, is MS-SQL. Because of this, Active Record emulates nested
172
+ # transactions by using savepoints. See
173
+ # https://dev.mysql.com/doc/refman/en/savepoint.html
174
+ # for more information about savepoints.
175
+ #
176
+ # === \Callbacks
177
+ #
178
+ # There are two types of callbacks associated with committing and rolling back transactions:
179
+ # #after_commit and #after_rollback.
180
+ #
181
+ # #after_commit callbacks are called on every record saved or destroyed within a
182
+ # transaction immediately after the transaction is committed. #after_rollback callbacks
183
+ # are called on every record saved or destroyed within a transaction immediately after the
184
+ # transaction or savepoint is rolled back.
185
+ #
186
+ # These callbacks are useful for interacting with other systems since you will be guaranteed
187
+ # that the callback is only executed when the database is in a permanent state. For example,
188
+ # #after_commit is a good spot to put in a hook to clearing a cache since clearing it from
189
+ # within a transaction could trigger the cache to be regenerated before the database is updated.
190
+ #
191
+ # ==== NOTE: Callbacks are deduplicated per callback by filter.
192
+ #
193
+ # Trying to define multiple callbacks with the same filter will result in a single callback being run.
194
+ #
195
+ # For example:
196
+ #
197
+ # after_commit :do_something
198
+ # after_commit :do_something # only the last one will be called
199
+ #
200
+ # This applies to all variations of <tt>after_*_commit</tt> callbacks as well.
201
+ #
202
+ # after_commit :do_something
203
+ # after_create_commit :do_something
204
+ # after_save_commit :do_something
205
+ #
206
+ # It is recommended to use the +on:+ option to specify when the callback should be run.
207
+ #
208
+ # after_commit :do_something, on: [:create, :update]
209
+ #
210
+ # This is equivalent to using +after_create_commit+ and +after_update_commit+, but will not be deduplicated.
211
+ #
212
+ # === Caveats
213
+ #
214
+ # If you're on MySQL, then do not use Data Definition Language (DDL) operations in nested
215
+ # transactions blocks that are emulated with savepoints. That is, do not execute statements
216
+ # like 'CREATE TABLE' inside such blocks. This is because MySQL automatically
217
+ # releases all savepoints upon executing a DDL operation. When +transaction+
218
+ # is finished and tries to release the savepoint it created earlier, a
219
+ # database error will occur because the savepoint has already been
220
+ # automatically released. The following example demonstrates the problem:
221
+ #
222
+ # Model.lease_connection.transaction do # BEGIN
223
+ # Model.lease_connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
224
+ # Model.lease_connection.create_table(...) # active_record_1 now automatically released
225
+ # end # RELEASE SAVEPOINT active_record_1
226
+ # # ^^^^ BOOM! database error!
227
+ # end
228
+ #
229
+ # Note that "TRUNCATE" is also a MySQL DDL statement!
230
+ module ClassMethods
231
+ # See the ConnectionAdapters::DatabaseStatements#transaction API docs.
232
+ def transaction(**options, &block)
233
+ with_connection do |connection|
234
+ connection.transaction(**options, &block)
235
+ end
236
+ end
237
+
238
+ # Returns a representation of the current transaction state,
239
+ # which can be a top level transaction, a savepoint, or the absence of a transaction.
240
+ #
241
+ # An object is always returned, whether or not a transaction is currently active.
242
+ # To check if a transaction was opened, use <tt>current_transaction.open?</tt>.
243
+ #
244
+ # See the ActiveRecord::Transaction documentation for detailed behavior.
245
+ def current_transaction
246
+ connection_pool.active_connection&.current_transaction&.user_transaction || Transaction::NULL_TRANSACTION
247
+ end
248
+
249
+ def before_commit(*args, &block) # :nodoc:
250
+ set_options_for_callbacks!(args)
251
+ set_callback(:before_commit, :before, *args, &block)
252
+ end
253
+
254
+ # This callback is called after a record has been created, updated, or destroyed.
255
+ #
256
+ # You can specify that the callback should only be fired by a certain action with
257
+ # the +:on+ option:
258
+ #
259
+ # after_commit :do_foo, on: :create
260
+ # after_commit :do_bar, on: :update
261
+ # after_commit :do_baz, on: :destroy
262
+ #
263
+ # after_commit :do_foo_bar, on: [:create, :update]
264
+ # after_commit :do_bar_baz, on: [:update, :destroy]
265
+ #
266
+ def after_commit(*args, &block)
267
+ set_options_for_callbacks!(args, prepend_option)
268
+ set_callback(:commit, :after, *args, &block)
269
+ end
270
+
271
+ # Shortcut for <tt>after_commit :hook, on: [ :create, :update ]</tt>.
272
+ def after_save_commit(*args, &block)
273
+ set_options_for_callbacks!(args, on: [ :create, :update ], **prepend_option)
274
+ set_callback(:commit, :after, *args, &block)
275
+ end
276
+
277
+ # Shortcut for <tt>after_commit :hook, on: :create</tt>.
278
+ def after_create_commit(*args, &block)
279
+ set_options_for_callbacks!(args, on: :create, **prepend_option)
280
+ set_callback(:commit, :after, *args, &block)
281
+ end
282
+
283
+ # Shortcut for <tt>after_commit :hook, on: :update</tt>.
284
+ def after_update_commit(*args, &block)
285
+ set_options_for_callbacks!(args, on: :update, **prepend_option)
286
+ set_callback(:commit, :after, *args, &block)
287
+ end
288
+
289
+ # Shortcut for <tt>after_commit :hook, on: :destroy</tt>.
290
+ def after_destroy_commit(*args, &block)
291
+ set_options_for_callbacks!(args, on: :destroy, **prepend_option)
292
+ set_callback(:commit, :after, *args, &block)
293
+ end
294
+
295
+ # This callback is called after a create, update, or destroy are rolled back.
296
+ #
297
+ # Please check the documentation of #after_commit for options.
298
+ def after_rollback(*args, &block)
299
+ set_options_for_callbacks!(args, prepend_option)
300
+ set_callback(:rollback, :after, *args, &block)
301
+ end
302
+
303
+ # Similar to ActiveSupport::Callbacks::ClassMethods#set_callback, but with
304
+ # support for options available on #after_commit and #after_rollback callbacks.
305
+ def set_callback(name, *filter_list, &block)
306
+ options = filter_list.extract_options!
307
+ filter_list << options
308
+
309
+ if name.in?([:commit, :rollback]) && options[:on]
310
+ fire_on = Array(options[:on])
311
+ assert_valid_transaction_action(fire_on)
312
+ options[:if] = [
313
+ -> { transaction_include_any_action?(fire_on) },
314
+ *options[:if]
315
+ ]
316
+ end
317
+
318
+
319
+ super(name, *filter_list, &block)
320
+ end
321
+
322
+ private
323
+ def prepend_option
324
+ if ActiveRecord.run_after_transaction_callbacks_in_order_defined
325
+ { prepend: true }
326
+ else
327
+ {}
328
+ end
329
+ end
330
+
331
+ def set_options_for_callbacks!(args, enforced_options = {})
332
+ options = args.extract_options!.merge!(enforced_options)
333
+ args << options
334
+
335
+ if options[:on]
336
+ fire_on = Array(options[:on])
337
+ assert_valid_transaction_action(fire_on)
338
+ options[:if] = [
339
+ -> { transaction_include_any_action?(fire_on) },
340
+ *options[:if]
341
+ ]
342
+ end
343
+ end
344
+
345
+ def assert_valid_transaction_action(actions)
346
+ if (actions - ACTIONS).any?
347
+ raise ArgumentError, ":on conditions for after_commit and after_rollback callbacks have to be one of #{ACTIONS}"
348
+ end
349
+ end
350
+ end
351
+
352
+ # See ActiveRecord::Transactions::ClassMethods for detailed documentation.
353
+ def transaction(**options, &block)
354
+ self.class.transaction(**options, &block)
355
+ end
356
+
357
+ def destroy # :nodoc:
358
+ with_transaction_returning_status { super }
359
+ end
360
+
361
+ def save(**) # :nodoc:
362
+ with_transaction_returning_status { super }
363
+ end
364
+
365
+ def save!(**) # :nodoc:
366
+ with_transaction_returning_status { super }
367
+ end
368
+
369
+ def touch(*, **) # :nodoc:
370
+ with_transaction_returning_status { super }
371
+ end
372
+
373
+ def before_committed! # :nodoc:
374
+ _run_before_commit_callbacks
375
+ end
376
+
377
+ # Call the #after_commit callbacks.
378
+ #
379
+ # Ensure that it is not called if the object was never persisted (failed create),
380
+ # but call it after the commit of a destroyed object.
381
+ def committed!(should_run_callbacks: true) # :nodoc:
382
+ @_start_transaction_state = nil
383
+ if should_run_callbacks
384
+ @_committed_already_called = true
385
+ _run_commit_callbacks
386
+ end
387
+ ensure
388
+ @_committed_already_called = @_trigger_update_callback = @_trigger_destroy_callback = false
389
+ end
390
+
391
+ # Call the #after_rollback callbacks. The +force_restore_state+ argument indicates if the record
392
+ # state should be rolled back to the beginning or just to the last savepoint.
393
+ def rolledback!(force_restore_state: false, should_run_callbacks: true) # :nodoc:
394
+ if should_run_callbacks
395
+ _run_rollback_callbacks
396
+ end
397
+ ensure
398
+ restore_transaction_record_state(force_restore_state)
399
+ clear_transaction_record_state
400
+ @_trigger_update_callback = @_trigger_destroy_callback = false if force_restore_state
401
+ end
402
+
403
+ # Executes a block within a transaction and captures its return value as a
404
+ # status flag. If the status is true, the transaction is committed,
405
+ # otherwise a ROLLBACK is issued. In any case, the status flag is returned.
406
+ #
407
+ # This method is available within the context of an ActiveRecord::Base
408
+ # instance.
409
+ def with_transaction_returning_status
410
+ self.class.with_connection do |connection|
411
+ status = nil
412
+ ensure_finalize = !connection.transaction_open?
413
+
414
+ connection.transaction do
415
+ add_to_transaction(ensure_finalize || has_transactional_callbacks?)
416
+ remember_transaction_record_state
417
+
418
+ status = yield
419
+ raise ActiveRecord::Rollback unless status
420
+ end
421
+ status
422
+ end
423
+ end
424
+
425
+ def trigger_transactional_callbacks? # :nodoc:
426
+ (@_new_record_before_last_commit || _trigger_update_callback) && persisted? ||
427
+ _trigger_destroy_callback && destroyed?
428
+ end
429
+
430
+ private
431
+ attr_reader :_committed_already_called, :_trigger_update_callback, :_trigger_destroy_callback
432
+
433
+ def init_internals
434
+ super
435
+ @_start_transaction_state = nil
436
+ @_committed_already_called = nil
437
+ @_new_record_before_last_commit = nil
438
+ end
439
+
440
+ # Save the new record state and id of a record so it can be restored later if a transaction fails.
441
+ def remember_transaction_record_state
442
+ @_start_transaction_state ||= {
443
+ id: id,
444
+ new_record: @new_record,
445
+ previously_new_record: @previously_new_record,
446
+ destroyed: @destroyed,
447
+ attributes: @attributes,
448
+ frozen?: frozen?,
449
+ level: 0
450
+ }
451
+ @_start_transaction_state[:level] += 1
452
+
453
+ if _committed_already_called
454
+ @_new_record_before_last_commit = false
455
+ else
456
+ @_new_record_before_last_commit = @_start_transaction_state[:new_record]
457
+ end
458
+ end
459
+
460
+ # Clear the new record state and id of a record.
461
+ def clear_transaction_record_state
462
+ return unless @_start_transaction_state
463
+ @_start_transaction_state[:level] -= 1
464
+ @_start_transaction_state = nil if @_start_transaction_state[:level] < 1
465
+ end
466
+
467
+ # Restore the new record state and id of a record that was previously saved by a call to save_record_state.
468
+ def restore_transaction_record_state(force_restore_state = false)
469
+ if restore_state = @_start_transaction_state
470
+ if force_restore_state || restore_state[:level] <= 1
471
+ @new_record = restore_state[:new_record]
472
+ @previously_new_record = restore_state[:previously_new_record]
473
+ @destroyed = restore_state[:destroyed]
474
+ @attributes = restore_state[:attributes].map do |attr|
475
+ value = @attributes.fetch_value(attr.name)
476
+ attr = attr.with_value_from_user(value) if attr.value != value
477
+ attr
478
+ end
479
+ @mutations_from_database = nil
480
+ @mutations_before_last_save = nil
481
+ if self.class.composite_primary_key?
482
+ if restore_state[:id] != @primary_key.map { |col| @attributes.fetch_value(col) }
483
+ @primary_key.zip(restore_state[:id]).each do |col, val|
484
+ @attributes.write_from_user(col, val)
485
+ end
486
+ end
487
+ else
488
+ if @attributes.fetch_value(@primary_key) != restore_state[:id]
489
+ @attributes.write_from_user(@primary_key, restore_state[:id])
490
+ end
491
+ end
492
+ freeze if restore_state[:frozen?]
493
+ end
494
+ end
495
+ end
496
+
497
+ # Determine if a transaction included an action for :create, :update, or :destroy. Used in filtering callbacks.
498
+ def transaction_include_any_action?(actions)
499
+ actions.any? do |action|
500
+ case action
501
+ when :create
502
+ persisted? && @_new_record_before_last_commit
503
+ when :update
504
+ !(@_new_record_before_last_commit || destroyed?) && _trigger_update_callback
505
+ when :destroy
506
+ _trigger_destroy_callback
507
+ end
508
+ end
509
+ end
510
+
511
+ # Add the record to the current transaction so that the #after_rollback and #after_commit
512
+ # callbacks can be called.
513
+ def add_to_transaction(ensure_finalize = true)
514
+ self.class.with_connection do |connection|
515
+ connection.add_transaction_record(self, ensure_finalize)
516
+ end
517
+ end
518
+
519
+ def has_transactional_callbacks?
520
+ !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_before_commit_callbacks.empty?
521
+ end
522
+ end
523
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Translation
5
+ # Set the lookup ancestors for ActiveModel.
6
+ def lookup_ancestors # :nodoc:
7
+ klass = self
8
+ classes = [klass]
9
+ return classes if klass == ActiveRecord::Base
10
+
11
+ while !klass.base_class?
12
+ classes << klass = klass.superclass
13
+ end
14
+ classes
15
+ end
16
+
17
+ # Set the i18n scope to override ActiveModel.
18
+ def i18n_scope # :nodoc:
19
+ :activerecord
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ # :stopdoc:
5
+ module Type
6
+ class AdapterSpecificRegistry # :nodoc:
7
+ def initialize
8
+ @registrations = []
9
+ end
10
+
11
+ def initialize_copy(other)
12
+ @registrations = @registrations.dup
13
+ end
14
+
15
+ def add_modifier(options, klass, **args)
16
+ registrations << DecorationRegistration.new(options, klass, **args)
17
+ end
18
+
19
+ def register(type_name, klass = nil, **options, &block)
20
+ unless block_given?
21
+ block = proc { |_, *args| klass.new(*args) }
22
+ block.ruby2_keywords if block.respond_to?(:ruby2_keywords)
23
+ end
24
+ registrations << Registration.new(type_name, block, **options)
25
+ end
26
+
27
+ def lookup(symbol, *args, **kwargs)
28
+ registration = find_registration(symbol, *args, **kwargs)
29
+
30
+ if registration
31
+ registration.call(self, symbol, *args, **kwargs)
32
+ else
33
+ raise ArgumentError, "Unknown type #{symbol.inspect}"
34
+ end
35
+ end
36
+
37
+ private
38
+ attr_reader :registrations
39
+
40
+ def find_registration(symbol, *args, **kwargs)
41
+ registrations
42
+ .select { |registration| registration.matches?(symbol, *args, **kwargs) }
43
+ .max
44
+ end
45
+ end
46
+
47
+ class Registration # :nodoc:
48
+ def initialize(name, block, adapter: nil, override: nil)
49
+ @name = name
50
+ @block = block
51
+ @adapter = adapter
52
+ @override = override
53
+ end
54
+
55
+ def call(_registry, *args, adapter: nil, **kwargs)
56
+ block.call(*args, **kwargs)
57
+ end
58
+
59
+ def matches?(type_name, *args, **kwargs)
60
+ type_name == name && matches_adapter?(**kwargs)
61
+ end
62
+
63
+ def <=>(other)
64
+ if conflicts_with?(other)
65
+ raise TypeConflictError.new("Type #{name} was registered for all
66
+ adapters, but shadows a native type with
67
+ the same name for #{other.adapter}".squish)
68
+ end
69
+ priority <=> other.priority
70
+ end
71
+
72
+ protected
73
+ attr_reader :name, :block, :adapter, :override
74
+
75
+ def priority
76
+ result = 0
77
+ if adapter
78
+ result |= 1
79
+ end
80
+ if override
81
+ result |= 2
82
+ end
83
+ result
84
+ end
85
+
86
+ def priority_except_adapter
87
+ priority & 0b111111100
88
+ end
89
+
90
+ private
91
+ def matches_adapter?(adapter: nil, **)
92
+ (self.adapter.nil? || adapter == self.adapter)
93
+ end
94
+
95
+ def conflicts_with?(other)
96
+ same_priority_except_adapter?(other) &&
97
+ has_adapter_conflict?(other)
98
+ end
99
+
100
+ def same_priority_except_adapter?(other)
101
+ priority_except_adapter == other.priority_except_adapter
102
+ end
103
+
104
+ def has_adapter_conflict?(other)
105
+ (override.nil? && other.adapter) ||
106
+ (adapter && other.override.nil?)
107
+ end
108
+ end
109
+
110
+ class DecorationRegistration < Registration # :nodoc:
111
+ def initialize(options, klass, adapter: nil)
112
+ @options = options
113
+ @klass = klass
114
+ @adapter = adapter
115
+ end
116
+
117
+ def call(registry, *args, **kwargs)
118
+ subtype = registry.lookup(*args, **kwargs.except(*options.keys))
119
+ klass.new(subtype)
120
+ end
121
+
122
+ def matches?(*args, **kwargs)
123
+ matches_adapter?(**kwargs) && matches_options?(**kwargs)
124
+ end
125
+
126
+ def priority
127
+ super | 4
128
+ end
129
+
130
+ private
131
+ attr_reader :options, :klass
132
+
133
+ def matches_options?(**kwargs)
134
+ options.all? do |key, value|
135
+ kwargs[key] == value
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ class TypeConflictError < StandardError # :nodoc:
142
+ end
143
+ # :startdoc:
144
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Type
5
+ class Date < ActiveModel::Type::Date
6
+ include Internal::Timezone
7
+ end
8
+ end
9
+ end