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/table.rb CHANGED
@@ -2,19 +2,24 @@
2
2
 
3
3
  module Arel # :nodoc: all
4
4
  class Table
5
- include Arel::Crud
6
5
  include Arel::FactoryMethods
6
+ include Arel::AliasPredication
7
7
 
8
8
  @engine = nil
9
9
  class << self; attr_accessor :engine; end
10
10
 
11
- attr_accessor :name, :table_alias
11
+ attr_accessor :name
12
+ attr_reader :table_alias
12
13
 
13
- # TableAlias and Table both have a #table_name which is the name of the underlying table
14
- alias :table_name :name
14
+ def initialize(name, as: nil, klass: nil, type_caster: klass&.type_caster)
15
+ @name =
16
+ case name
17
+ when Symbol then name.to_s
18
+ else
19
+ name
20
+ end
15
21
 
16
- def initialize(name, as: nil, type_caster: nil)
17
- @name = name.to_s
22
+ @klass = klass
18
23
  @type_caster = type_caster
19
24
 
20
25
  # Sometime AR sends an :as parameter to table, to let the table know
@@ -78,8 +83,10 @@ module Arel # :nodoc: all
78
83
  from.having expr
79
84
  end
80
85
 
81
- def [](name)
82
- ::Arel::Attribute.new self, name
86
+ def [](name, table = self)
87
+ name = name.to_s if name.is_a?(Symbol)
88
+ name = @klass.attribute_aliases[name] || name if @klass
89
+ Attribute.new(table, name)
83
90
  end
84
91
 
85
92
  def hash
@@ -96,8 +103,12 @@ module Arel # :nodoc: all
96
103
  end
97
104
  alias :== :eql?
98
105
 
99
- def type_cast_for_database(attribute_name, value)
100
- type_caster.type_cast_for_database(attribute_name, value)
106
+ def type_cast_for_database(attr_name, value)
107
+ type_caster.type_cast_for_database(attr_name, value)
108
+ end
109
+
110
+ def type_for_attribute(name)
111
+ type_caster.type_for_attribute(name)
101
112
  end
102
113
 
103
114
  def able_to_type_cast?
@@ -21,7 +21,11 @@ module Arel # :nodoc: all
21
21
  end
22
22
 
23
23
  def key=(key)
24
- @ast.key = Nodes.build_quoted(key)
24
+ @ast.key = if key.is_a?(Array)
25
+ key.map { |k| Nodes.build_quoted(k) }
26
+ else
27
+ Nodes.build_quoted(key)
28
+ end
25
29
  end
26
30
 
27
31
  def key
@@ -40,10 +44,6 @@ module Arel # :nodoc: all
40
44
 
41
45
  attr_reader :ast
42
46
 
43
- def initialize
44
- @ctx = nil
45
- end
46
-
47
47
  def to_dot
48
48
  collector = Arel::Collectors::PlainString.new
49
49
  collector = Visitors::Dot.new.accept @ast, collector
@@ -52,21 +52,14 @@ module Arel # :nodoc: all
52
52
 
53
53
  def to_sql(engine = Table.engine)
54
54
  collector = Arel::Collectors::SQLString.new
55
- collector = engine.connection.visitor.accept @ast, collector
56
- collector.value
55
+ engine.with_connection do |connection|
56
+ connection.visitor.accept(@ast, collector).value
57
+ end
57
58
  end
58
59
 
59
60
  def initialize_copy(other)
60
61
  super
61
62
  @ast = @ast.clone
62
63
  end
63
-
64
- def where(expr)
65
- if Arel::TreeManager === expr
66
- expr = expr.ast
67
- end
68
- @ctx.wheres << expr
69
- self
70
- end
71
64
  end
72
65
  end
@@ -4,10 +4,8 @@ module Arel # :nodoc: all
4
4
  class UpdateManager < Arel::TreeManager
5
5
  include TreeManager::StatementMethods
6
6
 
7
- def initialize
8
- super
9
- @ast = Nodes::UpdateStatement.new
10
- @ctx = @ast
7
+ def initialize(table = nil)
8
+ @ast = Nodes::UpdateStatement.new(table)
11
9
  end
12
10
 
13
11
  ###
