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
data/lib/arel/nodes/in.rb CHANGED
@@ -2,7 +2,14 @@
2
2
 
3
3
  module Arel # :nodoc: all
4
4
  module Nodes
5
- class In < Equality
5
+ class In < Arel::Nodes::Binary
6
+ include FetchAttribute
7
+
8
+ def equality?; true; end
9
+
10
+ def invert
11
+ Arel::Nodes::NotIn.new(left, right)
12
+ end
6
13
  end
7
14
  end
8
15
  end
@@ -43,7 +43,19 @@ module Arel # :nodoc: all
43
43
 
44
44
  class Concat < InfixOperation
45
45
  def initialize(left, right)
46
- super("||", left, right)
46
+ super(:"||", left, right)
47
+ end
48
+ end
49
+
50
+ class Contains < InfixOperation
51
+ def initialize(left, right)
52
+ super(:"@>", left, right)
53
+ end
54
+ end
55
+
56
+ class Overlaps < InfixOperation
57
+ def initialize(left, right)
58
+ super(:"&&", left, right)
47
59
  end
48
60
  end
49
61
 
@@ -5,9 +5,9 @@ module Arel # :nodoc: all
5
5
  class InsertStatement < Arel::Nodes::Node
6
6
  attr_accessor :relation, :columns, :values, :select
7
7
 
8
- def initialize
8
+ def initialize(relation = nil)
9
9
  super()
10
- @relation = nil
10
+ @relation = relation
11
11
  @columns = []
12
12
  @values = nil
13
13
  @select = nil
@@ -5,7 +5,7 @@ module Arel # :nodoc: all
5
5
  ###
6
6
  # Class that represents a join source
7
7
  #
8
- # http://www.sqlite.org/syntaxdiagrams.html#join-source
8
+ # https://www.sqlite.org/syntaxdiagrams.html#join-source
9
9
 
10
10
  class JoinSource < Arel::Nodes::Binary
11
11
  def initialize(single_source, joinop = [])
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arel # :nodoc: all
4
+ module Nodes
5
+ class LeadingJoin < Arel::Nodes::InnerJoin
6
+ end
7
+ end
8
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Arel # :nodoc: all
4
4
  module Nodes
5
- class And < Arel::Nodes::NodeExpression
5
+ class Nary < Arel::Nodes::NodeExpression
6
6
  attr_reader :children
7
7
 
8
8
  def initialize(children)
@@ -18,8 +18,12 @@ module Arel # :nodoc: all
18
18
  children[1]
19
19
  end
20
20
 
21
+ def fetch_attribute(&block)
22
+ children.any? && children.all? { |child| child.fetch_attribute(&block) }
23
+ end
24
+
21
25
  def hash
22
- children.hash
26
+ [self.class, children].hash
23
27
  end
24
28
 
25
29
  def eql?(other)
@@ -28,5 +32,8 @@ module Arel # :nodoc: all
28
32
  end
29
33
  alias :== :eql?
30
34
  end
35
+
36
+ And = Class.new(Nary)
37
+ Or = Class.new(Nary)
31
38
  end
32
39
  end
@@ -2,11 +2,119 @@
2
2
 
3
3
  module Arel # :nodoc: all
4
4
  module Nodes
