activerecord 6.0.0 → 7.2.3

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 (376) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +996 -594
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +34 -34
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record/aggregations.rb +22 -20
  7. data/lib/active_record/association_relation.rb +22 -12
  8. data/lib/active_record/associations/alias_tracker.rb +41 -30
  9. data/lib/active_record/associations/association.rb +106 -41
  10. data/lib/active_record/associations/association_scope.rb +30 -21
  11. data/lib/active_record/associations/belongs_to_association.rb +69 -14
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +20 -6
  13. data/lib/active_record/associations/builder/association.rb +39 -6
  14. data/lib/active_record/associations/builder/belongs_to.rb +47 -17
  15. data/lib/active_record/associations/builder/collection_association.rb +14 -6
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -10
  17. data/lib/active_record/associations/builder/has_many.rb +7 -3
  18. data/lib/active_record/associations/builder/has_one.rb +13 -16
  19. data/lib/active_record/associations/builder/singular_association.rb +7 -3
  20. data/lib/active_record/associations/collection_association.rb +90 -53
  21. data/lib/active_record/associations/collection_proxy.rb +54 -19
  22. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  23. data/lib/active_record/associations/errors.rb +265 -0
  24. data/lib/active_record/associations/foreign_association.rb +21 -1
  25. data/lib/active_record/associations/has_many_association.rb +41 -10
  26. data/lib/active_record/associations/has_many_through_association.rb +29 -12
  27. data/lib/active_record/associations/has_one_association.rb +33 -9
  28. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  29. data/lib/active_record/associations/join_dependency/join_association.rb +41 -17
  30. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  31. data/lib/active_record/associations/join_dependency.rb +97 -54
  32. data/lib/active_record/associations/nested_error.rb +47 -0
  33. data/lib/active_record/associations/preloader/association.rb +237 -54
  34. data/lib/active_record/associations/preloader/batch.rb +48 -0
  35. data/lib/active_record/associations/preloader/branch.rb +153 -0
  36. data/lib/active_record/associations/preloader/through_association.rb +51 -17
  37. data/lib/active_record/associations/preloader.rb +55 -121
  38. data/lib/active_record/associations/singular_association.rb +16 -4
  39. data/lib/active_record/associations/through_association.rb +26 -15
  40. data/lib/active_record/associations.rb +454 -440
  41. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  42. data/lib/active_record/attribute_assignment.rb +11 -14
  43. data/lib/active_record/attribute_methods/before_type_cast.rb +36 -11
  44. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  45. data/lib/active_record/attribute_methods/dirty.rb +75 -34
  46. data/lib/active_record/attribute_methods/primary_key.rb +53 -31
  47. data/lib/active_record/attribute_methods/query.rb +31 -22
  48. data/lib/active_record/attribute_methods/read.rb +16 -17
  49. data/lib/active_record/attribute_methods/serialization.rb +177 -35
  50. data/lib/active_record/attribute_methods/time_zone_conversion.rb +18 -15
  51. data/lib/active_record/attribute_methods/write.rb +16 -28
  52. data/lib/active_record/attribute_methods.rb +227 -100
  53. data/lib/active_record/attributes.rb +94 -56
  54. data/lib/active_record/autosave_association.rb +119 -73
  55. data/lib/active_record/base.rb +31 -21
  56. data/lib/active_record/callbacks.rb +168 -55
  57. data/lib/active_record/coders/column_serializer.rb +61 -0
  58. data/lib/active_record/coders/json.rb +1 -1
  59. data/lib/active_record/coders/yaml_column.rb +70 -25
  60. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
  61. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +367 -565
  64. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -57
  65. data/lib/active_record/connection_adapters/abstract/database_statements.rb +277 -89
  66. data/lib/active_record/connection_adapters/abstract/query_cache.rb +241 -69
  67. data/lib/active_record/connection_adapters/abstract/quoting.rb +122 -134
  68. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  69. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  70. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +324 -72
  71. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +17 -4
  72. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +611 -211
  73. data/lib/active_record/connection_adapters/abstract/transaction.rb +425 -82
  74. data/lib/active_record/connection_adapters/abstract_adapter.rb +698 -211
  75. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +464 -239
  76. data/lib/active_record/connection_adapters/column.rb +28 -1
  77. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  78. data/lib/active_record/connection_adapters/mysql/column.rb +2 -1
  79. data/lib/active_record/connection_adapters/mysql/database_statements.rb +32 -137
  80. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  81. data/lib/active_record/connection_adapters/mysql/quoting.rb +90 -43
  82. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +41 -7
  83. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +18 -1
  84. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +13 -4
  85. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +53 -15
  86. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  87. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
  88. data/lib/active_record/connection_adapters/mysql2_adapter.rb +127 -63
  89. data/lib/active_record/connection_adapters/pool_config.rb +83 -0
  90. data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
  91. data/lib/active_record/connection_adapters/postgresql/column.rb +54 -2
  92. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +127 -100
  93. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +9 -5
  95. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +10 -2
  96. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +15 -2
  97. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  98. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -15
  99. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
  101. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +5 -4
  103. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  104. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
  105. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +35 -8
  106. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  110. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -4
  111. data/lib/active_record/connection_adapters/postgresql/oid.rb +4 -0
  112. data/lib/active_record/connection_adapters/postgresql/quoting.rb +139 -106
  113. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -2
  114. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +98 -4
  115. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +176 -4
  116. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -1
  117. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +462 -118
  118. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  119. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -11
  120. data/lib/active_record/connection_adapters/postgresql_adapter.rb +585 -295
  121. data/lib/active_record/connection_adapters/schema_cache.rb +399 -60
  122. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  123. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  124. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +99 -48
  125. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +80 -54
  126. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +27 -1
  127. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
  128. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
  129. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +102 -24
  130. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +425 -174
  131. data/lib/active_record/connection_adapters/statement_pool.rb +7 -1
  132. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  133. data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
  134. data/lib/active_record/connection_adapters.rb +176 -0
  135. data/lib/active_record/connection_handling.rb +243 -115
  136. data/lib/active_record/core.rb +481 -199
  137. data/lib/active_record/counter_cache.rb +69 -32
  138. data/lib/active_record/database_configurations/connection_url_resolver.rb +107 -0
  139. data/lib/active_record/database_configurations/database_config.rb +77 -10
  140. data/lib/active_record/database_configurations/hash_config.rb +148 -26
  141. data/lib/active_record/database_configurations/url_config.rb +44 -45
  142. data/lib/active_record/database_configurations.rb +190 -114
  143. data/lib/active_record/delegated_type.rb +279 -0
  144. data/lib/active_record/deprecator.rb +7 -0
  145. data/lib/active_record/destroy_association_async_job.rb +38 -0
  146. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  147. data/lib/active_record/dynamic_matchers.rb +5 -6
  148. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  149. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  150. data/lib/active_record/encryption/cipher.rb +53 -0
  151. data/lib/active_record/encryption/config.rb +68 -0
  152. data/lib/active_record/encryption/configurable.rb +60 -0
  153. data/lib/active_record/encryption/context.rb +42 -0
  154. data/lib/active_record/encryption/contexts.rb +76 -0
  155. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  156. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  157. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  158. data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
  159. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  160. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  161. data/lib/active_record/encryption/encryptor.rb +171 -0
  162. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  163. data/lib/active_record/encryption/errors.rb +15 -0
  164. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  165. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  166. data/lib/active_record/encryption/key.rb +28 -0
  167. data/lib/active_record/encryption/key_generator.rb +53 -0
  168. data/lib/active_record/encryption/key_provider.rb +46 -0
  169. data/lib/active_record/encryption/message.rb +33 -0
  170. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  171. data/lib/active_record/encryption/message_serializer.rb +96 -0
  172. data/lib/active_record/encryption/null_encryptor.rb +25 -0
  173. data/lib/active_record/encryption/properties.rb +76 -0
  174. data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
  175. data/lib/active_record/encryption/scheme.rb +100 -0
  176. data/lib/active_record/encryption.rb +58 -0
  177. data/lib/active_record/enum.rb +224 -73
  178. data/lib/active_record/errors.rb +254 -36
  179. data/lib/active_record/explain.rb +30 -17
  180. data/lib/active_record/explain_registry.rb +11 -6
  181. data/lib/active_record/explain_subscriber.rb +2 -2
  182. data/lib/active_record/fixture_set/file.rb +22 -15
  183. data/lib/active_record/fixture_set/model_metadata.rb +15 -6
  184. data/lib/active_record/fixture_set/render_context.rb +3 -1
  185. data/lib/active_record/fixture_set/table_row.rb +88 -16
  186. data/lib/active_record/fixture_set/table_rows.rb +4 -5
  187. data/lib/active_record/fixtures.rb +229 -116
  188. data/lib/active_record/future_result.rb +178 -0
  189. data/lib/active_record/gem_version.rb +4 -4
  190. data/lib/active_record/inheritance.rb +121 -48
  191. data/lib/active_record/insert_all.rb +178 -29
  192. data/lib/active_record/integration.rb +16 -14
  193. data/lib/active_record/internal_metadata.rb +132 -21
  194. data/lib/active_record/legacy_yaml_adapter.rb +3 -36
  195. data/lib/active_record/locking/optimistic.rb +64 -33
  196. data/lib/active_record/locking/pessimistic.rb +21 -8
  197. data/lib/active_record/log_subscriber.rb +61 -30
  198. data/lib/active_record/marshalling.rb +59 -0
  199. data/lib/active_record/message_pack.rb +124 -0
  200. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  201. data/lib/active_record/middleware/database_selector/resolver.rb +19 -19
  202. data/lib/active_record/middleware/database_selector.rb +25 -13
  203. data/lib/active_record/middleware/shard_selector.rb +62 -0
  204. data/lib/active_record/migration/command_recorder.rb +160 -55
  205. data/lib/active_record/migration/compatibility.rb +286 -43
  206. data/lib/active_record/migration/default_strategy.rb +22 -0
  207. data/lib/active_record/migration/execution_strategy.rb +19 -0
  208. data/lib/active_record/migration/join_table.rb +1 -2
  209. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  210. data/lib/active_record/migration.rb +421 -193
  211. data/lib/active_record/model_schema.rb +217 -125
  212. data/lib/active_record/nested_attributes.rb +62 -27
  213. data/lib/active_record/no_touching.rb +4 -4
  214. data/lib/active_record/normalization.rb +163 -0
  215. data/lib/active_record/persistence.rb +322 -319
  216. data/lib/active_record/promise.rb +84 -0
  217. data/lib/active_record/query_cache.rb +18 -15
  218. data/lib/active_record/query_logs.rb +193 -0
  219. data/lib/active_record/query_logs_formatter.rb +41 -0
  220. data/lib/active_record/querying.rb +54 -14
  221. data/lib/active_record/railtie.rb +250 -72
  222. data/lib/active_record/railties/console_sandbox.rb +2 -4
  223. data/lib/active_record/railties/controller_runtime.rb +25 -11
  224. data/lib/active_record/railties/databases.rake +312 -197
  225. data/lib/active_record/railties/job_runtime.rb +23 -0
  226. data/lib/active_record/readonly_attributes.rb +45 -3
  227. data/lib/active_record/reflection.rb +389 -146
  228. data/lib/active_record/relation/batches/batch_enumerator.rb +61 -16
  229. data/lib/active_record/relation/batches.rb +214 -73
  230. data/lib/active_record/relation/calculations.rb +379 -124
  231. data/lib/active_record/relation/delegation.rb +36 -23
  232. data/lib/active_record/relation/finder_methods.rb +159 -49
  233. data/lib/active_record/relation/from_clause.rb +5 -1
  234. data/lib/active_record/relation/merger.rb +41 -33
  235. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -11
  236. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -7
  237. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +20 -13
  238. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  239. data/lib/active_record/relation/predicate_builder.rb +79 -53
  240. data/lib/active_record/relation/query_attribute.rb +30 -12
  241. data/lib/active_record/relation/query_methods.rb +1156 -279
  242. data/lib/active_record/relation/record_fetch_warning.rb +12 -11
  243. data/lib/active_record/relation/spawn_methods.rb +10 -9
  244. data/lib/active_record/relation/where_clause.rb +100 -66
  245. data/lib/active_record/relation.rb +829 -194
  246. data/lib/active_record/result.rb +76 -56
  247. data/lib/active_record/runtime_registry.rb +71 -13
  248. data/lib/active_record/sanitization.rb +86 -47
  249. data/lib/active_record/schema.rb +39 -23
  250. data/lib/active_record/schema_dumper.rb +140 -33
  251. data/lib/active_record/schema_migration.rb +74 -29
  252. data/lib/active_record/scoping/default.rb +73 -19
  253. data/lib/active_record/scoping/named.rb +10 -28
  254. data/lib/active_record/scoping.rb +65 -35
  255. data/lib/active_record/secure_password.rb +60 -0
  256. data/lib/active_record/secure_token.rb +34 -8
  257. data/lib/active_record/serialization.rb +11 -4
  258. data/lib/active_record/signed_id.rb +138 -0
  259. data/lib/active_record/statement_cache.rb +26 -10
  260. data/lib/active_record/store.rb +19 -14
  261. data/lib/active_record/suppressor.rb +15 -17
  262. data/lib/active_record/table_metadata.rb +46 -36
  263. data/lib/active_record/tasks/database_tasks.rb +371 -205
  264. data/lib/active_record/tasks/mysql_database_tasks.rb +43 -36
  265. data/lib/active_record/tasks/postgresql_database_tasks.rb +54 -41
  266. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -13
  267. data/lib/active_record/test_databases.rb +5 -4
  268. data/lib/active_record/test_fixtures.rb +189 -104
  269. data/lib/active_record/testing/query_assertions.rb +121 -0
  270. data/lib/active_record/timestamp.rb +35 -25
  271. data/lib/active_record/token_for.rb +123 -0
  272. data/lib/active_record/touch_later.rb +31 -27
  273. data/lib/active_record/transaction.rb +132 -0
  274. data/lib/active_record/transactions.rb +131 -99
  275. data/lib/active_record/translation.rb +3 -5
  276. data/lib/active_record/type/adapter_specific_registry.rb +33 -18
  277. data/lib/active_record/type/hash_lookup_type_map.rb +34 -2
  278. data/lib/active_record/type/internal/timezone.rb +7 -2
  279. data/lib/active_record/type/serialized.rb +11 -6
  280. data/lib/active_record/type/time.rb +14 -0
  281. data/lib/active_record/type/type_map.rb +17 -21
  282. data/lib/active_record/type/unsigned_integer.rb +0 -1
  283. data/lib/active_record/type.rb +7 -2
  284. data/lib/active_record/type_caster/connection.rb +4 -5
  285. data/lib/active_record/type_caster/map.rb +8 -5
  286. data/lib/active_record/validations/absence.rb +1 -1
  287. data/lib/active_record/validations/associated.rb +13 -8
  288. data/lib/active_record/validations/numericality.rb +36 -0
  289. data/lib/active_record/validations/presence.rb +5 -28
  290. data/lib/active_record/validations/uniqueness.rb +88 -18
  291. data/lib/active_record/validations.rb +15 -8
  292. data/lib/active_record/version.rb +1 -1
  293. data/lib/active_record.rb +446 -40
  294. data/lib/arel/alias_predication.rb +1 -1
  295. data/lib/arel/attributes/attribute.rb +4 -8
  296. data/lib/arel/collectors/bind.rb +8 -1
  297. data/lib/arel/collectors/composite.rb +15 -0
  298. data/lib/arel/collectors/sql_string.rb +7 -0
  299. data/lib/arel/collectors/substitute_binds.rb +7 -0
  300. data/lib/arel/crud.rb +30 -22
  301. data/lib/arel/delete_manager.rb +23 -4
  302. data/lib/arel/errors.rb +10 -0
  303. data/lib/arel/factory_methods.rb +4 -0
  304. data/lib/arel/filter_predications.rb +9 -0
  305. data/lib/arel/insert_manager.rb +2 -3
  306. data/lib/arel/nodes/binary.rb +82 -9
  307. data/lib/arel/nodes/bind_param.rb +8 -0
  308. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  309. data/lib/arel/nodes/casted.rb +22 -10
  310. data/lib/arel/nodes/cte.rb +36 -0
  311. data/lib/arel/nodes/delete_statement.rb +14 -13
  312. data/lib/arel/nodes/equality.rb +6 -9
  313. data/lib/arel/nodes/filter.rb +10 -0
  314. data/lib/arel/nodes/fragments.rb +35 -0
  315. data/lib/arel/nodes/function.rb +1 -0
  316. data/lib/arel/nodes/grouping.rb +3 -0
  317. data/lib/arel/nodes/homogeneous_in.rb +68 -0
  318. data/lib/arel/nodes/in.rb +8 -1
  319. data/lib/arel/nodes/infix_operation.rb +13 -1
  320. data/lib/arel/nodes/insert_statement.rb +2 -2
  321. data/lib/arel/nodes/join_source.rb +1 -1
  322. data/lib/arel/nodes/leading_join.rb +8 -0
  323. data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
  324. data/lib/arel/nodes/node.rb +122 -11
  325. data/lib/arel/nodes/ordering.rb +27 -0
  326. data/lib/arel/nodes/select_core.rb +2 -2
  327. data/lib/arel/nodes/select_statement.rb +2 -2
  328. data/lib/arel/nodes/sql_literal.rb +16 -0
  329. data/lib/arel/nodes/table_alias.rb +11 -3
  330. data/lib/arel/nodes/unary.rb +0 -1
  331. data/lib/arel/nodes/update_statement.rb +11 -4
  332. data/lib/arel/nodes.rb +10 -3
  333. data/lib/arel/predications.rb +31 -28
  334. data/lib/arel/select_manager.rb +18 -9
  335. data/lib/arel/table.rb +21 -10
  336. data/lib/arel/tree_manager.rb +8 -15
  337. data/lib/arel/update_manager.rb +25 -5
  338. data/lib/arel/visitors/dot.rb +94 -90
  339. data/lib/arel/visitors/mysql.rb +34 -6
  340. data/lib/arel/visitors/postgresql.rb +5 -16
  341. data/lib/arel/visitors/sqlite.rb +25 -1
  342. data/lib/arel/visitors/to_sql.rb +227 -81
  343. data/lib/arel/visitors/visitor.rb +2 -3
  344. data/lib/arel/visitors.rb +0 -7
  345. data/lib/arel.rb +37 -15
  346. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  347. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  348. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  349. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  350. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +6 -1
  351. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
  352. data/lib/rails/generators/active_record/migration.rb +9 -3
  353. data/lib/rails/generators/active_record/model/USAGE +113 -0
  354. data/lib/rails/generators/active_record/model/model_generator.rb +49 -4
  355. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  356. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  357. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  358. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  359. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  360. metadata +117 -30
  361. data/lib/active_record/attribute_decorators.rb +0 -90
  362. data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
  363. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  364. data/lib/active_record/define_callbacks.rb +0 -22
  365. data/lib/active_record/null_relation.rb +0 -68
  366. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  367. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  368. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  369. data/lib/arel/attributes.rb +0 -22
  370. data/lib/arel/visitors/depth_first.rb +0 -204
  371. data/lib/arel/visitors/ibm_db.rb +0 -34
  372. data/lib/arel/visitors/informix.rb +0 -62
  373. data/lib/arel/visitors/mssql.rb +0 -157
  374. data/lib/arel/visitors/oracle.rb +0 -159
  375. data/lib/arel/visitors/oracle12.rb +0 -66
  376. data/lib/arel/visitors/where_sql.rb +0 -23