@@ -18,7 +16,8 @@ module Arel # :nodoc: all
18
16
  end
19
17
 
20
18
  def set(values)
21
- if String === values
19
+ case values
20
+ when String, Nodes::BoundSqlLiteral
22
21
  @ast.values = [values]
23
22
  else
24
23
  @ast.values = values.map { |column, value|
@@ -30,5 +29,26 @@ module Arel # :nodoc: all
30
29
  end
31
30
  self
32
31
  end
32
+
33
+ def group(columns)
34
+ columns.each do |column|
35
+ column = Nodes::SqlLiteral.new(column) if String === column
36
+ column = Nodes::SqlLiteral.new(column.to_s) if Symbol === column
37
+
38
+ @ast.groups.push Nodes::Group.new column
39
+ end
40
+
41
+ self
42
+ end
43
+
44
+ def having(expr)
45
+ @ast.havings << expr
46
+ self
47
+ end
48
+
49
+ def comment(value)
50
+ @ast.comment = value
51
+ self
52
+ end
33
53
  end
34
54
  end
@@ -31,6 +31,39 @@ module Arel # :nodoc: all
31
31
  end
32
32
 
33
33
  private
34
+ def visit_Arel_Nodes_Function(o)
35
+ visit_edge o, "expressions"
36
+ visit_edge o, "distinct"
37
+ visit_edge o, "alias"
38
+ end
39
+
40
+ def visit_Arel_Nodes_Unary(o)
41
+ visit_edge o, "expr"
42
+ end
43
+
44
+ def visit_Arel_Nodes_Binary(o)
45
+ visit_edge o, "left"
46
+ visit_edge o, "right"
47
+ end
48
+
49
+ def visit_Arel_Nodes_UnaryOperation(o)
50
+ visit_edge o, "operator"
51
+ visit_edge o, "expr"
52
+ end
53
+
54
+ def visit_Arel_Nodes_InfixOperation(o)
55
+ visit_edge o, "operator"
56
+ visit_edge o, "left"
57
+ visit_edge o, "right"
58
+ end
59
+
60
+ def visit__regexp(o)
61
+ visit_edge o, "left"
62
+ visit_edge o, "right"
63
+ visit_edge o, "case_sensitive"
64
+ end
65
+ alias :visit_Arel_Nodes_Regexp :visit__regexp
66
+ alias :visit_Arel_Nodes_NotRegexp :visit__regexp
34
67
 
35
68
  def visit_Arel_Nodes_Ordering(o)
36
69
  visit_edge o, "expr"
@@ -54,71 +87,29 @@ module Arel # :nodoc: all
54
87
  visit_edge o, "left"
55
88
  end
56
89
 
57
- def visit_Arel_Nodes_InnerJoin(o)
58
- visit_edge o, "left"
59
- visit_edge o, "right"
60
- end
61
- alias :visit_Arel_Nodes_FullOuterJoin :visit_Arel_Nodes_InnerJoin
62
- alias :visit_Arel_Nodes_OuterJoin :visit_Arel_Nodes_InnerJoin
63
- alias :visit_Arel_Nodes_RightOuterJoin :visit_Arel_Nodes_InnerJoin
64
-
65
- def visit_Arel_Nodes_DeleteStatement(o)
66
- visit_edge o, "relation"
67
- visit_edge o, "wheres"
68
- end
69
-
70
- def unary(o)
71
- visit_edge o, "expr"
72
- end
73
- alias :visit_Arel_Nodes_Group :unary
74
- alias :visit_Arel_Nodes_Cube :unary
75
- alias :visit_Arel_Nodes_RollUp :unary
76
- alias :visit_Arel_Nodes_GroupingSet :unary
77
- alias :visit_Arel_Nodes_GroupingElement :unary
78
- alias :visit_Arel_Nodes_Grouping :unary
79
- alias :visit_Arel_Nodes_Having :unary
80
- alias :visit_Arel_Nodes_Limit :unary
81
- alias :visit_Arel_Nodes_Not :unary
82
- alias :visit_Arel_Nodes_Offset :unary
83
- alias :visit_Arel_Nodes_On :unary
84
- alias :visit_Arel_Nodes_UnqualifiedColumn :unary
85
- alias :visit_Arel_Nodes_OptimizerHints :unary
86
- alias :visit_Arel_Nodes_Preceding :unary
87
- alias :visit_Arel_Nodes_Following :unary
88
- alias :visit_Arel_Nodes_Rows :unary
89
- alias :visit_Arel_Nodes_Range :unary
90
-
91
- def window(o)
90
+ def visit_Arel_Nodes_Window(o)
92
91
  visit_edge o, "partitions"
93
92
  visit_edge o, "orders"
94
93
  visit_edge o, "framing"
95
94
  end
96
- alias :visit_Arel_Nodes_Window :window
97
95
 
98
- def named_window(o)
96
+ def visit_Arel_Nodes_NamedWindow(o)
99
97
  visit_edge o, "partitions"
100
98
  visit_edge o, "orders"
101
99
  visit_edge o, "framing"
102
100
  visit_edge o, "name"
103
101
  end
104
- alias :visit_Arel_Nodes_NamedWindow :named_window
105
102
 
106
- def function(o)
107
- visit_edge o, "expressions"
108
- visit_edge o, "distinct"
109
- visit_edge o, "alias"
103
+ def visit__no_edges(o)
104
+ # intentionally left blank
110
105
  end
111
- alias :visit_Arel_Nodes_Exists :function
112
- alias :visit_Arel_Nodes_Min :function
113
- alias :visit_Arel_Nodes_Max :function
114
- alias :visit_Arel_Nodes_Avg :function
115
- alias :visit_Arel_Nodes_Sum :function
106
+ alias :visit_Arel_Nodes_CurrentRow :visit__no_edges
107
+ alias :visit_Arel_Nodes_Distinct :visit__no_edges
116
108
 
117
- def extract(o)
109
+ def visit_Arel_Nodes_Extract(o)
118
110
  visit_edge o, "expressions"
119
111
  visit_edge o, "alias"
120
112
  end
121
- alias :visit_Arel_Nodes_Extract :extract
122
113
 
123
114
  def visit_Arel_Nodes_NamedFunction(o)
124
115
  visit_edge o, "name"
@@ -131,13 +122,19 @@ module Arel # :nodoc: all
131
122
  visit_edge o, "relation"
132
123
  visit_edge o, "columns"
133
124
  visit_edge o, "values"
125
+ visit_edge o, "select"
134
126
  end
135
127
 
136
128
  def visit_Arel_Nodes_SelectCore(o)
137
129
  visit_edge o, "source"
138
130
  visit_edge o, "projections"
139
131
  visit_edge o, "wheres"
140
- visit_edge o, "windows"
132
+ visit_edge o, "windows"
133
+ visit_edge o, "groups"
134
+ visit_edge o, "comment"
135
+ visit_edge o, "havings"
136
+ visit_edge o, "set_quantifier"
137
+ visit_edge o, "optimizer_hints"
141
138
  end
142
139
 
143
140
  def visit_Arel_Nodes_SelectStatement(o)
@@ -145,12 +142,29 @@ module Arel # :nodoc: all
145
142
  visit_edge o, "limit"
146
143
  visit_edge o, "orders"
147
144
  visit_edge o, "offset"
145
+ visit_edge o, "lock"
146
+ visit_edge o, "with"
148
147
  end
149
148
 
150
149
  def visit_Arel_Nodes_UpdateStatement(o)
151
150
  visit_edge o, "relation"
152
151
  visit_edge o, "wheres"
153
152
  visit_edge o, "values"
153
+ visit_edge o, "orders"
154
+ visit_edge o, "limit"
155
+ visit_edge o, "offset"
156
+ visit_edge o, "comment"
157
+ visit_edge o, "key"
158
+ end
159
+
160
+ def visit_Arel_Nodes_DeleteStatement(o)
161
+ visit_edge o, "relation"
162
+ visit_edge o, "wheres"
163
+ visit_edge o, "orders"
164
+ visit_edge o, "limit"
165
+ visit_edge o, "offset"
166
+ visit_edge o, "comment"
167
+ visit_edge o, "key"
154
168
  end
155
169
 
156
170
  def visit_Arel_Table(o)
@@ -158,51 +172,29 @@ module Arel # :nodoc: all
158
172
  end
159
173
 
160
174
  def visit_Arel_Nodes_Casted(o)
161
- visit_edge o, "val"
175
+ visit_edge o, "value"
176
+ visit_edge o, "attribute"
177
+ end
178
+
179
+ def visit_Arel_Nodes_HomogeneousIn(o)
180
+ visit_edge o, "values"
181
+ visit_edge o, "type"
162
182
  visit_edge o, "attribute"
163
183
  end
164
184
 
165
- def visit_Arel_Attribute(o)
185
+ def visit_Arel_Attributes_Attribute(o)
166
186
  visit_edge o, "relation"
167
187
  visit_edge o, "name"
168
188
  end
169
- alias :visit_Arel_Attributes_Integer :visit_Arel_Attribute
170
- alias :visit_Arel_Attributes_Float :visit_Arel_Attribute
171
- alias :visit_Arel_Attributes_String :visit_Arel_Attribute
172
- alias :visit_Arel_Attributes_Time :visit_Arel_Attribute
173
- alias :visit_Arel_Attributes_Boolean :visit_Arel_Attribute
174
- alias :visit_Arel_Attributes_Attribute :visit_Arel_Attribute
175
189
 
176
- def nary(o)
177
- o.children.each_with_index do |x, i|
178
- edge(i) { visit x }
190
+ def visit__children(o)
191
+ o.children.each_with_index do |child, i|
192
+ edge(i) { visit child }
179
193
  end
180
194
  end
181
- alias :visit_Arel_Nodes_And :nary
182
-
183
- def binary(o)
184
- visit_edge o, "left"
185
- visit_edge o, "right"
186
- end
187
- alias :visit_Arel_Nodes_As :binary
188
- alias :visit_Arel_Nodes_Assignment :binary
189
- alias :visit_Arel_Nodes_Between :binary
190
- alias :visit_Arel_Nodes_Concat :binary
191
- alias :visit_Arel_Nodes_DoesNotMatch :binary
192
- alias :visit_Arel_Nodes_Equality :binary
193
- alias :visit_Arel_Nodes_GreaterThan :binary
194
- alias :visit_Arel_Nodes_GreaterThanOrEqual :binary
195
- alias :visit_Arel_Nodes_In :binary
196
- alias :visit_Arel_Nodes_JoinSource :binary
197
- alias :visit_Arel_Nodes_LessThan :binary
198
- alias :visit_Arel_Nodes_LessThanOrEqual :binary
199
- alias :visit_Arel_Nodes_IsNotDistinctFrom :binary
200
- alias :visit_Arel_Nodes_IsDistinctFrom :binary
201
- alias :visit_Arel_Nodes_Matches :binary
202
- alias :visit_Arel_Nodes_NotEqual :binary
203
- alias :visit_Arel_Nodes_NotIn :binary
204
- alias :visit_Arel_Nodes_Or :binary
205
- alias :visit_Arel_Nodes_Over :binary
195
+ alias :visit_Arel_Nodes_And :visit__children
196
+ alias :visit_Arel_Nodes_Or :visit__children
197
+ alias :visit_Arel_Nodes_With :visit__children
206
198
 
207
199
  def visit_String(o)
208
200
  @node_stack.last.fields << o
@@ -219,17 +211,23 @@ module Arel # :nodoc: all
219
211
  alias :visit_Symbol :visit_String
220
212
  alias :visit_Arel_Nodes_SqlLiteral :visit_String
221
213
 
222
- def visit_Arel_Nodes_BindParam(o); end
214
+ def visit_Arel_Nodes_BindParam(o)
215
+ visit_edge(o, "value")
216
+ end
217
+
218
+ def visit_ActiveModel_Attribute(o)
219
+ visit_edge(o, "value_before_type_cast")
220
+ end
223
221
 
224
222
  def visit_Hash(o)
225
223
  o.each_with_index do |pair, i|
226
- edge("pair_#{i}") { visit pair }
224
+ edge("pair_#{i}") { visit pair }
227
225
  end
228
226
  end
229
227
 
230
228
  def visit_Array(o)
231
- o.each_with_index do |x, i|
232
- edge(i) { visit x }
229
+ o.each_with_index do |member, i|
230
+ edge(i) { visit member }
233
231
  end
234
232
  end
235
233
  alias :visit_Set :visit_Array
@@ -238,6 +236,12 @@ module Arel # :nodoc: all
238
236
  visit_edge(o, "values")
239
237
  end
240
238
 
239
+ def visit_Arel_Nodes_Case(o)
240
+ visit_edge(o, "case")
241
+ visit_edge(o, "conditions")
242
+ visit_edge(o, "default")
243
+ end
244
+
241
245
  def visit_edge(o, method)
242
246
  edge(method) { visit o.send(method) }
243
247
  end
@@ -5,8 +5,9 @@ module Arel # :nodoc: all
5
5
  class MySQL < Arel::Visitors::ToSql
6
6
  private
7
7
  def visit_Arel_Nodes_Bin(o, collector)
8
- collector << "BINARY "
8
+ collector << "CAST("
9
9
  visit o.expr, collector
10
+ collector << " AS BINARY)"
10
11
  end
11
12
 
12
13
  def visit_Arel_Nodes_UnqualifiedColumn(o, collector)
@@ -15,7 +16,9 @@ module Arel # :nodoc: all
15
16
 
16
17
  ###
17
18
  # :'(
18
- # http://dev.mysql.com/doc/refman/5.0/en/select.html#id3482214
19
+ # To retrieve all rows from a certain offset up to the end of the result set,
20
+ # you can use some large number for the second parameter.
21
+ # https://dev.mysql.com/doc/refman/en/select.html
19
22
  def visit_Arel_Nodes_SelectStatement(o, collector)
20
23
  if o.offset && !o.limit
21
24
  o.limit = Arel::Nodes::Limit.new(18446744073709551615)
@@ -24,7 +27,7 @@ module Arel # :nodoc: all
24
27
  end
25
28
 
26
29
  def visit_Arel_Nodes_SelectCore(o, collector)
27
- o.froms ||= Arel.sql("DUAL")
30
+ o.froms ||= Arel.sql("DUAL", retryable: true)
28
31
  super
29
32
  end
30
33
 
@@ -48,11 +51,36 @@ module Arel # :nodoc: all
48
51
  visit_Arel_Nodes_IsNotDistinctFrom o, collector
49
52
  end
50
53
 
54
+ def visit_Arel_Nodes_Regexp(o, collector)
55
+ infix_value o, collector, " REGEXP "
56
+ end
57
+
58
+ def visit_Arel_Nodes_NotRegexp(o, collector)
59
+ infix_value o, collector, " NOT REGEXP "
60
+ end
61
+
62
+ def visit_Arel_Nodes_NullsFirst(o, collector)
63
+ visit(o.expr.expr, collector) << " IS NOT NULL, "
64
+ visit(o.expr, collector)
65
+ end
66
+
67
+ def visit_Arel_Nodes_NullsLast(o, collector)
68
+ visit(o.expr.expr, collector) << " IS NULL, "
69
+ visit(o.expr, collector)
70
+ end
71
+
72
+ def visit_Arel_Nodes_Cte(o, collector)
73
+ collector << quote_table_name(o.name)
74
+ collector << " AS "
75
+ visit o.relation, collector
76
+ end
77
+
51
78
  # In the simple case, MySQL allows us to place JOINs directly into the UPDATE
52
79
  # query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
53
80
  # these, we must use a subquery.
54
81
  def prepare_update_statement(o)
55
- if o.offset || has_join_sources?(o) && has_limit_or_offset_or_orders?(o)
82
+ if o.offset || has_group_by_and_having?(o) ||
83
+ has_join_sources?(o) && has_limit_or_offset_or_orders?(o)
56
84
  super
57
85
  else
58
86
  o
@@ -60,7 +88,7 @@ module Arel # :nodoc: all
60
88
  end
61
89
  alias :prepare_delete_statement :prepare_update_statement
62
90
 
63
- # MySQL is too stupid to create a temporary table for use subquery, so we have
91
+ # MySQL doesn't automatically create a temporary table for use subquery, so we have
64
92
  # to give it some prompting in the form of a subsubquery.
65
93
  def build_subselect(key, o)
66
94
  subselect = super
@@ -75,7 +103,7 @@ module Arel # :nodoc: all
75
103
  Nodes::SelectStatement.new.tap do |stmt|
76
104
  core = stmt.cores.last
77
105
  core.froms = Nodes::Grouping.new(subselect).as("__active_record_temp")
78
- core.projections = [Arel.sql(quote_column_name(key.name))]
106
+ core.projections = [Arel.sql(quote_column_name(key.name), retryable: true)]
79
107
  end
80
108
  end
81
109
  end
@@ -4,7 +4,6 @@ module Arel # :nodoc: all
4
4
  module Visitors
5
5
  class PostgreSQL < Arel::Visitors::ToSql
6
6
  private
7
-
8
7
  def visit_Arel_Nodes_Matches(o, collector)
9
8
  op = o.case_sensitive ? " LIKE " : " ILIKE "
10
9
  collector = infix_value o, collector, op
@@ -42,10 +41,6 @@ module Arel # :nodoc: all
42
41
  visit(o.expr, collector) << " )"
43
42
  end
44
43
 
45
- def visit_Arel_Nodes_BindParam(o, collector)
46
- collector.add_bind(o.value) { |i| "$#{i}" }
47
- end
48
-
49
44
  def visit_Arel_Nodes_GroupingElement(o, collector)
50
45
  collector << "( "
51
46
  visit(o.expr, collector) << " )"
@@ -68,7 +63,7 @@ module Arel # :nodoc: all
68
63
 
69
64
  def visit_Arel_Nodes_Lateral(o, collector)
70
65
  collector << "LATERAL "
71
- grouping_parentheses o, collector
66
+ grouping_parentheses o.expr, collector
72
67
  end
73
68
 
74
69
  def visit_Arel_Nodes_IsNotDistinctFrom(o, collector)
@@ -83,16 +78,10 @@ module Arel # :nodoc: all
83
78
  visit o.right, collector
84
79
  end
85
80
 
86
- # Used by Lateral visitor to enclose select queries in parentheses
87
- def grouping_parentheses(o, collector)
88
- if o.expr.is_a? Nodes::SelectStatement
89
- collector << "("
90
- visit o.expr, collector
91
- collector << ")"
92
- else
93
- visit o.expr, collector
94
- end
95
- end
81
+ BIND_BLOCK = proc { |i| "$#{i}" }
82
+ private_constant :BIND_BLOCK
83
+
84
+ def bind_block; BIND_BLOCK; end
96
85
 
97
86
  # Utilized by GroupingSet, Cube & RollUp visitors to
98
87
  # handle grouping aggregation semantics
@@ -4,7 +4,6 @@ module Arel # :nodoc: all
4
4
  module Visitors
5
5
  class SQLite < Arel::Visitors::ToSql
6
6
  private
7
-
8
7
  # Locks are not supported in SQLite
9
8
  def visit_Arel_Nodes_Lock(o, collector)
10
9
  collector
@@ -34,6 +33,31 @@ module Arel # :nodoc: all
34
33
  collector << " IS NOT "
35
34
  visit o.right, collector
36
35
  end
36
+
37
+ # Queries used in UNION should not be wrapped by parentheses,
38
+ # because it is an invalid syntax in SQLite.
39
+ def infix_value_with_paren(o, collector, value, suppress_parens = false)
40
+ collector << "( " unless suppress_parens
41
+
42
+ left = o.left.is_a?(Nodes::Grouping) ? o.left.expr : o.left
43
+ collector = if left.class == o.class
44
+ infix_value_with_paren(left, collector, value, true)
45
+ else
46
+ grouping_parentheses left, collector, false
47
+ end
48
+
49
+ collector << value
50
+
51
+ right = o.right.is_a?(Nodes::Grouping) ? o.right.expr : o.right
52
+ collector = if right.class == o.class
53
+ infix_value_with_paren(right, collector, value, true)
54
+ else
55
+ grouping_parentheses right, collector, false
56
+ end
57
+
58
+ collector << " )" unless suppress_parens
59
+ collector
60
+ end
37
61
  end
38
62
  end
39
63
  end