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,747 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters # :nodoc:
5
+ module DatabaseStatements
6
+ def initialize
7
+ super
8
+ reset_transaction
9
+ end
10
+
11
+ # Converts an arel AST to SQL
12
+ def to_sql(arel_or_sql_string, binds = [])
13
+ sql, _ = to_sql_and_binds(arel_or_sql_string, binds)
14
+ sql
15
+ end
16
+
17
+ def to_sql_and_binds(arel_or_sql_string, binds = [], preparable = nil, allow_retry = false) # :nodoc:
18
+ # Arel::TreeManager -> Arel::Node
19
+ if arel_or_sql_string.respond_to?(:ast)
20
+ arel_or_sql_string = arel_or_sql_string.ast
21
+ end
22
+
23
+ if Arel.arel_node?(arel_or_sql_string) && !(String === arel_or_sql_string)
24
+ unless binds.empty?
25
+ raise "Passing bind parameters with an arel AST is forbidden. " \
26
+ "The values must be stored on the AST directly"
27
+ end
28
+
29
+ collector = collector()
30
+ collector.retryable = true
31
+
32
+ if prepared_statements
33
+ collector.preparable = true
34
+ sql, binds = visitor.compile(arel_or_sql_string, collector)
35
+
36
+ if binds.length > bind_params_length
37
+ unprepared_statement do
38
+ return to_sql_and_binds(arel_or_sql_string)
39
+ end
40
+ end
41
+ preparable = collector.preparable
42
+ else
43
+ sql = visitor.compile(arel_or_sql_string, collector)
44
+ end
45
+ allow_retry = collector.retryable
46
+ [sql.freeze, binds, preparable, allow_retry]
47
+ else
48
+ arel_or_sql_string = arel_or_sql_string.dup.freeze unless arel_or_sql_string.frozen?
49
+ [arel_or_sql_string, binds, preparable, allow_retry]
50
+ end
51
+ end
52
+ private :to_sql_and_binds
53
+
54
+ # This is used in the StatementCache object. It returns an object that
55
+ # can be used to query the database repeatedly.
56
+ def cacheable_query(klass, arel) # :nodoc:
57
+ if prepared_statements
58
+ sql, binds = visitor.compile(arel.ast, collector)
59
+ query = klass.query(sql)
60
+ else
61
+ collector = klass.partial_query_collector
62
+ parts, binds = visitor.compile(arel.ast, collector)
63
+ query = klass.partial_query(parts)
64
+ end
65
+ [query, binds]
66
+ end
67
+
68
+ # Returns an ActiveRecord::Result instance.
69
+ def select_all(arel, name = nil, binds = [], preparable: nil, async: false, allow_retry: false)
70
+ arel = arel_from_relation(arel)
71
+ sql, binds, preparable, allow_retry = to_sql_and_binds(arel, binds, preparable, allow_retry)
72
+
73
+ select(sql, name, binds,
74
+ prepare: prepared_statements && preparable,
75
+ async: async && FutureResult::SelectAll,
76
+ allow_retry: allow_retry
77
+ )
78
+ rescue ::RangeError
79
+ ActiveRecord::Result.empty(async: async)
80
+ end
81
+
82
+ # Returns a record hash with the column names as keys and column values
83
+ # as values.
84
+ def select_one(arel, name = nil, binds = [], async: false)
85
+ select_all(arel, name, binds, async: async).then(&:first)
86
+ end
87
+
88
+ # Returns a single value from a record
89
+ def select_value(arel, name = nil, binds = [], async: false)
90
+ select_rows(arel, name, binds, async: async).then { |rows| single_value_from_rows(rows) }
91
+ end
92
+
93
+ # Returns an array of the values of the first column in a select:
94
+ # select_values("SELECT id FROM companies LIMIT 3") => [1,2,3]
95
+ def select_values(arel, name = nil, binds = [])
96
+ select_rows(arel, name, binds).map(&:first)
97
+ end
98
+
99
+ # Returns an array of arrays containing the field values.
100
+ # Order is the same as that returned by +columns+.
101
+ def select_rows(arel, name = nil, binds = [], async: false)
102
+ select_all(arel, name, binds, async: async).then(&:rows)
103
+ end
104
+
105
+ def query_value(...) # :nodoc:
106
+ single_value_from_rows(query(...))
107
+ end
108
+
109
+ def query_values(...) # :nodoc:
110
+ query(...).map(&:first)
111
+ end
112
+
113
+ def query(...) # :nodoc:
114
+ internal_exec_query(...).rows
115
+ end
116
+
117
+ # Determines whether the SQL statement is a write query.
118
+ def write_query?(sql)
119
+ raise NotImplementedError
120
+ end
121
+
122
+ # Executes the SQL statement in the context of this connection and returns
123
+ # the raw result from the connection adapter.
124
+ #
125
+ # Setting +allow_retry+ to true causes the db to reconnect and retry
126
+ # executing the SQL statement in case of a connection-related exception.
127
+ # This option should only be enabled for known idempotent queries.
128
+ #
129
+ # Note: the query is assumed to have side effects and the query cache
130
+ # will be cleared. If the query is read-only, consider using #select_all
131
+ # instead.
132
+ #
133
+ # Note: depending on your database connector, the result returned by this
134
+ # method may be manually memory managed. Consider using #exec_query
135
+ # wrapper instead.
136
+ def execute(sql, name = nil, allow_retry: false)
137
+ internal_execute(sql, name, allow_retry: allow_retry)
138
+ end
139
+
140
+ # Executes +sql+ statement in the context of this connection using
141
+ # +binds+ as the bind substitutes. +name+ is logged along with
142
+ # the executed +sql+ statement.
143
+ #
144
+ # Note: the query is assumed to have side effects and the query cache
145
+ # will be cleared. If the query is read-only, consider using #select_all
146
+ # instead.
147
+ def exec_query(sql, name = "SQL", binds = [], prepare: false)
148
+ internal_exec_query(sql, name, binds, prepare: prepare)
149
+ end
150
+
151
+ # Executes insert +sql+ statement in the context of this connection using
152
+ # +binds+ as the bind substitutes. +name+ is logged along with
153
+ # the executed +sql+ statement.
154
+ # Some adapters support the `returning` keyword argument which allows to control the result of the query:
155
+ # `nil` is the default value and maintains default behavior. If an array of column names is passed -
156
+ # the result will contain values of the specified columns from the inserted row.
157
+ def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil)
158
+ sql, binds = sql_for_insert(sql, pk, binds, returning)
159
+ internal_exec_query(sql, name, binds)
160
+ end
161
+
162
+ # Executes delete +sql+ statement in the context of this connection using
163
+ # +binds+ as the bind substitutes. +name+ is logged along with
164
+ # the executed +sql+ statement.
165
+ def exec_delete(sql, name = nil, binds = [])
166
+ affected_rows(internal_execute(sql, name, binds))
167
+ end
168
+
169
+ # Executes update +sql+ statement in the context of this connection using
170
+ # +binds+ as the bind substitutes. +name+ is logged along with
171
+ # the executed +sql+ statement.
172
+ def exec_update(sql, name = nil, binds = [])
173
+ affected_rows(internal_execute(sql, name, binds))
174
+ end
175
+
176
+ def exec_insert_all(sql, name) # :nodoc:
177
+ internal_exec_query(sql, name)
178
+ end
179
+
180
+ def explain(arel, binds = [], options = []) # :nodoc:
181
+ raise NotImplementedError
182
+ end
183
+
184
+ # Executes an INSERT query and returns the new record's ID
185
+ #
186
+ # +id_value+ will be returned unless the value is +nil+, in
187
+ # which case the database will attempt to calculate the last inserted
188
+ # id and return that value.
189
+ #
190
+ # If the next id was calculated in advance (as in Oracle), it should be
191
+ # passed in as +id_value+.
192
+ # Some adapters support the `returning` keyword argument which allows defining the return value of the method:
193
+ # `nil` is the default value and maintains default behavior. If an array of column names is passed -
194
+ # an array of is returned from the method representing values of the specified columns from the inserted row.
195
+ def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [], returning: nil)
196
+ sql, binds = to_sql_and_binds(arel, binds)
197
+ value = exec_insert(sql, name, binds, pk, sequence_name, returning: returning)
198
+
199
+ return returning_column_values(value) unless returning.nil?
200
+
201
+ id_value || last_inserted_id(value)
202
+ end
203
+ alias create insert
204
+
205
+ # Executes the update statement and returns the number of rows affected.
206
+ def update(arel, name = nil, binds = [])
207
+ sql, binds = to_sql_and_binds(arel, binds)
208
+ exec_update(sql, name, binds)
209
+ end
210
+
211
+ # Executes the delete statement and returns the number of rows affected.
212
+ def delete(arel, name = nil, binds = [])
213
+ sql, binds = to_sql_and_binds(arel, binds)
214
+ exec_delete(sql, name, binds)
215
+ end
216
+
217
+ # Executes the truncate statement.
218
+ def truncate(table_name, name = nil)
219
+ execute(build_truncate_statement(table_name), name)
220
+ end
221
+
222
+ def truncate_tables(*table_names) # :nodoc:
223
+ table_names -= [pool.schema_migration.table_name, pool.internal_metadata.table_name]
224
+
225
+ return if table_names.empty?
226
+
227
+ disable_referential_integrity do
228
+ statements = build_truncate_statements(table_names)
229
+ execute_batch(statements, "Truncate Tables")
230
+ end
231
+ end
232
+
233
+ # Runs the given block in a database transaction, and returns the result
234
+ # of the block.
235
+ #
236
+ # == Transaction callbacks
237
+ #
238
+ # #transaction yields an ActiveRecord::Transaction object on which it is
239
+ # possible to register callback:
240
+ #
241
+ # ActiveRecord::Base.transaction do |transaction|
242
+ # transaction.before_commit { puts "before commit!" }
243
+ # transaction.after_commit { puts "after commit!" }
244
+ # transaction.after_rollback { puts "after rollback!" }
245
+ # end
246
+ #
247
+ # == Nested transactions support
248
+ #
249
+ # #transaction calls can be nested. By default, this makes all database
250
+ # statements in the nested transaction block become part of the parent
251
+ # transaction. For example, the following behavior may be surprising:
252
+ #
253
+ # ActiveRecord::Base.transaction do
254
+ # Post.create(title: 'first')
255
+ # ActiveRecord::Base.transaction do
256
+ # Post.create(title: 'second')
257
+ # raise ActiveRecord::Rollback
258
+ # end
259
+ # end
260
+ #
261
+ # This creates both "first" and "second" posts. Reason is the
262
+ # ActiveRecord::Rollback exception in the nested block does not issue a
263
+ # ROLLBACK. Since these exceptions are captured in transaction blocks,
264
+ # the parent block does not see it and the real transaction is committed.
265
+ #
266
+ # Most databases don't support true nested transactions. At the time of
267
+ # writing, the only database that supports true nested transactions that
268
+ # we're aware of, is MS-SQL.
269
+ #
270
+ # In order to get around this problem, #transaction will emulate the effect
271
+ # of nested transactions, by using savepoints:
272
+ # https://dev.mysql.com/doc/refman/en/savepoint.html.
273
+ #
274
+ # It is safe to call this method if a database transaction is already open,
275
+ # i.e. if #transaction is called within another #transaction block. In case
276
+ # of a nested call, #transaction will behave as follows:
277
+ #
278
+ # - The block will be run without doing anything. All database statements
279
+ # that happen within the block are effectively appended to the already
280
+ # open database transaction.
281
+ # - However, if +:requires_new+ is set, the block will be wrapped in a
282
+ # database savepoint acting as a sub-transaction.
283
+ #
284
+ # In order to get a ROLLBACK for the nested transaction you may ask for a
285
+ # real sub-transaction by passing <tt>requires_new: true</tt>.
286
+ # If anything goes wrong, the database rolls back to the beginning of
287
+ # the sub-transaction without rolling back the parent transaction.
288
+ # If we add it to the previous example:
289
+ #
290
+ # ActiveRecord::Base.transaction do
291
+ # Post.create(title: 'first')
292
+ # ActiveRecord::Base.transaction(requires_new: true) do
293
+ # Post.create(title: 'second')
294
+ # raise ActiveRecord::Rollback
295
+ # end
296
+ # end
297
+ #
298
+ # only post with title "first" is created.
299
+ #
300
+ # See ActiveRecord::Transactions to learn more.
301
+ #
302
+ # === Caveats
303
+ #
304
+ # MySQL doesn't support DDL transactions. If you perform a DDL operation,
305
+ # then any created savepoints will be automatically released. For example,
306
+ # if you've created a savepoint, then you execute a CREATE TABLE statement,
307
+ # then the savepoint that was created will be automatically released.
308
+ #
309
+ # This means that, on MySQL, you shouldn't execute DDL operations inside
310
+ # a #transaction call that you know might create a savepoint. Otherwise,
311
+ # #transaction will raise exceptions when it tries to release the
312
+ # already-automatically-released savepoints:
313
+ #
314
+ # Model.lease_connection.transaction do # BEGIN
315
+ # Model.lease_connection.transaction(requires_new: true) do # CREATE SAVEPOINT active_record_1
316
+ # Model.lease_connection.create_table(...)
317
+ # # active_record_1 now automatically released
318
+ # end # RELEASE SAVEPOINT active_record_1 <--- BOOM! database error!
319
+ # end
320
+ #
321
+ # == Transaction isolation
322
+ #
323
+ # If your database supports setting the isolation level for a transaction, you can set
324
+ # it like so:
325
+ #
326
+ # Post.transaction(isolation: :serializable) do
327
+ # # ...
328
+ # end
329
+ #
330
+ # Valid isolation levels are:
331
+ #
332
+ # * <tt>:read_uncommitted</tt>
333
+ # * <tt>:read_committed</tt>
334
+ # * <tt>:repeatable_read</tt>
335
+ # * <tt>:serializable</tt>
336
+ #
337
+ # You should consult the documentation for your database to understand the
338
+ # semantics of these different levels:
339
+ #
340
+ # * https://www.postgresql.org/docs/current/static/transaction-iso.html
341
+ # * https://dev.mysql.com/doc/refman/en/set-transaction.html
342
+ #
343
+ # An ActiveRecord::TransactionIsolationError will be raised if:
344
+ #
345
+ # * The adapter does not support setting the isolation level
346
+ # * You are joining an existing open transaction
347
+ # * You are creating a nested (savepoint) transaction
348
+ #
349
+ # The mysql2, trilogy, and postgresql adapters support setting the transaction
350
+ # isolation level.
351
+ # :args: (requires_new: nil, isolation: nil, &block)
352
+ def transaction(requires_new: nil, isolation: nil, joinable: true, &block)
353
+ if !requires_new && current_transaction.joinable?
354
+ if isolation
355
+ raise ActiveRecord::TransactionIsolationError, "cannot set isolation when joining a transaction"
356
+ end
357
+ yield current_transaction.user_transaction
358
+ else
359
+ within_new_transaction(isolation: isolation, joinable: joinable, &block)
360
+ end
361
+ rescue ActiveRecord::Rollback
362
+ # rollbacks are silently swallowed
363
+ end
364
+
365
+ attr_reader :transaction_manager # :nodoc:
366
+
367
+ delegate :within_new_transaction, :open_transactions, :current_transaction, :begin_transaction,
368
+ :commit_transaction, :rollback_transaction, :materialize_transactions,
369
+ :disable_lazy_transactions!, :enable_lazy_transactions!, :dirty_current_transaction,
370
+ to: :transaction_manager
371
+
372
+ def mark_transaction_written_if_write(sql) # :nodoc:
373
+ transaction = current_transaction
374
+ if transaction.open?
375
+ transaction.written ||= write_query?(sql)
376
+ end
377
+ end
378
+
379
+ def transaction_open?
380
+ current_transaction.open?
381
+ end
382
+
383
+ def reset_transaction(restore: false) # :nodoc:
384
+ # Store the existing transaction state to the side
385
+ old_state = @transaction_manager if restore && @transaction_manager&.restorable?
386
+
387
+ @transaction_manager = ConnectionAdapters::TransactionManager.new(self)
388
+
389
+ if block_given?
390
+ # Reconfigure the connection without any transaction state in the way
391
+ result = yield
392
+
393
+ # Now the connection's fully established, we can swap back
394
+ if old_state
395
+ @transaction_manager = old_state
396
+ @transaction_manager.restore_transactions
397
+ end
398
+
399
+ result
400
+ end
401
+ end
402
+
403
+ # Register a record with the current transaction so that its after_commit and after_rollback callbacks
404
+ # can be called.
405
+ def add_transaction_record(record, ensure_finalize = true)
406
+ current_transaction.add_record(record, ensure_finalize)
407
+ end
408
+
409
+ # Begins the transaction (and turns off auto-committing).
410
+ def begin_db_transaction() end
411
+
412
+ def begin_deferred_transaction(isolation_level = nil) # :nodoc:
413
+ if isolation_level
414
+ begin_isolated_db_transaction(isolation_level)
415
+ else
416
+ begin_db_transaction
417
+ end
418
+ end
419
+
420
+ def transaction_isolation_levels
421
+ {
422
+ read_uncommitted: "READ UNCOMMITTED",
423
+ read_committed: "READ COMMITTED",
424
+ repeatable_read: "REPEATABLE READ",
425
+ serializable: "SERIALIZABLE"
426
+ }
427
+ end
428
+
429
+ # Begins the transaction with the isolation level set. Raises an error by
430
+ # default; adapters that support setting the isolation level should implement
431
+ # this method.
432
+ def begin_isolated_db_transaction(isolation)
433
+ raise ActiveRecord::TransactionIsolationError, "adapter does not support setting transaction isolation"
434
+ end
435
+
436
+ # Hook point called after an isolated DB transaction is committed
437
+ # or rolled back.
438
+ # Most adapters don't need to implement anything because the isolation
439
+ # level is set on a per transaction basis.
440
+ # But some databases like SQLite set it on a per connection level
441
+ # and need to explicitly reset it after commit or rollback.
442
+ def reset_isolation_level
443
+ end
444
+
445
+ # Commits the transaction (and turns on auto-committing).
446
+ def commit_db_transaction() end
447
+
448
+ # Rolls back the transaction (and turns on auto-committing). Must be
449
+ # done if the transaction block raises an exception or returns false.
450
+ def rollback_db_transaction
451
+ exec_rollback_db_transaction
452
+ rescue ActiveRecord::ConnectionNotEstablished, ActiveRecord::ConnectionFailed
453
+ # Connection's gone; that counts as a rollback
454
+ end
455
+
456
+ def exec_rollback_db_transaction() end # :nodoc:
457
+
458
+ def restart_db_transaction
459
+ exec_restart_db_transaction
460
+ end
461
+
462
+ def exec_restart_db_transaction() end # :nodoc:
463
+
464
+ def rollback_to_savepoint(name = nil)
465
+ exec_rollback_to_savepoint(name)
466
+ end
467
+
468
+ def default_sequence_name(table, column)
469
+ nil
470
+ end
471
+
472
+ # Set the sequence to the max value of the table's column.
473
+ def reset_sequence!(table, column, sequence = nil)
474
+ # Do nothing by default. Implement for PostgreSQL, Oracle, ...
475
+ end
476
+
477
+ # Inserts the given fixture into the table. Overridden in adapters that require
478
+ # something beyond a simple insert (e.g. Oracle).
479
+ # Most of adapters should implement +insert_fixtures_set+ that leverages bulk SQL insert.
480
+ # We keep this method to provide fallback
481
+ # for databases like SQLite that do not support bulk inserts.
482
+ def insert_fixture(fixture, table_name)
483
+ execute(build_fixture_sql(Array.wrap(fixture), table_name), "Fixture Insert")
484
+ end
485
+
486
+ def insert_fixtures_set(fixture_set, tables_to_delete = [])
487
+ fixture_inserts = build_fixture_statements(fixture_set)
488
+ table_deletes = tables_to_delete.map { |table| "DELETE FROM #{quote_table_name(table)}" }
489
+ statements = table_deletes + fixture_inserts
490
+
491
+ transaction(requires_new: true) do
492
+ disable_referential_integrity do
493
+ execute_batch(statements, "Fixtures Load")
494
+ end
495
+ end
496
+ end
497
+
498
+ def empty_insert_statement_value(primary_key = nil)
499
+ "DEFAULT VALUES"
500
+ end
501
+
502
+ # Sanitizes the given LIMIT parameter in order to prevent SQL injection.
503
+ #
504
+ # The +limit+ may be anything that can evaluate to a string via #to_s. It
505
+ # should look like an integer, or an Arel SQL literal.
506
+ #
507
+ # Returns Integer and Arel::Nodes::SqlLiteral limits as is.
508
+ def sanitize_limit(limit)
509
+ if limit.is_a?(Integer) || limit.is_a?(Arel::Nodes::SqlLiteral)
510
+ limit
511
+ else
512
+ Integer(limit)
513
+ end
514
+ end
515
+
516
+ # Fixture value is quoted by Arel, however scalar values
517
+ # are not quotable. In this case we want to convert
518
+ # the column value to YAML.
519
+ def with_yaml_fallback(value) # :nodoc:
520
+ if value.is_a?(Hash) || value.is_a?(Array)
521
+ YAML.dump(value)
522
+ else
523
+ value
524
+ end
525
+ end
526
+
527
+ # This is a safe default, even if not high precision on all databases
528
+ HIGH_PRECISION_CURRENT_TIMESTAMP = Arel.sql("CURRENT_TIMESTAMP", retryable: true).freeze # :nodoc:
529
+ private_constant :HIGH_PRECISION_CURRENT_TIMESTAMP
530
+
531
+ # Returns an Arel SQL literal for the CURRENT_TIMESTAMP for usage with
532
+ # arbitrary precision date/time columns.
533
+ #
534
+ # Adapters supporting datetime with precision should override this to
535
+ # provide as much precision as is available.
536
+ def high_precision_current_timestamp
537
+ HIGH_PRECISION_CURRENT_TIMESTAMP
538
+ end
539
+
540
+ # Same as raw_execute but returns an ActiveRecord::Result object.
541
+ def raw_exec_query(...) # :nodoc:
542
+ cast_result(raw_execute(...))
543
+ end
544
+
545
+ # Execute a query and returns an ActiveRecord::Result
546
+ def internal_exec_query(...) # :nodoc:
547
+ cast_result(internal_execute(...))
548
+ end
549
+
550
+ private
551
+ # Lowest level way to execute a query. Doesn't check for illegal writes, doesn't annotate queries, yields a native result object.
552
+ def raw_execute(sql, name = nil, binds = [], prepare: false, async: false, allow_retry: false, materialize_transactions: true, batch: false)
553
+ type_casted_binds = type_casted_binds(binds)
554
+ log(sql, name, binds, type_casted_binds, async: async) do |notification_payload|
555
+ with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
556
+ perform_query(conn, sql, binds, type_casted_binds, prepare: prepare, notification_payload: notification_payload, batch: batch)
557
+ end
558
+ end
559
+ end
560
+
561
+ def perform_query(raw_connection, sql, binds, type_casted_binds, prepare:, notification_payload:, batch:)
562
+ raise NotImplementedError
563
+ end
564
+
565
+ # Receive a native adapter result object and returns an ActiveRecord::Result object.
566
+ def cast_result(raw_result)
567
+ raise NotImplementedError
568
+ end
569
+
570
+ def affected_rows(raw_result)
571
+ raise NotImplementedError
572
+ end
573
+
574
+ def preprocess_query(sql)
575
+ check_if_write_query(sql)
576
+ mark_transaction_written_if_write(sql)
577
+
578
+ # We call tranformers after the write checks so we don't add extra parsing work.
579
+ # This means we assume no transformer whille change a read for a write
580
+ # but it would be insane to do such a thing.
581
+ ActiveRecord.query_transformers.each do |transformer|
582
+ sql = transformer.call(sql, self)
583
+ end
584
+
585
+ sql
586
+ end
587
+
588
+ # Same as #internal_exec_query, but yields a native adapter result
589
+ def internal_execute(sql, name = "SQL", binds = [], prepare: false, async: false, allow_retry: false, materialize_transactions: true, &block)
590
+ sql = preprocess_query(sql)
591
+ raw_execute(sql, name, binds, prepare: prepare, async: async, allow_retry: allow_retry, materialize_transactions: materialize_transactions, &block)
592
+ end
593
+
594
+ def execute_batch(statements, name = nil, **kwargs)
595
+ statements.each do |statement|
596
+ raw_execute(statement, name, **kwargs)
597
+ end
598
+ end
599
+
600
+ DEFAULT_INSERT_VALUE = Arel.sql("DEFAULT").freeze
601
+ private_constant :DEFAULT_INSERT_VALUE
602
+
603
+ def default_insert_value(column)
604
+ DEFAULT_INSERT_VALUE
605
+ end
606
+
607
+ def build_fixture_sql(fixtures, table_name)
608
+ columns = schema_cache.columns_hash(table_name).reject { |_, column| supports_virtual_columns? && column.virtual? }
609
+
610
+ values_list = fixtures.map do |fixture|
611
+ fixture = fixture.stringify_keys
612
+
613
+ unknown_columns = fixture.keys - columns.keys
614
+ if unknown_columns.any?
615
+ raise Fixture::FixtureError, %(table "#{table_name}" has no columns named #{unknown_columns.map(&:inspect).join(', ')}.)
616
+ end
617
+
618
+ columns.map do |name, column|
619
+ if fixture.key?(name)
620
+ type = lookup_cast_type_from_column(column)
621
+ with_yaml_fallback(type.serialize(fixture[name]))
622
+ else
623
+ default_insert_value(column)
624
+ end
625
+ end
626
+ end
627
+
628
+ table = Arel::Table.new(table_name)
629
+ manager = Arel::InsertManager.new(table)
630
+
631
+ if values_list.size == 1
632
+ values = values_list.shift
633
+ new_values = []
634
+ columns.each_key.with_index { |column, i|
635
+ unless values[i].equal?(DEFAULT_INSERT_VALUE)
636
+ new_values << values[i]
637
+ manager.columns << table[column]
638
+ end
639
+ }
640
+ values_list << new_values
641
+ else
642
+ columns.each_key { |column| manager.columns << table[column] }
643
+ end
644
+
645
+ manager.values = manager.create_values_list(values_list)
646
+ visitor.compile(manager.ast)
647
+ end
648
+
649
+ def build_fixture_statements(fixture_set)
650
+ fixture_set.filter_map do |table_name, fixtures|
651
+ next if fixtures.empty?
652
+ build_fixture_sql(fixtures, table_name)
653
+ end
654
+ end
655
+
656
+ def build_truncate_statement(table_name)
657
+ "TRUNCATE TABLE #{quote_table_name(table_name)}"
658
+ end
659
+
660
+ def build_truncate_statements(table_names)
661
+ table_names.map do |table_name|
662
+ build_truncate_statement(table_name)
663
+ end
664
+ end
665
+
666
+ def combine_multi_statements(total_sql)
667
+ total_sql.join(";\n")
668
+ end
669
+
670
+ # Returns an ActiveRecord::Result instance.
671
+ def select(sql, name = nil, binds = [], prepare: false, async: false, allow_retry: false)
672
+ if async && async_enabled?
673
+ if current_transaction.joinable?
674
+ raise AsynchronousQueryInsideTransactionError, "Asynchronous queries are not allowed inside transactions"
675
+ end
676
+
677
+ # We make sure to run query transformers on the orignal thread
678
+ sql = preprocess_query(sql)
679
+ future_result = async.new(
680
+ pool,
681
+ sql,
682
+ name,
683
+ binds,
684
+ prepare: prepare,
685
+ )
686
+ if supports_concurrent_connections? && !current_transaction.joinable?
687
+ future_result.schedule!(ActiveRecord::Base.asynchronous_queries_session)
688
+ else
689
+ future_result.execute!(self)
690
+ end
691
+ future_result
692
+ else
693
+ result = internal_exec_query(sql, name, binds, prepare: prepare, allow_retry: allow_retry)
694
+ if async
695
+ FutureResult.wrap(result)
696
+ else
697
+ result
698
+ end
699
+ end
700
+ end
701
+
702
+ def sql_for_insert(sql, pk, binds, returning) # :nodoc:
703
+ if supports_insert_returning?
704
+ if pk.nil?
705
+ # Extract the table from the insert sql. Yuck.
706
+ table_ref = extract_table_ref_from_insert_sql(sql)
707
+ pk = primary_key(table_ref) if table_ref
708
+ end
709
+
710
+ returning_columns = returning || Array(pk)
711
+
712
+ returning_columns_statement = returning_columns.map { |c| quote_column_name(c) }.join(", ")
713
+ sql = "#{sql} RETURNING #{returning_columns_statement}" if returning_columns.any?
714
+ end
715
+
716
+ [sql, binds]
717
+ end
718
+
719
+ def last_inserted_id(result)
720
+ single_value_from_rows(result.rows)
721
+ end
722
+
723
+ def returning_column_values(result)
724
+ [last_inserted_id(result)]
725
+ end
726
+
727
+ def single_value_from_rows(rows)
728
+ row = rows.first
729
+ row && row.first
730
+ end
731
+
732
+ def arel_from_relation(relation)
733
+ if relation.is_a?(Relation)
734
+ relation.arel
735
+ else
736
+ relation
737
+ end
738
+ end
739
+
740
+ def extract_table_ref_from_insert_sql(sql)
741
+ if sql =~ /into\s("[A-Za-z0-9_."\[\]\s]+"|[A-Za-z0-9_."\[\]]+)\s*/im
742
+ $1.delete('"').strip
743
+ end
744
+ end
745
+ end
746
+ end
747
+ end