@@ -19,8 +19,8 @@ module Arel # :nodoc: all
19
19
  end
20
20
 
21
21
  private
22
-
23
22
  def visit_Arel_Nodes_DeleteStatement(o, collector)
23
+ collector.retryable = false
24
24
  o = prepare_delete_statement(o)
25
25
 
26
26
  if has_join_sources?(o)
@@ -35,9 +35,11 @@ module Arel # :nodoc: all
35
35
  collect_nodes_for o.wheres, collector, " WHERE ", " AND "
36
36
  collect_nodes_for o.orders, collector, " ORDER BY "
37
37
  maybe_visit o.limit, collector
38
+ maybe_visit o.comment, collector
38
39
  end
39
40
 
40
41
  def visit_Arel_Nodes_UpdateStatement(o, collector)
42
+ collector.retryable = false
41
43
  o = prepare_update_statement(o)
42
44
 
43
45
  collector << "UPDATE "
@@ -47,9 +49,11 @@ module Arel # :nodoc: all
47
49
  collect_nodes_for o.wheres, collector, " WHERE ", " AND "
48
50
  collect_nodes_for o.orders, collector, " ORDER BY "
49
51
  maybe_visit o.limit, collector
52
+ maybe_visit o.comment, collector
50
53
  end
51
54
 