5
- ###
6
- # Abstract base class for all AST nodes
5
+ # = Using +Arel::Nodes::Node+
6
+ #
7
+ # Active Record uses Arel to compose SQL statements. Instead of building SQL strings directly, it's building an
8
+ # abstract syntax tree (AST) of the statement using various types of Arel::Nodes::Node. Each node represents a
9
+ # fragment of a SQL statement.
10
+ #
11
+ # The intermediate representation allows Arel to compile the statement into the database's specific SQL dialect
12
+ # only before sending it without having to care about the nuances of each database when building the statement.
13
+ # It also allows easier composition of statements without having to resort to (brittle and unsafe) string manipulation.
14
+ #
15
+ # == Building constraints
16
+ #
17
+ # One of the most common use cases of Arel is generating constraints for +SELECT+ statements. To help with that,
18
+ # most nodes include a couple of useful factory methods to create subtree structures for common constraints. For
19
+ # a full list of those, please refer to Arel::Predications.
20
+ #
21
+ # The following example creates an equality constraint where the value of the name column on the users table
22
+ # matches the value DHH.
23
+ #
24
+ # users = Arel::Table.new(:users)
25
+ # constraint = users[:name].eq("DHH")
26
+ #
27
+ # # => Arel::Nodes::Equality.new(
28
+ # # Arel::Attributes::Attribute.new(users, "name"),
29
+ # # Arel::Nodes::Casted.new(
30
+ # # "DHH",
31
+ # # Arel::Attributes::Attribute.new(users, "name")
32
+ # # )
33
+ # # )
34
+ #
35
+ # The resulting SQL fragment will look like this:
36
+ #
37
+ # "users"."name" = 'DHH'
38
+ #
39
+ # The constraint fragments can be used with regular ActiveRecord::Relation objects instead of a Hash. The
40
+ # following two examples show two ways of creating the same query.
41
+ #
42
+ # User.where(name: 'DHH')
43
+ #
44
+ # # SELECT "users".* FROM "users" WHERE "users"."name" = 'DHH'
45
+ #
46
+ # users = User.arel_table
47
+ #
48
+ # User.where(users[:name].eq('DHH'))
49
+ #
50
+ # # SELECT "users".* FROM "users" WHERE "users"."name" = 'DHH'
51
+ #
52
+ # == Functions
53
+ #
54
+ # Arel comes with built-in support for SQL functions like +COUNT+, +SUM+, +MIN+, +MAX+, and +AVG+. The
55
+ # Arel::Expressions module includes factory methods for the default functions.
56
+ #
57
+ # employees = Employee.arel_table
58
+ #
59
+ # Employee.select(employees[:department_id], employees[:salary].average).group(employees[:department_id])
60
+ #
61
+ # # SELECT "employees"."department_id", AVG("employees"."salary")
62
+ # # FROM "employees" GROUP BY "employees"."department_id"
63
+ #
64
+ # It’s also possible to use custom functions by using the Arel::Nodes::NamedFunction node type. It accepts a
65
+ # function name and an array of parameters.
66
+ #
67
+ # Arel::Nodes::NamedFunction.new('date_trunc', [Arel::Nodes.build_quoted('day'), User.arel_table[:created_at]])
68
+ #
69
+ # # date_trunc('day', "users"."created_at")
70
+ #
71
+ # == Quoting & bind params
72
+ #
73
+ # Values that you pass to Arel nodes need to be quoted or wrapped in bind params. This ensures they are properly
74
+ # converted into the correct format without introducing a possible SQL injection vulnerability. Most factory
75
+ # methods (like +eq+, +gt+, +lteq+, …) quote passed values automatically. When not using a factory method, it’s
76
+ # possible to convert a value and wrap it in an Arel::Nodes::Quoted node (if necessary) by calling +Arel::Nodes.
77
+ # build_quoted+.
78
+ #
79
+ # Arel::Nodes.build_quoted("foo") # 'foo'
80
+ # Arel::Nodes.build_quoted(12.3) # 12.3
81
+ #
82
+ # Instead of quoting values and embedding them directly in the SQL statement, it’s also possible to create bind
83
+ # params. This keeps the actual values outside of the statement and allows using the prepared statement feature
84
+ # of some databases.
85
+ #
86
+ # attribute = ActiveRecord::Relation::QueryAttribute.new(:name, "DHH", ActiveRecord::Type::String.new)
87
+ # Arel::Nodes::BindParam.new(attribute)
88
+ #
89
+ # When ActiveRecord runs the query, bind params are replaced by placeholders (like +$1+) and the values are passed
90
+ # separately.
91
+ #
92
+ # == SQL Literals
93
+ #
94
+ # For cases where there is no way to represent a particular SQL fragment using Arel nodes, you can use an SQL
95
+ # literal. SQL literals are strings that Arel will treat “as is”.
96
+ #
97
+ # Arel.sql('LOWER("users"."name")').eq('dhh')
98
+ #
99
+ # # LOWER("users"."name") = 'dhh'
100
+ #
101
+ # Please keep in mind that passing data as raw SQL literals might introduce a possible SQL injection. However,
102
+ # `Arel.sql` supports binding parameters which will ensure proper quoting. This can be useful when you need to
103
+ # control the exact SQL you run, but you still have potentially user-supplied values.
104
+ #
105
+ # Arel.sql('LOWER("users"."name") = ?', 'dhh')
106
+ #
107
+ # # LOWER("users"."name") = 'dhh'
108
+ #
109
+ # You can also combine SQL literals.
110
+ #
111
+ # sql = Arel.sql('SELECT * FROM "users" WHERE ')
112
+ # sql += Arel.sql('LOWER("users"."name") = :name', name: 'dhh')
113
+ # sql += Arel.sql('AND "users"."age" > :age', age: 35)
114
+ #
115
+ # # SELECT * FROM "users" WHERE LOWER("users"."name") = 'dhh' AND "users"."age" > '35'
7
116
  class Node
