omg-activerecord 8.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
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