52
55
  def visit_Arel_Nodes_InsertStatement(o, collector)
56
+ collector.retryable = false
53
57
  collector << "INSERT INTO "
54
58
  collector = visit o.relation, collector
55
59
 
@@ -83,12 +87,9 @@ module Arel # :nodoc: all
83
87
  end
84
88
 
85
89
  def visit_Arel_Nodes_Casted(o, collector)
86
- collector << quoted(o.val, o.attribute).to_s
87
- end
88
-
89
- def visit_Arel_Nodes_Quoted(o, collector)
90
- collector << quoted(o.expr, nil).to_s
90
+ collector << quote(o.value_for_database).to_s
91
91
  end
92
+ alias :visit_Arel_Nodes_Quoted :visit_Arel_Nodes_Casted
92
93
 
93
94
  def visit_Arel_Nodes_True(o, collector)
94
95
  collector << "TRUE"
@@ -107,7 +108,7 @@ module Arel # :nodoc: all
107
108
  row.each_with_index do |value, k|
108
109
  collector << ", " unless k == 0
109
110
  case value
110
- when Nodes::SqlLiteral, Nodes::BindParam
111
+ when Nodes::SqlLiteral, Nodes::BindParam, ActiveModel::Attribute
111
112
  collector = visit(value, collector)