8
117
  include Arel::FactoryMethods
9
- include Enumerable
10
118
 
11
119
  ###
12
120
  # Factory method to create a Nodes::Not node that has the recipient of
@@ -19,7 +127,7 @@ module Arel # :nodoc: all
19
127
  # Factory method to create a Nodes::Grouping node that has an Nodes::Or
20
128
  # node as a child.
21
129
  def or(right)
22
- Nodes::Grouping.new Nodes::Or.new(self, right)
130
+ Nodes::Grouping.new Nodes::Or.new([self, right])
23
131
  end
24
132
 
25
133
  ###
@@ -28,6 +136,10 @@ module Arel # :nodoc: all
28
136
  Nodes::And.new [self, right]
29
137
  end
30
138
 
139
+ def invert
140
+ Arel::Nodes::Not.new(self)
141
+ end
142
+
31
143
  # FIXME: this method should go away. I don't like people calling
32
144
  # to_sql on non-head nodes. This forces us to walk the AST until we
33
145
  # can find a node that has a "relation" member.
@@ -35,16 +147,15 @@ module Arel # :nodoc: all
35
147
  # Maybe we should just use `Table.engine`? :'(
36
148
  def to_sql(engine = Table.engine)
37
149
  collector = Arel::Collectors::SQLString.new
38
- collector = engine.connection.visitor.accept self, collector
39
- collector.value
150
+ engine.with_connection do |connection|
151
+ connection.visitor.accept(self, collector).value
152
+ end
40
153
  end
41
154
 
42
- # Iterate through AST, nodes will be yielded depth-first
43
- def each(&block)
44
- return enum_for(:each) unless block_given?
45
-
46
- ::Arel::Visitors::DepthFirst.new(block).accept self
155
+ def fetch_attribute
47
156
  end
157
+
158
+ def equality?; false; end
48
159
  end
49
160
  end
50
161
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arel # :nodoc: all
4
+ module Nodes
5
+ class Ordering < Unary
6
+ def nulls_first
7
+ NullsFirst.new(self)
8
+ end
9
+
10
+ def nulls_last
11
+ NullsLast.new(self)
12
+ end
13
+ end
14
+
15
+ class NullsFirst < Ordering
16
+ def reverse
17
+ NullsLast.new(expr.reverse)
18
+ end
19
+ end
20
+
21
+ class NullsLast < Ordering
22
+ def reverse
23
+ NullsFirst.new(expr.reverse)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -6,9 +6,9 @@ module Arel # :nodoc: all
6
6
  attr_accessor :projections, :wheres, :groups, :windows, :comment
7
7
  attr_accessor :havings, :source, :set_quantifier, :optimizer_hints
8
8
 
9
- def initialize
9
+ def initialize(relation = nil)
10
10
  super()
11
- @source = JoinSource.new nil
11
+ @source = JoinSource.new(relation)
12
12
 
13
13
  # https://ronsavage.github.io/SQL/sql-92.bnf.html#set%20quantifier
14
14
  @set_quantifier = nil
@@ -6,9 +6,9 @@ module Arel # :nodoc: all
6
6
  attr_reader :cores
7
7
  attr_accessor :limit, :orders, :lock, :offset, :with
8
8
 
9
- def initialize(cores = [SelectCore.new])
9
+ def initialize(relation = nil)
10
10
  super()
11
- @cores = cores
11
+ @cores = [SelectCore.new(relation)]
12
12
  @orders = []
13
13
  @limit = nil
14
14
  @lock = nil
@@ -8,9 +8,25 @@ module Arel # :nodoc: all
8
8
  include Arel::AliasPredication
9
9
  include Arel::OrderPredications
10
10
 
11
+ attr_reader :retryable
12
+
13
+ def initialize(string, retryable: false)
14
+ @retryable = retryable
15
+ super(string)
16
+ end
17
+
11
18
  def encode_with(coder)
12
19
  coder.scalar = self.to_s
13
20
  end
21
+
22
+ def fetch_attribute
23
+ end
24
+
25
+ def +(other)
26
+ raise ArgumentError, "Expected Arel node" unless Arel.arel_node?(other)
27
+
28
+ Fragments.new([self, other])
29
+ end
14
30
  end