112
113
  else
113
114
  collector << quote(value).to_s
@@ -139,6 +140,8 @@ module Arel # :nodoc: all
139
140
  visit_Arel_Nodes_SelectOptions(o, collector)
140
141
  end
141
142
 
143
+ # The Oracle enhanced adapter uses this private method,
144
+ # see https://github.com/rsim/oracle-enhanced/issues/2186
142
145
  def visit_Arel_Nodes_SelectOptions(o, collector)
143
146
  collector = maybe_visit o.limit, collector
144
147
  collector = maybe_visit o.offset, collector
@@ -196,12 +199,12 @@ module Arel # :nodoc: all
196
199
 
197
200
  def visit_Arel_Nodes_With(o, collector)
198
201
  collector << "WITH "
199
- inject_join o.children, collector, ", "
202
+ collect_ctes(o.children, collector)
200
203
  end
201
204
 
202
205
  def visit_Arel_Nodes_WithRecursive(o, collector)
203
206
  collector << "WITH RECURSIVE "
204
- inject_join o.children, collector, ", "
207
+ collect_ctes(o.children, collector)
205
208
  end
206
209
 
207
210
  def visit_Arel_Nodes_Union(o, collector)
@@ -247,6 +250,13 @@ module Arel # :nodoc: all
247
250
  collector << ")"
248
251
  end
249
252
 
253
+ def visit_Arel_Nodes_Filter(o, collector)
254
+ visit o.left, collector
255
+ collector << " FILTER (WHERE "
256
+ visit o.right, collector
257
+ collector << ")"
258
+ end
259
+
250
260
  def visit_Arel_Nodes_Rows(o, collector)
251
261
  if o.expr
252
262
  collector << "ROWS "
@@ -325,6 +335,28 @@ module Arel # :nodoc: all
325
335
  end
326
336
  end
327
337
 
338
+ def visit_Arel_Nodes_HomogeneousIn(o, collector)
339
+ collector.preparable = false
340
+
341
+ visit o.left, collector
342
+
343
+ if o.type == :in
344
+ collector << " IN ("
345
+ else
346
+ collector << " NOT IN ("
347
+ end
348
+
349
+ values = o.casted_values
350
+
351
+ if values.empty?
352
+ collector << @connection.quote(nil)
353
+ else
354
+ collector.add_binds(values, o.proc_for_binds, &bind_block)
355
+ end
356
+
357
+ collector << ")"
358
+ end
359
+
328
360
  def visit_Arel_SelectManager(o, collector)
329
361
  collector << "("
330
362
  visit(o.ast, collector) << ")"
@@ -338,11 +370,23 @@ module Arel # :nodoc: all
338
370
  visit(o.expr, collector) << " DESC"
339
371
  end
340
372
 
373
+ # NullsFirst is available on all but MySQL, where it is redefined.
374
+ def visit_Arel_Nodes_NullsFirst(o, collector)
375
+ visit o.expr, collector
376
+ collector << " NULLS FIRST"
377
+ end
378
+
379
+ def visit_Arel_Nodes_NullsLast(o, collector)
380
+ visit o.expr, collector
381
+ collector << " NULLS LAST"
382
+ end
383
+
341
384
  def visit_Arel_Nodes_Group(o, collector)
342
385
  visit o.expr, collector
343
386
  end
344
387
 
345
388
  def visit_Arel_Nodes_NamedFunction(o, collector)
389
+ collector.retryable = false
346
390
  collector << o.name
347
391
  collector << "("
348
392
  collector << "DISTINCT " if o.distinct
@@ -393,24 +437,48 @@ module Arel # :nodoc: all
393
437
  end
394
438
 
395
439
  def visit_Arel_Nodes_GreaterThanOrEqual(o, collector)
440
+ case unboundable?(o.right)
441
+ when 1
442
+ return collector << "1=0"
443
+ when -1
444
+ return collector << "1=1"
445
+ end
396
446
  collector = visit o.left, collector
397
447
  collector << " >= "
398
448
  visit o.right, collector
399
449
  end
400
450
 
401
451
  def visit_Arel_Nodes_GreaterThan(o, collector)
452
+ case unboundable?(o.right)
453
+ when 1
454
+ return collector << "1=0"
455
+ when -1
456
+ return collector << "1=1"
457
+ end
402
458
  collector = visit o.left, collector
403
459
  collector << " > "
404
460
  visit o.right, collector
405
461
  end
406
462
 
407
463
  def visit_Arel_Nodes_LessThanOrEqual(o, collector)
464
+ case unboundable?(o.right)
465
+ when 1
466
+ return collector << "1=1"
467
+ when -1
468
+ return collector << "1=0"
469
+ end
408
470
  collector = visit o.left, collector
409
471
  collector << " <= "
410
472
  visit o.right, collector
411
473
  end
412
474
 
413
475
  def visit_Arel_Nodes_LessThan(o, collector)
476
+ case unboundable?(o.right)
477
+ when 1
478
+ return collector << "1=1"
479
+ when -1
480
+ return collector << "1=0"
481
+ end
414
482
  collector = visit o.left, collector
415
483
  collector << " < "
416
484
  visit o.right, collector
@@ -506,72 +574,51 @@ module Arel # :nodoc: all
506
574
  end
507
575
 
508
576
  def visit_Arel_Table(o, collector)
509
- if o.table_alias
510
- collector << quote_table_name(o.name) << " " << quote_table_name(o.table_alias)
577
+ if Arel::Nodes::Node === o.name
578
+ visit o.name, collector
511
579
  else
512
580
  collector << quote_table_name(o.name)
513
581
  end
514
- end
515
582
 
516
- def visit_Arel_Nodes_In(o, collector)
517
- unless Array === o.right
518
- return collect_in_clause(o.left, o.right, collector)
583
+ if o.table_alias
584
+ collector << " " << quote_table_name(o.table_alias)
519
585
  end
520
586
 
521
- unless o.right.empty?
522
- o.right.delete_if { |value| unboundable?(value) }
523
- end
587
+ collector
588
+ end
524
589
 
525
- return collector << "1=0" if o.right.empty?
590
+ def visit_Arel_Nodes_In(o, collector)
591
+ attr, values = o.left, o.right
526
592
 
527
- in_clause_length = @connection.in_clause_length
593
+ if Array === values
594
+ collector.preparable = false
528
595
 
529
- if !in_clause_length || o.right.length <= in_clause_length
530
- collect_in_clause(o.left, o.right, collector)
531
- else
532
- collector << "("
533
- o.right.each_slice(in_clause_length).each_with_index do |right, i|
534
- collector << " OR " unless i == 0
535
- collect_in_clause(o.left, right, collector)
596
+ unless values.empty?
597
+ values.delete_if { |value| unboundable?(value) }
536
598
  end
537
- collector << ")"
599
+
600
+ return collector << "1=0" if values.empty?
538
601
  end
539
- end
540
602
 