15
31
  end
16
32
  end
@@ -8,20 +8,28 @@ module Arel # :nodoc: all
8
8
  alias :table_alias :name
9
9
 
10
10
  def [](name)
11
- Attribute.new(self, name)
11
+ relation.is_a?(Table) ? relation[name, self] : Attribute.new(self, name)
12
12
  end
13
13
 
14
14
  def table_name
15
15
  relation.respond_to?(:name) ? relation.name : name
16
16
  end
17
17
 
18
- def type_cast_for_database(*args)
19
- relation.type_cast_for_database(*args)
18
+ def type_cast_for_database(attr_name, value)
19
+ relation.type_cast_for_database(attr_name, value)
20
+ end
21
+
22
+ def type_for_attribute(name)
23
+ relation.type_for_attribute(name)
20
24
  end
21
25
 
22
26
  def able_to_type_cast?
23
27
  relation.respond_to?(:able_to_type_cast?) && relation.able_to_type_cast?
24
28
  end
29
+
30
+ def to_cte
31
+ Arel::Nodes::Cte.new(name, relation)
32
+ end
25
33
  end
26
34
  end
27
35
  end
@@ -36,7 +36,6 @@ module Arel # :nodoc: all
36
36
  Offset
37
37
  On
38
38
  OptimizerHints
39
- Ordering
40
39
  RollUp
41
40
  }.each do |name|
42
41
  const_set(name, Class.new(Unary))
@@ -3,15 +3,19 @@
3
3
  module Arel # :nodoc: all
4
4
  module Nodes
5
5
  class UpdateStatement < Arel::Nodes::Node
6
- attr_accessor :relation, :wheres, :values, :orders, :limit, :offset, :key
6
+ attr_accessor :relation, :wheres, :values, :groups, :havings, :orders, :limit, :offset, :comment, :key
7
7
 
8
- def initialize
9
- @relation = nil
8
+ def initialize(relation = nil)
9
+ super()
10
+ @relation = relation
10
11
  @wheres = []
11
12
  @values = []
13
+ @groups = []
14
+ @havings = []
12
15
  @orders = []
13
16
  @limit = nil
14
17
  @offset = nil
18
+ @comment = nil
15
19
  @key = nil
16
20
  end
17
21
 
@@ -22,7 +26,7 @@ module Arel # :nodoc: all
22
26
  end
23
27
 
24
28
  def hash
25
- [@relation, @wheres, @values, @orders, @limit, @offset, @key].hash
29
+ [@relation, @wheres, @values, @orders, @limit, @offset, @comment, @key].hash
26
30
  end
27
31
 
28
32
  def eql?(other)
@@ -30,9 +34,12 @@ module Arel # :nodoc: all
30
34
  self.relation == other.relation &&
31
35
  self.wheres == other.wheres &&
32
36
  self.values == other.values &&
37
+ self.groups == other.groups &&
38
+ self.havings == other.havings &&
33
39
  self.orders == other.orders &&
34
40
  self.limit == other.limit &&
35
41
  self.offset == other.offset &&
42
+ self.comment == other.comment &&
36
43
  self.key == other.key
37
44
  end
38
45
  alias :== :eql?
data/lib/arel/nodes.rb CHANGED
@@ -8,6 +8,7 @@ require "arel/nodes/select_core"
8
8
  require "arel/nodes/insert_statement"
9
9
  require "arel/nodes/update_statement"
10
10
  require "arel/nodes/bind_param"
11
+ require "arel/nodes/fragments"
11
12
 
12
13
  # terminal
13
14
 
@@ -18,6 +19,8 @@ require "arel/nodes/false"
18
19
  # unary
19
20
  require "arel/nodes/unary"
20
21
  require "arel/nodes/grouping"
22
+ require "arel/nodes/homogeneous_in"
23
+ require "arel/nodes/ordering"
21
24
  require "arel/nodes/ascending"
22
25
  require "arel/nodes/descending"
23
26
  require "arel/nodes/unqualified_column"
@@ -26,7 +29,8 @@ require "arel/nodes/with"
26
29
  # binary
27
30
  require "arel/nodes/binary"
28
31
  require "arel/nodes/equality"
29
- require "arel/nodes/in" # Why is this subclassed from equality?
32
+ require "arel/nodes/filter"
33
+ require "arel/nodes/in"
30
34
  require "arel/nodes/join_source"
31
35
  require "arel/nodes/delete_statement"
32
36
  require "arel/nodes/table_alias"
@@ -35,9 +39,10 @@ require "arel/nodes/unary_operation"
35
39
  require "arel/nodes/over"
36
40
  require "arel/nodes/matches"
37
41
  require "arel/nodes/regexp"
42
+ require "arel/nodes/cte"
38
43
 
39
- # nary
40
- require "arel/nodes/and"
44
+ # nary (And and Or)
45
+ require "arel/nodes/nary"
41
46
 
42
47
  # function
43
48
  # FIXME: Function + Alias can be rewritten as a Function and Alias node.
@@ -60,9 +65,11 @@ require "arel/nodes/inner_join"
60
65
  require "arel/nodes/outer_join"
61
66
  require "arel/nodes/right_outer_join"
62
67
  require "arel/nodes/string_join"
68
+ require "arel/nodes/leading_join"
63
69
 
64
70
  require "arel/nodes/comment"
65
71
 
66
72
  require "arel/nodes/sql_literal"
73
+ require "arel/nodes/bound_sql_literal"
67
74
 
68
75
  require "arel/nodes/casted"
@@ -38,21 +38,27 @@ module Arel # :nodoc: all
38
38
  if unboundable?(other.begin) == 1 || unboundable?(other.end) == -1
39
39
  self.in([])
40
40
  elsif open_ended?(other.begin)
41
- if other.end.nil? || open_ended?(other.end)
42
- not_in([])
41
+ if open_ended?(other.end)
42
+ if infinity?(other.begin) == 1 || infinity?(other.end) == -1
43
+ self.in([])
44
+ else
45
+ not_in([])
46
+ end
43
47
  elsif other.exclude_end?
44
48
  lt(other.end)
45
49
  else
46
50
  lteq(other.end)
47
51
  end
48
- elsif other.end.nil? || open_ended?(other.end)
52
+ elsif open_ended?(other.end)
49
53
  gteq(other.begin)
50
54
  elsif other.exclude_end?
51
55
  gteq(other.begin).and(lt(other.end))
56
+ elsif other.begin == other.end
57
+ eq(other.begin)
52
58
  else
53
59
  left = quoted_node(other.begin)
54
60
  right = quoted_node(other.end)
55
- Nodes::Between.new(self, left.and(right))
61
+ Nodes::Between.new(self, Nodes::And.new([left, right]))
56
62
  end
57
63
  end
58
64
 
@@ -60,13 +66,6 @@ module Arel # :nodoc: all
60
66
  case other
61
67
  when Arel::SelectManager
62
68
  Arel::Nodes::In.new(self, other.ast)
63
- when Range
64
- if $VERBOSE
65
- warn <<-eowarn
66
- Passing a range to `#in` is deprecated. Call `#between`, instead.
67
- eowarn
68
- end
69
- between(other)
70
69
  when Enumerable
71
70
  Nodes::In.new self, quoted_array(other)
72
71
  else
@@ -86,14 +85,18 @@ Passing a range to `#in` is deprecated. Call `#between`, instead.
86
85
  if unboundable?(other.begin) == 1 || unboundable?(other.end) == -1
87
86
  not_in([])
88
87
  elsif open_ended?(other.begin)
89
- if other.end.nil? || open_ended?(other.end)
90
- self.in([])
88
+ if open_ended?(other.end)
89
+ if infinity?(other.begin) == 1 || infinity?(other.end) == -1
90
+ not_in([])
91
+ else
92
+ self.in([])
93
+ end
91
94
  elsif other.exclude_end?
92
95
  gteq(other.end)
93
96
  else
94
97
  gt(other.end)
95
98
  end
96
- elsif other.end.nil? || open_ended?(other.end)
99
+ elsif open_ended?(other.end)
97
100
  lt(other.begin)
98
101
  else
99
102
  left = lt(other.begin)
@@ -110,13 +113,6 @@ Passing a range to `#in` is deprecated. Call `#between`, instead.
110
113
  case other
111
114
  when Arel::SelectManager
112
115
  Arel::Nodes::NotIn.new(self, other.ast)
113
- when Range
114
- if $VERBOSE
115
- warn <<-eowarn
116
- Passing a range to `#not_in` is deprecated. Call `#not_between`, instead.
117
- eowarn
118
- end
119
- not_between(other)
120
116
  when Enumerable