541
- def collect_in_clause(left, right, collector)
542
- collector = visit left, collector
543
- collector << " IN ("
544
- visit(right, collector) << ")"
603
+ visit(attr, collector) << " IN ("
604
+ visit(values, collector) << ")"
545
605
  end
546
606
 
547
607
  def visit_Arel_Nodes_NotIn(o, collector)
548
- unless Array === o.right
549
- return collect_not_in_clause(o.left, o.right, collector)
550
- end
608
+ attr, values = o.left, o.right
551
609
 
552
- unless o.right.empty?
553
- o.right.delete_if { |value| unboundable?(value) }
554
- end
555
-
556
- return collector << "1=1" if o.right.empty?
557
-
558
- in_clause_length = @connection.in_clause_length
610
+ if Array === values
611
+ collector.preparable = false
559
612
 
560
- if !in_clause_length || o.right.length <= in_clause_length
561
- collect_not_in_clause(o.left, o.right, collector)
562
- else
563
- o.right.each_slice(in_clause_length).each_with_index do |right, i|
564
- collector << " AND " unless i == 0
565
- collect_not_in_clause(o.left, right, collector)
613
+ unless values.empty?
614
+ values.delete_if { |value| unboundable?(value) }
566
615
  end
567
- collector
616
+
617
+ return collector << "1=1" if values.empty?
568
618
  end
569
- end
570
619
 
571
- def collect_not_in_clause(left, right, collector)
572
- collector = visit left, collector
573
- collector << " NOT IN ("
574
- visit(right, collector) << ")"
620
+ visit(attr, collector) << " NOT IN ("
621
+ visit(values, collector) << ")"
575
622
  end
576
623
 
577
624
  def visit_Arel_Nodes_And(o, collector)
@@ -579,14 +626,12 @@ module Arel # :nodoc: all
579
626
  end
580
627
 
581
628
  def visit_Arel_Nodes_Or(o, collector)
582
- collector = visit o.left, collector
583
- collector << " OR "
584
- visit o.right, collector
629
+ inject_join o.children, collector, " OR "
585
630
  end
586
631
 
587
632
  def visit_Arel_Nodes_Assignment(o, collector)
588
633
  case o.right
589
- when Arel::Nodes::Node, Arel::Attributes::Attribute
634
+ when Arel::Nodes::Node, Arel::Attributes::Attribute, ActiveModel::Attribute
590
635
  collector = visit o.left, collector
591
636
  collector << " = "
592
637
  visit o.right, collector
@@ -686,32 +731,100 @@ module Arel # :nodoc: all
686
731
  collector << quote_column_name(o.name)
687
732
  end
688
733
 
734
+ def visit_Arel_Nodes_Cte(o, collector)
735
+ collector << quote_table_name(o.name)
736
+ collector << " AS "
737
+
738
+ case o.materialized
739
+ when true
740
+ collector << "MATERIALIZED "
741
+ when false
742
+ collector << "NOT MATERIALIZED "
743
+ end
744
+
745
+ visit o.relation, collector
746
+ end
747
+
689
748
  def visit_Arel_Attributes_Attribute(o, collector)
690
749
  join_name = o.relation.table_alias || o.relation.name
691
750
  collector << quote_table_name(join_name) << "." << quote_column_name(o.name)
692
751
  end
693
- alias :visit_Arel_Attributes_Integer :visit_Arel_Attributes_Attribute
694
- alias :visit_Arel_Attributes_Float :visit_Arel_Attributes_Attribute
695
- alias :visit_Arel_Attributes_Decimal :visit_Arel_Attributes_Attribute
696
- alias :visit_Arel_Attributes_String :visit_Arel_Attributes_Attribute
697
- alias :visit_Arel_Attributes_Time :visit_Arel_Attributes_Attribute
698
- alias :visit_Arel_Attributes_Boolean :visit_Arel_Attributes_Attribute
699
752
 
700
- def literal(o, collector); collector << o.to_s; end
753
+ BIND_BLOCK = proc { "?" }
754
+ private_constant :BIND_BLOCK
755
+
756
+ def bind_block; BIND_BLOCK; end
757
+
758
+ def visit_ActiveModel_Attribute(o, collector)
759
+ collector.add_bind(o, &bind_block)
760
+ end
701
761
 
702
762
  def visit_Arel_Nodes_BindParam(o, collector)
703
- collector.add_bind(o.value) { "?" }
763
+ collector.add_bind(o.value, &bind_block)
704
764
  end
705
765
 
706
- alias :visit_Arel_Nodes_SqlLiteral :literal
707
- alias :visit_Integer :literal
766
+ def visit_Arel_Nodes_SqlLiteral(o, collector)
767
+ collector.preparable = false
768
+ collector.retryable &&= o.retryable
769
+ collector << o.to_s
770
+ end
771
+
772
+ def visit_Arel_Nodes_BoundSqlLiteral(o, collector)
773
+ collector.retryable = false
774
+ bind_index = 0
775
+
776
+ new_bind = lambda do |value|
777
+ if Arel.arel_node?(value)
778
+ visit value, collector
779
+ elsif value.is_a?(Array)
780
+ if value.empty?
781
+ collector << @connection.quote(nil)
782
+ else
783
+ if value.none? { |v| Arel.arel_node?(v) }
784
+ collector.add_binds(value.map { |v| @connection.cast_bound_value(v) }, &bind_block)
785
+ else
786
+ value.each_with_index do |v, i|
787
+ collector << ", " unless i == 0
788
+ if Arel.arel_node?(v)
789
+ visit v, collector
790
+ else
791
+ collector.add_bind(@connection.cast_bound_value(v), &bind_block)
792
+ end
793
+ end
794
+ end
795
+ end
796
+ else
797
+ collector.add_bind(@connection.cast_bound_value(value), &bind_block)
798
+ end
799
+ end
708
800
 
709
- def quoted(o, a)
710
- if a && a.able_to_type_cast?
711
- quote(a.type_cast_for_database(o))
801
+ if o.positional_binds
802
+ o.sql_with_placeholders.scan(/\?|([^?]+)/) do
803
+ if $1
804
+ collector << $1
805
+ else
806
+ value = o.positional_binds[bind_index]
807
+ bind_index += 1
808
+
809
+ new_bind.call(value)
810
+ end
811
+ end
712
812
  else
713
- quote(o)
813
+ o.sql_with_placeholders.scan(/:(?<!::)([a-zA-Z]\w*)|([^:]+|.)/) do
814
+ if $2
815
+ collector << $2
816
+ else
817
+ value = o.named_binds[$1.to_sym]
818
+ new_bind.call(value)
819
+ end
820
+ end
714
821
  end
822
+
823
+ collector
824
+ end
825
+
826
+ def visit_Integer(o, collector)
827
+ collector << o.to_s
715
828
  end
716
829
 
717
830
  def unsupported(o, collector)
@@ -739,11 +852,6 @@ module Arel # :nodoc: all
739
852
  visit o.right, collector
740
853
  end
741
854
 
742
- alias :visit_Arel_Nodes_Addition :visit_Arel_Nodes_InfixOperation
743
- alias :visit_Arel_Nodes_Subtraction :visit_Arel_Nodes_InfixOperation
744
- alias :visit_Arel_Nodes_Multiplication :visit_Arel_Nodes_InfixOperation
745
- alias :visit_Arel_Nodes_Division :visit_Arel_Nodes_InfixOperation
746
-
747
855
  def visit_Arel_Nodes_UnaryOperation(o, collector)
748
856
  collector << " #{o.operator} "
749
857
  visit o.expr, collector
@@ -754,6 +862,10 @@ module Arel # :nodoc: all
754
862
  end
755
863
  alias :visit_Set :visit_Array
756
864
 
865
+ def visit_Arel_Nodes_Fragments(o, collector)
866
+ inject_join o.values, collector, " "
867
+ end
868
+
757
869
  def quote(value)
758
870
  return value if Arel::Nodes::SqlLiteral === value
759
871
  @connection.quote value
@@ -804,6 +916,10 @@ module Arel # :nodoc: all
804
916
  o.limit || o.offset || !o.orders.empty?
805
917
  end
806
918
 
919
+ def has_group_by_and_having?(o)
920
+ !o.groups.empty? && !o.havings.empty?
921
+ end
922
+
807
923
  # The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
808
924
  # on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
809
925
  # an UPDATE statement, so in the MySQL visitor we redefine this to do that.
@@ -813,8 +929,11 @@ module Arel # :nodoc: all
813
929
  stmt.limit = nil
814
930
  stmt.offset = nil
815
931
  stmt.orders = []
816
- stmt.wheres = [Nodes::In.new(o.key, [build_subselect(o.key, o)])]
932
+ columns = Arel::Nodes::Grouping.new(o.key)
933
+ stmt.wheres = [Nodes::In.new(columns, [build_subselect(o.key, o)])]
817
934
  stmt.relation = o.relation.left if has_join_sources?(o)
935
+ stmt.groups = o.groups unless o.groups.empty?
936
+ stmt.havings = o.havings unless o.havings.empty?
818
937
  stmt
819
938
  else
820
939
  o
@@ -829,6 +948,8 @@ module Arel # :nodoc: all
829
948
  core.froms = o.relation
830
949
  core.wheres = o.wheres
831
950
  core.projections = [key]
951
+ core.groups = o.groups unless o.groups.empty?
952
+ core.havings = o.havings unless o.havings.empty?
832
953
  stmt.limit = o.limit
833
954
  stmt.offset = o.offset
834
955
  stmt.orders = o.orders
@@ -846,18 +967,34 @@ module Arel # :nodoc: all
846
967
  collector = if o.left.class == o.class
847
968
  infix_value_with_paren(o.left, collector, value, true)
848
969
  else
849
- visit o.left, collector
970
+ grouping_parentheses o.left, collector, false
850
971
  end
851
972
  collector << value
852
973
  collector = if o.right.class == o.class
853
974
  infix_value_with_paren(o.right, collector, value, true)
854
975
  else
855
- visit o.right, collector
976
+ grouping_parentheses o.right, collector, false
856
977
  end
857
978
  collector << " )" unless suppress_parens
858
979
  collector
859
980
  end
860
981
 
982
+ # Used by some visitors to enclose select queries in parentheses
983
+ def grouping_parentheses(o, collector, always_wrap_selects = true)
984
+ if o.is_a?(Nodes::SelectStatement) && (always_wrap_selects || require_parentheses?(o))
985
+ collector << "("
986
+ visit o, collector
987
+ collector << ")"
988
+ collector
989
+ else
990
+ visit o, collector
991
+ end
992
+ end
993
+
994
+ def require_parentheses?(o)
995
+ !o.orders.empty? || o.limit || o.offset
996
+ end
997
+
861
998
  def aggregate(name, o, collector)
862
999
  collector << "#{name}("
863
1000
  if o.distinct
@@ -884,6 +1021,15 @@ module Arel # :nodoc: all
884
1021
  collector << " IS NULL)"
885
1022
  collector << " THEN 0 ELSE 1 END"
886
1023
  end
1024
+
1025
+ def collect_ctes(children, collector)
1026
+ children.each_with_index do |child, i|
1027
+ collector << ", " unless i == 0
1028
+ visit child.to_cte, collector
1029
+ end
1030
+
1031
+ collector
1032
+ end
887
1033
  end
888
1034
  end
889
1035
  end
@@ -12,13 +12,12 @@ module Arel # :nodoc: all
12
12
  end
13
13
 
14
14
  private
15
-
16
15
  attr_reader :dispatch
17
16
 
18
17
  def self.dispatch_cache
19
18
  @dispatch_cache ||= Hash.new do |hash, klass|