121
117
  Nodes::NotIn.new self, quoted_array(other)
122
118
  else
@@ -220,12 +216,23 @@ Passing a range to `#not_in` is deprecated. Call `#not_between`, instead.
220
216
  Nodes::Concat.new self, other
221
217
  end
222
218
 
223
- private
219
+ def contains(other)
220
+ Arel::Nodes::Contains.new self, quoted_node(other)
221
+ end
222
+
223
+ def overlaps(other)
224
+ Arel::Nodes::Overlaps.new self, quoted_node(other)
225
+ end
224
226
 
227
+ def quoted_array(others)
228
+ others.map { |v| quoted_node(v) }
229
+ end
230
+
231
+ private
225
232
  def grouping_any(method_id, others, *extras)
226
233
  nodes = others.map { |expr| send(method_id, expr, *extras) }
227
234
  Nodes::Grouping.new nodes.inject { |memo, node|
228
- Nodes::Or.new(memo, node)
235
+ Nodes::Or.new([memo, node])
229
236
  }
230
237
  end
231
238
 
@@ -238,10 +245,6 @@ Passing a range to `#not_in` is deprecated. Call `#not_between`, instead.
238
245
  Nodes.build_quoted(other, self)
239
246
  end
240
247
 
241
- def quoted_array(others)
242
- others.map { |v| quoted_node(v) }
243
- end
244
-
245
248
  def infinity?(value)
246
249
  value.respond_to?(:infinite?) && value.infinite?
247
250
  end
@@ -251,7 +254,7 @@ Passing a range to `#not_in` is deprecated. Call `#not_between`, instead.
251
254
  end
252
255
 
253
256
  def open_ended?(value)
254
- infinity?(value) || unboundable?(value)
257
+ value.nil? || infinity?(value) || unboundable?(value)
255
258
  end
256
259
  end
257
260
  end
@@ -7,10 +7,8 @@ module Arel # :nodoc: all
7
7
  STRING_OR_SYMBOL_CLASS = [Symbol, String]
8
8
 
9
9
  def initialize(table = nil)
10
- super()
11
- @ast = Nodes::SelectStatement.new
10
+ @ast = Nodes::SelectStatement.new(table)
12
11
  @ctx = @ast.cores.last
13
- from table
14
12
  end
15
13
 
16
14
  def initialize_copy(other)
@@ -48,7 +46,7 @@ module Arel # :nodoc: all
48
46
  end
49
47
 
50
48
  def as(other)
51
- create_table_alias grouping(@ast), Nodes::SqlLiteral.new(other)
49
+ create_table_alias grouping(@ast), Nodes::SqlLiteral.new(other, retryable: true)
52
50
  end
53
51
 
54
52
  def lock(locking = Arel.sql("FOR UPDATE"))
@@ -98,7 +96,7 @@ module Arel # :nodoc: all
98
96
  end
99
97
 
100
98
  def froms
101
- @ast.cores.map { |x| x.from }.compact
99
+ @ast.cores.filter_map { |x| x.from }
102
100
  end
103
101
 
104
102
  def join(relation, klass = Nodes::InnerJoin)
@@ -183,11 +181,18 @@ module Arel # :nodoc: all
183
181
  @ast.orders
184
182
  end
185
183
 
184
+ def where(expr)
185
+ if Arel::TreeManager === expr
186
+ expr = expr.ast
187
+ end
188
+ @ctx.wheres << expr
189
+ self
190
+ end
191
+
186
192
  def where_sql(engine = Table.engine)
187
193
  return if @ctx.wheres.empty?
188
194
 
189
- viz = Visitors::WhereSql.new(engine.connection.visitor, engine.connection)
190
- Nodes::SqlLiteral.new viz.accept(@ctx, Collectors::SQLString.new).value
195
+ Nodes::SqlLiteral.new("WHERE #{Nodes::And.new(@ctx.wheres).to_sql(engine)}")
191
196
  end
192
197
 
193
198
  def union(operation, other = nil)
@@ -245,8 +250,12 @@ module Arel # :nodoc: all
245
250
  end
246
251
 
247
252
  def comment(*values)
248
- @ctx.comment = Nodes::Comment.new(values)
249
- self
253
+ if values.any?
254
+ @ctx.comment = Nodes::Comment.new(values)
255
+ self
256
+ else
257
+ @ctx.comment
258
+ end
250
259
  end
251
260
 
252
261
  private