20
- hash[klass] = "visit_#{(klass.name || '').gsub('::', '_')}"
21
- end
19
+ hash[klass] = :"visit_#{(klass.name || "").gsub("::", "_")}"
20
+ end.compare_by_identity
22
21
  end
23
22
 
24
23
  def get_dispatch_cache
data/lib/arel/visitors.rb CHANGED
@@ -1,18 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "arel/visitors/visitor"
4
- require "arel/visitors/depth_first"
5
4
  require "arel/visitors/to_sql"
6
5
  require "arel/visitors/sqlite"
7
6
  require "arel/visitors/postgresql"
8
7
  require "arel/visitors/mysql"
9
- require "arel/visitors/mssql"
10
- require "arel/visitors/oracle"
11
- require "arel/visitors/oracle12"
12
- require "arel/visitors/where_sql"
13
8
  require "arel/visitors/dot"
14
- require "arel/visitors/ibm_db"
15
- require "arel/visitors/informix"
16
9
 
17
10
  module Arel # :nodoc: all
18
11
  module Visitors
data/lib/arel.rb CHANGED
@@ -7,12 +7,13 @@ require "arel/factory_methods"
7
7
 
8
8
  require "arel/expressions"
9
9
  require "arel/predications"
10
+ require "arel/filter_predications"
10
11
  require "arel/window_predications"
11
12
  require "arel/math"
12
13
  require "arel/alias_predication"
13
14
  require "arel/order_predications"
14
15
  require "arel/table"
15
- require "arel/attributes"
16
+ require "arel/attributes/attribute"
16
17
 
17
18
  require "arel/visitors"
18
19
  require "arel/collectors/sql_string"
@@ -24,28 +25,49 @@ require "arel/update_manager"
24
25
  require "arel/delete_manager"
25
26
  require "arel/nodes"
26
27
 
27
- module Arel # :nodoc: all
28
+ module Arel
28
29
  VERSION = "10.0.0"
29
30
 
30
- def self.sql(raw_sql)
31
- Arel::Nodes::SqlLiteral.new raw_sql
31
+ # Wrap a known-safe SQL string for passing to query methods, e.g.
32
+ #
33
+ # Post.order(Arel.sql("REPLACE(title, 'misc', 'zzzz') asc")).pluck(:id)
34
+ #
35
+ # Great caution should be taken to avoid SQL injection vulnerabilities.
36
+ # This method should not be used with unsafe values such as request
37
+ # parameters or model attributes.
38
+ #
39
+ # Take a look at the {security guide}[https://guides.rubyonrails.org/security.html#sql-injection]
40
+ # for more information.
41
+ #
42
+ # To construct a more complex query fragment, including the possible
43
+ # use of user-provided values, the +sql_string+ may contain <tt>?</tt> and
44
+ # +:key+ placeholders, corresponding to the additional arguments. Note
45
+ # that this behavior only applies when bind value parameters are
46
+ # supplied in the call; without them, the placeholder tokens have no
47
+ # special meaning, and will be passed through to the query as-is.
48
+ #
49
+ # The +:retryable+ option can be used to mark the SQL as safe to retry.
50
+ # Use this option only if the SQL is idempotent, as it could be executed
51
+ # more than once.
52
+ def self.sql(sql_string, *positional_binds, retryable: false, **named_binds)
53
+ if positional_binds.empty? && named_binds.empty?
54
+ Arel::Nodes::SqlLiteral.new(sql_string, retryable: retryable)
55
+ else
56
+ Arel::Nodes::BoundSqlLiteral.new sql_string, positional_binds, named_binds
57
+ end
32
58
  end
33
59
 
34
- def self.star
35
- sql "*"
60
+ def self.star # :nodoc:
61
+ sql("*", retryable: true)
36
62
  end
37
63
 
38
- def self.arel_node?(value)
39
- value.is_a?(Arel::Node) || value.is_a?(Arel::Attribute) || value.is_a?(Arel::Nodes::SqlLiteral)
64
+ def self.arel_node?(value) # :nodoc:
65
+ value.is_a?(Arel::Nodes::Node) || value.is_a?(Arel::Attribute) || value.is_a?(Arel::Nodes::SqlLiteral)
40
66
  end
41
67
 
42
- def self.fetch_attribute(value)
43
- case value
44
- when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
45
- yield value.left.is_a?(Arel::Attributes::Attribute) ? value.left : value.right
68
+ def self.fetch_attribute(value, &block) # :nodoc:
69
+ unless String === value
70
+ value.fetch_attribute(&block)
46
71
  end
47
72
  end
48
-
49
- ## Convenience Alias
50
- Node = Arel::Nodes::Node
51
73
  end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Generates an `ApplicationRecord` base class for other models to inherit from.
3
+
4
+ Example:
5
+ `bin/rails generate application_record`
6
+
7
+ This generates the base class. A test is not generated because no
8
+ behaviour is included in `ApplicationRecord` by default.
@@ -13,7 +13,6 @@ module ActiveRecord
13
13
  end
14
14
 
15
15
  private
16
-
17
16
  def application_record_file_name
18
17
  @application_record_file_name ||=
19
18
  if namespaced?
@@ -1,5 +1,5 @@
1
1
  <% module_namespacing do -%>
2
2
  class ApplicationRecord < ActiveRecord::Base
3
- self.abstract_class = true
3
+ primary_abstract_class
4
4
  end
5
5
  <% end -%>
@@ -7,6 +7,7 @@ module ActiveRecord
7
7
  class MigrationGenerator < Base # :nodoc:
8
8
  argument :attributes, type: :array, default: [], banner: "field[:type][:index] field[:type][:index]"
9
9
 
10
+ class_option :timestamps, type: :boolean
10
11
  class_option :primary_key_type, type: :string, desc: "The type for primary key"
11
12
  class_option :database, type: :string, aliases: %i(--db), desc: "The database for your migration. By default, the current environment's primary database is used."
12
13