activerecord 5.0.7.2 → 6.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (363) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +829 -2015
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +11 -9
  5. data/examples/performance.rb +31 -29
  6. data/examples/simple.rb +5 -3
  7. data/lib/active_record.rb +37 -29
  8. data/lib/active_record/aggregations.rb +249 -247
  9. data/lib/active_record/association_relation.rb +30 -18
  10. data/lib/active_record/associations.rb +1714 -1596
  11. data/lib/active_record/associations/alias_tracker.rb +36 -42
  12. data/lib/active_record/associations/association.rb +143 -68
  13. data/lib/active_record/associations/association_scope.rb +98 -94
  14. data/lib/active_record/associations/belongs_to_association.rb +76 -46
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -12
  16. data/lib/active_record/associations/builder/association.rb +27 -28
  17. data/lib/active_record/associations/builder/belongs_to.rb +52 -60
  18. data/lib/active_record/associations/builder/collection_association.rb +12 -22
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +40 -62
  20. data/lib/active_record/associations/builder/has_many.rb +10 -2
  21. data/lib/active_record/associations/builder/has_one.rb +35 -2
  22. data/lib/active_record/associations/builder/singular_association.rb +5 -1
  23. data/lib/active_record/associations/collection_association.rb +104 -259
  24. data/lib/active_record/associations/collection_proxy.rb +169 -125
  25. data/lib/active_record/associations/foreign_association.rb +22 -0
  26. data/lib/active_record/associations/has_many_association.rb +46 -31
  27. data/lib/active_record/associations/has_many_through_association.rb +66 -46
  28. data/lib/active_record/associations/has_one_association.rb +71 -52
  29. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  30. data/lib/active_record/associations/join_dependency.rb +169 -180
  31. data/lib/active_record/associations/join_dependency/join_association.rb +53 -79
  32. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  33. data/lib/active_record/associations/join_dependency/join_part.rb +14 -14
  34. data/lib/active_record/associations/preloader.rb +97 -104
  35. data/lib/active_record/associations/preloader/association.rb +109 -97
  36. data/lib/active_record/associations/preloader/through_association.rb +77 -76
  37. data/lib/active_record/associations/singular_association.rb +12 -45
  38. data/lib/active_record/associations/through_association.rb +27 -15
  39. data/lib/active_record/attribute_assignment.rb +55 -60
  40. data/lib/active_record/attribute_methods.rb +111 -141
  41. data/lib/active_record/attribute_methods/before_type_cast.rb +17 -9
  42. data/lib/active_record/attribute_methods/dirty.rb +172 -112
  43. data/lib/active_record/attribute_methods/primary_key.rb +88 -91
  44. data/lib/active_record/attribute_methods/query.rb +6 -8
  45. data/lib/active_record/attribute_methods/read.rb +18 -50
  46. data/lib/active_record/attribute_methods/serialization.rb +38 -10
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +38 -66
  48. data/lib/active_record/attribute_methods/write.rb +25 -32
  49. data/lib/active_record/attributes.rb +69 -31
  50. data/lib/active_record/autosave_association.rb +102 -66
  51. data/lib/active_record/base.rb +16 -25
  52. data/lib/active_record/callbacks.rb +202 -43
  53. data/lib/active_record/coders/json.rb +2 -0
  54. data/lib/active_record/coders/yaml_column.rb +11 -12
  55. data/lib/active_record/connection_adapters.rb +50 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +661 -375
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +14 -38
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +269 -105
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +54 -35
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +137 -93
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +155 -113
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -162
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +68 -80
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +591 -259
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +229 -91
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +392 -244
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +457 -582
  69. data/lib/active_record/connection_adapters/column.rb +55 -13
  70. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  71. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +8 -31
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +135 -49
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +24 -23
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +50 -20
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +79 -49
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +66 -56
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +70 -36
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +268 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +20 -12
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +74 -37
  82. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  83. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  84. data/lib/active_record/connection_adapters/postgresql/column.rb +39 -28
  85. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +70 -101
  86. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +5 -3
  87. data/lib/active_record/connection_adapters/postgresql/oid.rb +26 -21
  88. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +22 -11
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +6 -5
  90. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -6
  93. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +14 -4
  95. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -4
  97. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +19 -18
  98. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  101. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -5
  104. data/lib/active_record/connection_adapters/postgresql/oid/{json.rb → oid.rb} +6 -1
  105. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +30 -9
  106. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -30
  107. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  108. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +58 -54
  109. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +18 -4
  110. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  112. data/lib/active_record/connection_adapters/postgresql/quoting.rb +98 -38
  113. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +21 -27
  114. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +80 -0
  115. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +147 -105
  116. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +34 -32
  117. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +426 -324
  118. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +32 -23
  119. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -6
  120. data/lib/active_record/connection_adapters/postgresql_adapter.rb +418 -293
  121. data/lib/active_record/connection_adapters/schema_cache.rb +135 -18
  122. data/lib/active_record/connection_adapters/sql_type_metadata.rb +22 -7
  123. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
  124. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +3 -1
  125. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +72 -18
  126. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -6
  127. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  128. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  129. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +170 -0
  130. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +282 -290
  131. data/lib/active_record/connection_adapters/statement_pool.rb +9 -8
  132. data/lib/active_record/connection_handling.rb +287 -45
  133. data/lib/active_record/core.rb +385 -181
  134. data/lib/active_record/counter_cache.rb +60 -28
  135. data/lib/active_record/database_configurations.rb +272 -0
  136. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  137. data/lib/active_record/database_configurations/database_config.rb +80 -0
  138. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  139. data/lib/active_record/database_configurations/url_config.rb +53 -0
  140. data/lib/active_record/delegated_type.rb +209 -0
  141. data/lib/active_record/destroy_association_async_job.rb +36 -0
  142. data/lib/active_record/dynamic_matchers.rb +87 -87
  143. data/lib/active_record/enum.rb +122 -47
  144. data/lib/active_record/errors.rb +153 -22
  145. data/lib/active_record/explain.rb +13 -8
  146. data/lib/active_record/explain_registry.rb +3 -1
  147. data/lib/active_record/explain_subscriber.rb +9 -4
  148. data/lib/active_record/fixture_set/file.rb +20 -22
  149. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  150. data/lib/active_record/fixture_set/render_context.rb +17 -0
  151. data/lib/active_record/fixture_set/table_row.rb +152 -0
  152. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  153. data/lib/active_record/fixtures.rb +246 -507
  154. data/lib/active_record/gem_version.rb +6 -4
  155. data/lib/active_record/inheritance.rb +168 -95
  156. data/lib/active_record/insert_all.rb +208 -0
  157. data/lib/active_record/integration.rb +114 -25
  158. data/lib/active_record/internal_metadata.rb +30 -24
  159. data/lib/active_record/legacy_yaml_adapter.rb +11 -5
  160. data/lib/active_record/locking/optimistic.rb +81 -85
  161. data/lib/active_record/locking/pessimistic.rb +22 -6
  162. data/lib/active_record/log_subscriber.rb +68 -31
  163. data/lib/active_record/middleware/database_selector.rb +77 -0
  164. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  165. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  166. data/lib/active_record/migration.rb +439 -342
  167. data/lib/active_record/migration/command_recorder.rb +152 -98
  168. data/lib/active_record/migration/compatibility.rb +229 -60
  169. data/lib/active_record/migration/join_table.rb +8 -7
  170. data/lib/active_record/model_schema.rb +230 -122
  171. data/lib/active_record/nested_attributes.rb +213 -203
  172. data/lib/active_record/no_touching.rb +11 -2
  173. data/lib/active_record/null_relation.rb +12 -34
  174. data/lib/active_record/persistence.rb +471 -97
  175. data/lib/active_record/query_cache.rb +23 -12
  176. data/lib/active_record/querying.rb +43 -25
  177. data/lib/active_record/railtie.rb +155 -43
  178. data/lib/active_record/railties/console_sandbox.rb +2 -0
  179. data/lib/active_record/railties/controller_runtime.rb +34 -33
  180. data/lib/active_record/railties/databases.rake +507 -195
  181. data/lib/active_record/readonly_attributes.rb +9 -4
  182. data/lib/active_record/reflection.rb +245 -269
  183. data/lib/active_record/relation.rb +475 -324
  184. data/lib/active_record/relation/batches.rb +125 -72
  185. data/lib/active_record/relation/batches/batch_enumerator.rb +28 -10
  186. data/lib/active_record/relation/calculations.rb +267 -171
  187. data/lib/active_record/relation/delegation.rb +73 -69
  188. data/lib/active_record/relation/finder_methods.rb +238 -248
  189. data/lib/active_record/relation/from_clause.rb +7 -9
  190. data/lib/active_record/relation/merger.rb +95 -77
  191. data/lib/active_record/relation/predicate_builder.rb +109 -110
  192. data/lib/active_record/relation/predicate_builder/array_handler.rb +22 -17
  193. data/lib/active_record/relation/predicate_builder/association_query_value.rb +42 -0
  194. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +6 -4
  195. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +55 -0
  196. data/lib/active_record/relation/predicate_builder/range_handler.rb +7 -18
  197. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  198. data/lib/active_record/relation/query_attribute.rb +33 -2
  199. data/lib/active_record/relation/query_methods.rb +654 -374
  200. data/lib/active_record/relation/record_fetch_warning.rb +8 -6
  201. data/lib/active_record/relation/spawn_methods.rb +15 -14
  202. data/lib/active_record/relation/where_clause.rb +171 -109
  203. data/lib/active_record/result.rb +88 -51
  204. data/lib/active_record/runtime_registry.rb +5 -3
  205. data/lib/active_record/sanitization.rb +73 -100
  206. data/lib/active_record/schema.rb +7 -14
  207. data/lib/active_record/schema_dumper.rb +101 -69
  208. data/lib/active_record/schema_migration.rb +16 -12
  209. data/lib/active_record/scoping.rb +20 -20
  210. data/lib/active_record/scoping/default.rb +92 -95
  211. data/lib/active_record/scoping/named.rb +39 -30
  212. data/lib/active_record/secure_token.rb +19 -9
  213. data/lib/active_record/serialization.rb +7 -3
  214. data/lib/active_record/signed_id.rb +116 -0
  215. data/lib/active_record/statement_cache.rb +80 -29
  216. data/lib/active_record/store.rb +122 -42
  217. data/lib/active_record/suppressor.rb +6 -3
  218. data/lib/active_record/table_metadata.rb +51 -39
  219. data/lib/active_record/tasks/database_tasks.rb +332 -115
  220. data/lib/active_record/tasks/mysql_database_tasks.rb +66 -104
  221. data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -56
  222. data/lib/active_record/tasks/sqlite_database_tasks.rb +40 -19
  223. data/lib/active_record/test_databases.rb +24 -0
  224. data/lib/active_record/test_fixtures.rb +246 -0
  225. data/lib/active_record/timestamp.rb +70 -38
  226. data/lib/active_record/touch_later.rb +26 -24
  227. data/lib/active_record/transactions.rb +121 -184
  228. data/lib/active_record/translation.rb +3 -1
  229. data/lib/active_record/type.rb +29 -17
  230. data/lib/active_record/type/adapter_specific_registry.rb +44 -48
  231. data/lib/active_record/type/date.rb +2 -0
  232. data/lib/active_record/type/date_time.rb +2 -0
  233. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  234. data/lib/active_record/type/hash_lookup_type_map.rb +5 -4
  235. data/lib/active_record/type/internal/timezone.rb +2 -0
  236. data/lib/active_record/type/json.rb +30 -0
  237. data/lib/active_record/type/serialized.rb +20 -9
  238. data/lib/active_record/type/text.rb +11 -0
  239. data/lib/active_record/type/time.rb +12 -1
  240. data/lib/active_record/type/type_map.rb +14 -17
  241. data/lib/active_record/type/unsigned_integer.rb +16 -0
  242. data/lib/active_record/type_caster.rb +4 -2
  243. data/lib/active_record/type_caster/connection.rb +17 -13
  244. data/lib/active_record/type_caster/map.rb +10 -6
  245. data/lib/active_record/validations.rb +8 -5
  246. data/lib/active_record/validations/absence.rb +2 -0
  247. data/lib/active_record/validations/associated.rb +4 -3
  248. data/lib/active_record/validations/length.rb +2 -0
  249. data/lib/active_record/validations/numericality.rb +35 -0
  250. data/lib/active_record/validations/presence.rb +4 -2
  251. data/lib/active_record/validations/uniqueness.rb +52 -45
  252. data/lib/active_record/version.rb +3 -1
  253. data/lib/arel.rb +54 -0
  254. data/lib/arel/alias_predication.rb +9 -0
  255. data/lib/arel/attributes/attribute.rb +41 -0
  256. data/lib/arel/collectors/bind.rb +29 -0
  257. data/lib/arel/collectors/composite.rb +39 -0
  258. data/lib/arel/collectors/plain_string.rb +20 -0
  259. data/lib/arel/collectors/sql_string.rb +27 -0
  260. data/lib/arel/collectors/substitute_binds.rb +35 -0
  261. data/lib/arel/crud.rb +42 -0
  262. data/lib/arel/delete_manager.rb +18 -0
  263. data/lib/arel/errors.rb +9 -0
  264. data/lib/arel/expressions.rb +29 -0
  265. data/lib/arel/factory_methods.rb +49 -0
  266. data/lib/arel/insert_manager.rb +49 -0
  267. data/lib/arel/math.rb +45 -0
  268. data/lib/arel/nodes.rb +70 -0
  269. data/lib/arel/nodes/and.rb +32 -0
  270. data/lib/arel/nodes/ascending.rb +23 -0
  271. data/lib/arel/nodes/binary.rb +126 -0
  272. data/lib/arel/nodes/bind_param.rb +44 -0
  273. data/lib/arel/nodes/case.rb +55 -0
  274. data/lib/arel/nodes/casted.rb +62 -0
  275. data/lib/arel/nodes/comment.rb +29 -0
  276. data/lib/arel/nodes/count.rb +12 -0
  277. data/lib/arel/nodes/delete_statement.rb +45 -0
  278. data/lib/arel/nodes/descending.rb +23 -0
  279. data/lib/arel/nodes/equality.rb +15 -0
  280. data/lib/arel/nodes/extract.rb +24 -0
  281. data/lib/arel/nodes/false.rb +16 -0
  282. data/lib/arel/nodes/full_outer_join.rb +8 -0
  283. data/lib/arel/nodes/function.rb +44 -0
  284. data/lib/arel/nodes/grouping.rb +11 -0
  285. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  286. data/lib/arel/nodes/in.rb +15 -0
  287. data/lib/arel/nodes/infix_operation.rb +92 -0
  288. data/lib/arel/nodes/inner_join.rb +8 -0
  289. data/lib/arel/nodes/insert_statement.rb +37 -0
  290. data/lib/arel/nodes/join_source.rb +20 -0
  291. data/lib/arel/nodes/matches.rb +18 -0
  292. data/lib/arel/nodes/named_function.rb +23 -0
  293. data/lib/arel/nodes/node.rb +51 -0
  294. data/lib/arel/nodes/node_expression.rb +13 -0
  295. data/lib/arel/nodes/ordering.rb +27 -0
  296. data/lib/arel/nodes/outer_join.rb +8 -0
  297. data/lib/arel/nodes/over.rb +15 -0
  298. data/lib/arel/nodes/regexp.rb +16 -0
  299. data/lib/arel/nodes/right_outer_join.rb +8 -0
  300. data/lib/arel/nodes/select_core.rb +67 -0
  301. data/lib/arel/nodes/select_statement.rb +41 -0
  302. data/lib/arel/nodes/sql_literal.rb +19 -0
  303. data/lib/arel/nodes/string_join.rb +11 -0
  304. data/lib/arel/nodes/table_alias.rb +31 -0
  305. data/lib/arel/nodes/terminal.rb +16 -0
  306. data/lib/arel/nodes/true.rb +16 -0
  307. data/lib/arel/nodes/unary.rb +44 -0
  308. data/lib/arel/nodes/unary_operation.rb +20 -0
  309. data/lib/arel/nodes/unqualified_column.rb +22 -0
  310. data/lib/arel/nodes/update_statement.rb +41 -0
  311. data/lib/arel/nodes/values_list.rb +9 -0
  312. data/lib/arel/nodes/window.rb +126 -0
  313. data/lib/arel/nodes/with.rb +11 -0
  314. data/lib/arel/order_predications.rb +13 -0
  315. data/lib/arel/predications.rb +250 -0
  316. data/lib/arel/select_manager.rb +270 -0
  317. data/lib/arel/table.rb +118 -0
  318. data/lib/arel/tree_manager.rb +72 -0
  319. data/lib/arel/update_manager.rb +34 -0
  320. data/lib/arel/visitors.rb +13 -0
  321. data/lib/arel/visitors/dot.rb +308 -0
  322. data/lib/arel/visitors/mysql.rb +93 -0
  323. data/lib/arel/visitors/postgresql.rb +120 -0
  324. data/lib/arel/visitors/sqlite.rb +38 -0
  325. data/lib/arel/visitors/to_sql.rb +899 -0
  326. data/lib/arel/visitors/visitor.rb +45 -0
  327. data/lib/arel/window_predications.rb +9 -0
  328. data/lib/rails/generators/active_record.rb +7 -5
  329. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  330. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  331. data/lib/rails/generators/active_record/migration.rb +22 -3
  332. data/lib/rails/generators/active_record/migration/migration_generator.rb +38 -35
  333. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +3 -1
  334. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +7 -5
  335. data/lib/rails/generators/active_record/model/model_generator.rb +41 -25
  336. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  337. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +10 -1
  338. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  339. metadata +141 -57
  340. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  341. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  342. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  343. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  344. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  345. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  346. data/lib/active_record/associations/preloader/singular_association.rb +0 -20
  347. data/lib/active_record/attribute.rb +0 -213
  348. data/lib/active_record/attribute/user_provided_default.rb +0 -28
  349. data/lib/active_record/attribute_decorators.rb +0 -67
  350. data/lib/active_record/attribute_mutation_tracker.rb +0 -70
  351. data/lib/active_record/attribute_set.rb +0 -110
  352. data/lib/active_record/attribute_set/builder.rb +0 -132
  353. data/lib/active_record/collection_cache_key.rb +0 -50
  354. data/lib/active_record/connection_adapters/connection_specification.rb +0 -263
  355. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -22
  356. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +0 -50
  357. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  358. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  359. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -17
  360. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
  361. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -57
  362. data/lib/active_record/relation/where_clause_factory.rb +0 -38
  363. data/lib/active_record/type/internal/abstract_json.rb +0 -33
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arel # :nodoc: all
4
+ module Visitors
5
+ class MySQL < Arel::Visitors::ToSql
6
+ private
7
+ def visit_Arel_Nodes_Bin(o, collector)
8
+ collector << "BINARY "
9
+ visit o.expr, collector
10
+ end
11
+
12
+ def visit_Arel_Nodes_UnqualifiedColumn(o, collector)
13
+ visit o.expr, collector
14
+ end
15
+
16
+ ###
17
+ # :'(
18
+ # To retrieve all rows from a certain offset up to the end of the result set,
19
+ # you can use some large number for the second parameter.
20
+ # https://dev.mysql.com/doc/refman/en/select.html
21
+ def visit_Arel_Nodes_SelectStatement(o, collector)
22
+ if o.offset && !o.limit
23
+ o.limit = Arel::Nodes::Limit.new(18446744073709551615)
24
+ end
25
+ super
26
+ end
27
+
28
+ def visit_Arel_Nodes_SelectCore(o, collector)
29
+ o.froms ||= Arel.sql("DUAL")
30
+ super
31
+ end
32
+
33
+ def visit_Arel_Nodes_Concat(o, collector)
34
+ collector << " CONCAT("
35
+ visit o.left, collector
36
+ collector << ", "
37
+ visit o.right, collector
38
+ collector << ") "
39
+ collector
40
+ end
41
+
42
+ def visit_Arel_Nodes_IsNotDistinctFrom(o, collector)
43
+ collector = visit o.left, collector
44
+ collector << " <=> "
45
+ visit o.right, collector
46
+ end
47
+
48
+ def visit_Arel_Nodes_IsDistinctFrom(o, collector)
49
+ collector << "NOT "
50
+ visit_Arel_Nodes_IsNotDistinctFrom o, collector
51
+ end
52
+
53
+ def visit_Arel_Nodes_Regexp(o, collector)
54
+ infix_value o, collector, " REGEXP "
55
+ end
56
+
57
+ def visit_Arel_Nodes_NotRegexp(o, collector)
58
+ infix_value o, collector, " NOT REGEXP "
59
+ end
60
+
61
+ # In the simple case, MySQL allows us to place JOINs directly into the UPDATE
62
+ # query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
63
+ # these, we must use a subquery.
64
+ def prepare_update_statement(o)
65
+ if o.offset || has_join_sources?(o) && has_limit_or_offset_or_orders?(o)
66
+ super
67
+ else
68
+ o
69
+ end
70
+ end
71
+ alias :prepare_delete_statement :prepare_update_statement
72
+
73
+ # MySQL is too stupid to create a temporary table for use subquery, so we have
74
+ # to give it some prompting in the form of a subsubquery.
75
+ def build_subselect(key, o)
76
+ subselect = super
77
+
78
+ # Materialize subquery by adding distinct
79
+ # to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on'
80
+ unless has_limit_or_offset_or_orders?(subselect)
81
+ core = subselect.cores.last
82
+ core.set_quantifier = Arel::Nodes::Distinct.new
83
+ end
84
+
85
+ Nodes::SelectStatement.new.tap do |stmt|
86
+ core = stmt.cores.last
87
+ core.froms = Nodes::Grouping.new(subselect).as("__active_record_temp")
88
+ core.projections = [Arel.sql(quote_column_name(key.name))]
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arel # :nodoc: all
4
+ module Visitors
5
+ class PostgreSQL < Arel::Visitors::ToSql
6
+ private
7
+ def visit_Arel_Nodes_Matches(o, collector)
8
+ op = o.case_sensitive ? " LIKE " : " ILIKE "
9
+ collector = infix_value o, collector, op
10
+ if o.escape
11
+ collector << " ESCAPE "
12
+ visit o.escape, collector
13
+ else
14
+ collector
15
+ end
16
+ end
17
+
18
+ def visit_Arel_Nodes_DoesNotMatch(o, collector)
19
+ op = o.case_sensitive ? " NOT LIKE " : " NOT ILIKE "
20
+ collector = infix_value o, collector, op
21
+ if o.escape
22
+ collector << " ESCAPE "
23
+ visit o.escape, collector
24
+ else
25
+ collector
26
+ end
27
+ end
28
+
29
+ def visit_Arel_Nodes_Regexp(o, collector)
30
+ op = o.case_sensitive ? " ~ " : " ~* "
31
+ infix_value o, collector, op
32
+ end
33
+
34
+ def visit_Arel_Nodes_NotRegexp(o, collector)
35
+ op = o.case_sensitive ? " !~ " : " !~* "
36
+ infix_value o, collector, op
37
+ end
38
+
39
+ def visit_Arel_Nodes_DistinctOn(o, collector)
40
+ collector << "DISTINCT ON ( "
41
+ visit(o.expr, collector) << " )"
42
+ end
43
+
44
+ def visit_Arel_Nodes_GroupingElement(o, collector)
45
+ collector << "( "
46
+ visit(o.expr, collector) << " )"
47
+ end
48
+
49
+ def visit_Arel_Nodes_Cube(o, collector)
50
+ collector << "CUBE"
51
+ grouping_array_or_grouping_element o, collector
52
+ end
53
+
54
+ def visit_Arel_Nodes_RollUp(o, collector)
55
+ collector << "ROLLUP"
56
+ grouping_array_or_grouping_element o, collector
57
+ end
58
+
59
+ def visit_Arel_Nodes_GroupingSet(o, collector)
60
+ collector << "GROUPING SETS"
61
+ grouping_array_or_grouping_element o, collector
62
+ end
63
+
64
+ def visit_Arel_Nodes_Lateral(o, collector)
65
+ collector << "LATERAL "
66
+ grouping_parentheses o, collector
67
+ end
68
+
69
+ def visit_Arel_Nodes_IsNotDistinctFrom(o, collector)
70
+ collector = visit o.left, collector
71
+ collector << " IS NOT DISTINCT FROM "
72
+ visit o.right, collector
73
+ end
74
+
75
+ def visit_Arel_Nodes_IsDistinctFrom(o, collector)
76
+ collector = visit o.left, collector
77
+ collector << " IS DISTINCT FROM "
78
+ visit o.right, collector
79
+ end
80
+
81
+ def visit_Arel_Nodes_NullsFirst(o, collector)
82
+ visit o.expr, collector
83
+ collector << " NULLS FIRST"
84
+ end
85
+
86
+ def visit_Arel_Nodes_NullsLast(o, collector)
87
+ visit o.expr, collector
88
+ collector << " NULLS LAST"
89
+ end
90
+
91
+ BIND_BLOCK = proc { |i| "$#{i}" }
92
+ private_constant :BIND_BLOCK
93
+
94
+ def bind_block; BIND_BLOCK; end
95
+
96
+ # Used by Lateral visitor to enclose select queries in parentheses
97
+ def grouping_parentheses(o, collector)
98
+ if o.expr.is_a? Nodes::SelectStatement
99
+ collector << "("
100
+ visit o.expr, collector
101
+ collector << ")"
102
+ else
103
+ visit o.expr, collector
104
+ end
105
+ end
106
+
107
+ # Utilized by GroupingSet, Cube & RollUp visitors to
108
+ # handle grouping aggregation semantics
109
+ def grouping_array_or_grouping_element(o, collector)
110
+ if o.expr.is_a? Array
111
+ collector << "( "
112
+ visit o.expr, collector
113
+ collector << " )"
114
+ else
115
+ visit o.expr, collector
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arel # :nodoc: all
4
+ module Visitors
5
+ class SQLite < Arel::Visitors::ToSql
6
+ private
7
+ # Locks are not supported in SQLite
8
+ def visit_Arel_Nodes_Lock(o, collector)
9
+ collector
10
+ end
11
+
12
+ def visit_Arel_Nodes_SelectStatement(o, collector)
13
+ o.limit = Arel::Nodes::Limit.new(-1) if o.offset && !o.limit
14
+ super
15
+ end
16
+
17
+ def visit_Arel_Nodes_True(o, collector)
18
+ collector << "1"
19
+ end
20
+
21
+ def visit_Arel_Nodes_False(o, collector)
22
+ collector << "0"
23
+ end
24
+
25
+ def visit_Arel_Nodes_IsNotDistinctFrom(o, collector)
26
+ collector = visit o.left, collector
27
+ collector << " IS "
28
+ visit o.right, collector
29
+ end
30
+
31
+ def visit_Arel_Nodes_IsDistinctFrom(o, collector)
32
+ collector = visit o.left, collector
33
+ collector << " IS NOT "
34
+ visit o.right, collector
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,899 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Arel # :nodoc: all
4
+ module Visitors
5
+ class UnsupportedVisitError < StandardError
6
+ def initialize(object)
7
+ super "Unsupported argument type: #{object.class.name}. Construct an Arel node instead."
8
+ end
9
+ end
10
+
11
+ class ToSql < Arel::Visitors::Visitor
12
+ def initialize(connection)
13
+ super()
14
+ @connection = connection
15
+ end
16
+
17
+ def compile(node, collector = Arel::Collectors::SQLString.new)
18
+ accept(node, collector).value
19
+ end
20
+
21
+ private
22
+ def visit_Arel_Nodes_DeleteStatement(o, collector)
23
+ o = prepare_delete_statement(o)
24
+
25
+ if has_join_sources?(o)
26
+ collector << "DELETE "
27
+ visit o.relation.left, collector
28
+ collector << " FROM "
29
+ else
30
+ collector << "DELETE FROM "
31
+ end
32
+ collector = visit o.relation, collector
33
+
34
+ collect_nodes_for o.wheres, collector, " WHERE ", " AND "
35
+ collect_nodes_for o.orders, collector, " ORDER BY "
36
+ maybe_visit o.limit, collector
37
+ end
38
+
39
+ def visit_Arel_Nodes_UpdateStatement(o, collector)
40
+ o = prepare_update_statement(o)
41
+
42
+ collector << "UPDATE "
43
+ collector = visit o.relation, collector
44
+ collect_nodes_for o.values, collector, " SET "
45
+
46
+ collect_nodes_for o.wheres, collector, " WHERE ", " AND "
47
+ collect_nodes_for o.orders, collector, " ORDER BY "
48
+ maybe_visit o.limit, collector
49
+ end
50
+
51
+ def visit_Arel_Nodes_InsertStatement(o, collector)
52
+ collector << "INSERT INTO "
53
+ collector = visit o.relation, collector
54
+
55
+ unless o.columns.empty?
56
+ collector << " ("
57
+ o.columns.each_with_index do |x, i|
58
+ collector << ", " unless i == 0
59
+ collector << quote_column_name(x.name)
60
+ end
61
+ collector << ")"
62
+ end
63
+
64
+ if o.values
65
+ maybe_visit o.values, collector
66
+ elsif o.select
67
+ maybe_visit o.select, collector
68
+ else
69
+ collector
70
+ end
71
+ end
72
+
73
+ def visit_Arel_Nodes_Exists(o, collector)
74
+ collector << "EXISTS ("
75
+ collector = visit(o.expressions, collector) << ")"
76
+ if o.alias
77
+ collector << " AS "
78
+ visit o.alias, collector
79
+ else
80
+ collector
81
+ end
82
+ end
83
+
84
+ def visit_Arel_Nodes_Casted(o, collector)
85
+ collector << quote(o.value_for_database).to_s
86
+ end
87
+ alias :visit_Arel_Nodes_Quoted :visit_Arel_Nodes_Casted
88
+
89
+ def visit_Arel_Nodes_True(o, collector)
90
+ collector << "TRUE"
91
+ end
92
+
93
+ def visit_Arel_Nodes_False(o, collector)
94
+ collector << "FALSE"
95
+ end
96
+
97
+ def visit_Arel_Nodes_ValuesList(o, collector)
98
+ collector << "VALUES "
99
+
100
+ o.rows.each_with_index do |row, i|
101
+ collector << ", " unless i == 0
102
+ collector << "("
103
+ row.each_with_index do |value, k|
104
+ collector << ", " unless k == 0
105
+ case value
106
+ when Nodes::SqlLiteral, Nodes::BindParam
107
+ collector = visit(value, collector)
108
+ else
109
+ collector << quote(value).to_s
110
+ end
111
+ end
112
+ collector << ")"
113
+ end
114
+ collector
115
+ end
116
+
117
+ def visit_Arel_Nodes_SelectStatement(o, collector)
118
+ if o.with
119
+ collector = visit o.with, collector
120
+ collector << " "
121
+ end
122
+
123
+ collector = o.cores.inject(collector) { |c, x|
124
+ visit_Arel_Nodes_SelectCore(x, c)
125
+ }
126
+
127
+ unless o.orders.empty?
128
+ collector << " ORDER BY "
129
+ o.orders.each_with_index do |x, i|
130
+ collector << ", " unless i == 0
131
+ collector = visit(x, collector)
132
+ end
133
+ end
134
+
135
+ visit_Arel_Nodes_SelectOptions(o, collector)
136
+ end
137
+
138
+ def visit_Arel_Nodes_SelectOptions(o, collector)
139
+ collector = maybe_visit o.limit, collector
140
+ collector = maybe_visit o.offset, collector
141
+ maybe_visit o.lock, collector
142
+ end
143
+
144
+ def visit_Arel_Nodes_SelectCore(o, collector)
145
+ collector << "SELECT"
146
+
147
+ collector = collect_optimizer_hints(o, collector)
148
+ collector = maybe_visit o.set_quantifier, collector
149
+
150
+ collect_nodes_for o.projections, collector, " "
151
+
152
+ if o.source && !o.source.empty?
153
+ collector << " FROM "
154
+ collector = visit o.source, collector
155
+ end
156
+
157
+ collect_nodes_for o.wheres, collector, " WHERE ", " AND "
158
+ collect_nodes_for o.groups, collector, " GROUP BY "
159
+ collect_nodes_for o.havings, collector, " HAVING ", " AND "
160
+ collect_nodes_for o.windows, collector, " WINDOW "
161
+
162
+ maybe_visit o.comment, collector
163
+ end
164
+
165
+ def visit_Arel_Nodes_OptimizerHints(o, collector)
166
+ hints = o.expr.map { |v| sanitize_as_sql_comment(v) }.join(" ")
167
+ collector << "/*+ #{hints} */"
168
+ end
169
+
170
+ def visit_Arel_Nodes_Comment(o, collector)
171
+ collector << o.values.map { |v| "/* #{sanitize_as_sql_comment(v)} */" }.join(" ")
172
+ end
173
+
174
+ def collect_nodes_for(nodes, collector, spacer, connector = ", ")
175
+ unless nodes.empty?
176
+ collector << spacer
177
+ inject_join nodes, collector, connector
178
+ end
179
+ end
180
+
181
+ def visit_Arel_Nodes_Bin(o, collector)
182
+ visit o.expr, collector
183
+ end
184
+
185
+ def visit_Arel_Nodes_Distinct(o, collector)
186
+ collector << "DISTINCT"
187
+ end
188
+
189
+ def visit_Arel_Nodes_DistinctOn(o, collector)
190
+ raise NotImplementedError, "DISTINCT ON not implemented for this db"
191
+ end
192
+
193
+ def visit_Arel_Nodes_With(o, collector)
194
+ collector << "WITH "
195
+ collect_ctes(o.children, collector)
196
+ end
197
+
198
+ def visit_Arel_Nodes_WithRecursive(o, collector)
199
+ collector << "WITH RECURSIVE "
200
+ collect_ctes(o.children, collector)
201
+ end
202
+
203
+ def visit_Arel_Nodes_Union(o, collector)
204
+ infix_value_with_paren(o, collector, " UNION ")
205
+ end
206
+
207
+ def visit_Arel_Nodes_UnionAll(o, collector)
208
+ infix_value_with_paren(o, collector, " UNION ALL ")
209
+ end
210
+
211
+ def visit_Arel_Nodes_Intersect(o, collector)
212
+ collector << "( "
213
+ infix_value(o, collector, " INTERSECT ") << " )"
214
+ end
215
+
216
+ def visit_Arel_Nodes_Except(o, collector)
217
+ collector << "( "
218
+ infix_value(o, collector, " EXCEPT ") << " )"
219
+ end
220
+
221
+ def visit_Arel_Nodes_NamedWindow(o, collector)
222
+ collector << quote_column_name(o.name)
223
+ collector << " AS "
224
+ visit_Arel_Nodes_Window o, collector
225
+ end
226
+
227
+ def visit_Arel_Nodes_Window(o, collector)
228
+ collector << "("
229
+
230
+ collect_nodes_for o.partitions, collector, "PARTITION BY "
231
+
232
+ if o.orders.any?
233
+ collector << " " if o.partitions.any?
234
+ collector << "ORDER BY "
235
+ collector = inject_join o.orders, collector, ", "
236
+ end
237
+
238
+ if o.framing
239
+ collector << " " if o.partitions.any? || o.orders.any?
240
+ collector = visit o.framing, collector
241
+ end
242
+
243
+ collector << ")"
244
+ end
245
+
246
+ def visit_Arel_Nodes_Rows(o, collector)
247
+ if o.expr
248
+ collector << "ROWS "
249
+ visit o.expr, collector
250
+ else
251
+ collector << "ROWS"
252
+ end
253
+ end
254
+
255
+ def visit_Arel_Nodes_Range(o, collector)
256
+ if o.expr
257
+ collector << "RANGE "
258
+ visit o.expr, collector
259
+ else
260
+ collector << "RANGE"
261
+ end
262
+ end
263
+
264
+ def visit_Arel_Nodes_Preceding(o, collector)
265
+ collector = if o.expr
266
+ visit o.expr, collector
267
+ else
268
+ collector << "UNBOUNDED"
269
+ end
270
+
271
+ collector << " PRECEDING"
272
+ end
273
+
274
+ def visit_Arel_Nodes_Following(o, collector)
275
+ collector = if o.expr
276
+ visit o.expr, collector
277
+ else
278
+ collector << "UNBOUNDED"
279
+ end
280
+
281
+ collector << " FOLLOWING"
282
+ end
283
+
284
+ def visit_Arel_Nodes_CurrentRow(o, collector)
285
+ collector << "CURRENT ROW"
286
+ end
287
+
288
+ def visit_Arel_Nodes_Over(o, collector)
289
+ case o.right
290
+ when nil
291
+ visit(o.left, collector) << " OVER ()"
292
+ when Arel::Nodes::SqlLiteral
293
+ infix_value o, collector, " OVER "
294
+ when String, Symbol
295
+ visit(o.left, collector) << " OVER #{quote_column_name o.right.to_s}"
296
+ else
297
+ infix_value o, collector, " OVER "
298
+ end
299
+ end
300
+
301
+ def visit_Arel_Nodes_Offset(o, collector)
302
+ collector << "OFFSET "
303
+ visit o.expr, collector
304
+ end
305
+
306
+ def visit_Arel_Nodes_Limit(o, collector)
307
+ collector << "LIMIT "
308
+ visit o.expr, collector
309
+ end
310
+
311
+ def visit_Arel_Nodes_Lock(o, collector)
312
+ visit o.expr, collector
313
+ end
314
+
315
+ def visit_Arel_Nodes_Grouping(o, collector)
316
+ if o.expr.is_a? Nodes::Grouping
317
+ visit(o.expr, collector)
318
+ else
319
+ collector << "("
320
+ visit(o.expr, collector) << ")"
321
+ end
322
+ end
323
+
324
+ def visit_Arel_Nodes_HomogeneousIn(o, collector)
325
+ collector.preparable = false
326
+
327
+ collector << quote_table_name(o.table_name) << "." << quote_column_name(o.column_name)
328
+
329
+ if o.type == :in
330
+ collector << " IN ("
331
+ else
332
+ collector << " NOT IN ("
333
+ end
334
+
335
+ values = o.casted_values
336
+
337
+ if values.empty?
338
+ collector << @connection.quote(nil)
339
+ else
340
+ collector.add_binds(values, &bind_block)
341
+ end
342
+
343
+ collector << ")"
344
+ collector
345
+ end
346
+
347
+ def visit_Arel_SelectManager(o, collector)
348
+ collector << "("
349
+ visit(o.ast, collector) << ")"
350
+ end
351
+
352
+ def visit_Arel_Nodes_Ascending(o, collector)
353
+ visit(o.expr, collector) << " ASC"
354
+ end
355
+
356
+ def visit_Arel_Nodes_Descending(o, collector)
357
+ visit(o.expr, collector) << " DESC"
358
+ end
359
+
360
+ def visit_Arel_Nodes_Group(o, collector)
361
+ visit o.expr, collector
362
+ end
363
+
364
+ def visit_Arel_Nodes_NamedFunction(o, collector)
365
+ collector << o.name
366
+ collector << "("
367
+ collector << "DISTINCT " if o.distinct
368
+ collector = inject_join(o.expressions, collector, ", ") << ")"
369
+ if o.alias
370
+ collector << " AS "
371
+ visit o.alias, collector
372
+ else
373
+ collector
374
+ end
375
+ end
376
+
377
+ def visit_Arel_Nodes_Extract(o, collector)
378
+ collector << "EXTRACT(#{o.field.to_s.upcase} FROM "
379
+ visit(o.expr, collector) << ")"
380
+ end
381
+
382
+ def visit_Arel_Nodes_Count(o, collector)
383
+ aggregate "COUNT", o, collector
384
+ end
385
+
386
+ def visit_Arel_Nodes_Sum(o, collector)
387
+ aggregate "SUM", o, collector
388
+ end
389
+
390
+ def visit_Arel_Nodes_Max(o, collector)
391
+ aggregate "MAX", o, collector
392
+ end
393
+
394
+ def visit_Arel_Nodes_Min(o, collector)
395
+ aggregate "MIN", o, collector
396
+ end
397
+
398
+ def visit_Arel_Nodes_Avg(o, collector)
399
+ aggregate "AVG", o, collector
400
+ end
401
+
402
+ def visit_Arel_Nodes_TableAlias(o, collector)
403
+ collector = visit o.relation, collector
404
+ collector << " "
405
+ collector << quote_table_name(o.name)
406
+ end
407
+
408
+ def visit_Arel_Nodes_Between(o, collector)
409
+ collector = visit o.left, collector
410
+ collector << " BETWEEN "
411
+ visit o.right, collector
412
+ end
413
+
414
+ def visit_Arel_Nodes_GreaterThanOrEqual(o, collector)
415
+ collector = visit o.left, collector
416
+ collector << " >= "
417
+ visit o.right, collector
418
+ end
419
+
420
+ def visit_Arel_Nodes_GreaterThan(o, collector)
421
+ collector = visit o.left, collector
422
+ collector << " > "
423
+ visit o.right, collector
424
+ end
425
+
426
+ def visit_Arel_Nodes_LessThanOrEqual(o, collector)
427
+ collector = visit o.left, collector
428
+ collector << " <= "
429
+ visit o.right, collector
430
+ end
431
+
432
+ def visit_Arel_Nodes_LessThan(o, collector)
433
+ collector = visit o.left, collector
434
+ collector << " < "
435
+ visit o.right, collector
436
+ end
437
+
438
+ def visit_Arel_Nodes_Matches(o, collector)
439
+ collector = visit o.left, collector
440
+ collector << " LIKE "
441
+ collector = visit o.right, collector
442
+ if o.escape
443
+ collector << " ESCAPE "
444
+ visit o.escape, collector
445
+ else
446
+ collector
447
+ end
448
+ end
449
+
450
+ def visit_Arel_Nodes_DoesNotMatch(o, collector)
451
+ collector = visit o.left, collector
452
+ collector << " NOT LIKE "
453
+ collector = visit o.right, collector
454
+ if o.escape
455
+ collector << " ESCAPE "
456
+ visit o.escape, collector
457
+ else
458
+ collector
459
+ end
460
+ end
461
+
462
+ def visit_Arel_Nodes_JoinSource(o, collector)
463
+ if o.left
464
+ collector = visit o.left, collector
465
+ end
466
+ if o.right.any?
467
+ collector << " " if o.left
468
+ collector = inject_join o.right, collector, " "
469
+ end
470
+ collector
471
+ end
472
+
473
+ def visit_Arel_Nodes_Regexp(o, collector)
474
+ raise NotImplementedError, "~ not implemented for this db"
475
+ end
476
+
477
+ def visit_Arel_Nodes_NotRegexp(o, collector)
478
+ raise NotImplementedError, "!~ not implemented for this db"
479
+ end
480
+
481
+ def visit_Arel_Nodes_StringJoin(o, collector)
482
+ visit o.left, collector
483
+ end
484
+
485
+ def visit_Arel_Nodes_FullOuterJoin(o, collector)
486
+ collector << "FULL OUTER JOIN "
487
+ collector = visit o.left, collector
488
+ collector << " "
489
+ visit o.right, collector
490
+ end
491
+
492
+ def visit_Arel_Nodes_OuterJoin(o, collector)
493
+ collector << "LEFT OUTER JOIN "
494
+ collector = visit o.left, collector
495
+ collector << " "
496
+ visit o.right, collector
497
+ end
498
+
499
+ def visit_Arel_Nodes_RightOuterJoin(o, collector)
500
+ collector << "RIGHT OUTER JOIN "
501
+ collector = visit o.left, collector
502
+ collector << " "
503
+ visit o.right, collector
504
+ end
505
+
506
+ def visit_Arel_Nodes_InnerJoin(o, collector)
507
+ collector << "INNER JOIN "
508
+ collector = visit o.left, collector
509
+ if o.right
510
+ collector << " "
511
+ visit(o.right, collector)
512
+ else
513
+ collector
514
+ end
515
+ end
516
+
517
+ def visit_Arel_Nodes_On(o, collector)
518
+ collector << "ON "
519
+ visit o.expr, collector
520
+ end
521
+
522
+ def visit_Arel_Nodes_Not(o, collector)
523
+ collector << "NOT ("
524
+ visit(o.expr, collector) << ")"
525
+ end
526
+
527
+ def visit_Arel_Table(o, collector)
528
+ if o.table_alias
529
+ collector << quote_table_name(o.name) << " " << quote_table_name(o.table_alias)
530
+ else
531
+ collector << quote_table_name(o.name)
532
+ end
533
+ end
534
+
535
+ def visit_Arel_Nodes_In(o, collector)
536
+ collector.preparable = false
537
+ attr, values = o.left, o.right
538
+
539
+ if Array === values
540
+ unless values.empty?
541
+ values.delete_if { |value| unboundable?(value) }
542
+ end
543
+
544
+ return collector << "1=0" if values.empty?
545
+ end
546
+
547
+ visit(attr, collector) << " IN ("
548
+ visit(values, collector) << ")"
549
+ end
550
+
551
+ def visit_Arel_Nodes_NotIn(o, collector)
552
+ collector.preparable = false
553
+ attr, values = o.left, o.right
554
+
555
+ if Array === values
556
+ unless values.empty?
557
+ values.delete_if { |value| unboundable?(value) }
558
+ end
559
+
560
+ return collector << "1=1" if values.empty?
561
+ end
562
+
563
+ visit(attr, collector) << " NOT IN ("
564
+ visit(values, collector) << ")"
565
+ end
566
+
567
+ def visit_Arel_Nodes_And(o, collector)
568
+ inject_join o.children, collector, " AND "
569
+ end
570
+
571
+ def visit_Arel_Nodes_Or(o, collector)
572
+ stack = [o.right, o.left]
573
+
574
+ while o = stack.pop
575
+ if o.is_a?(Arel::Nodes::Or)
576
+ stack.push o.right, o.left
577
+ else
578
+ visit o, collector
579
+ collector << " OR " unless stack.empty?
580
+ end
581
+ end
582
+
583
+ collector
584
+ end
585
+
586
+ def visit_Arel_Nodes_Assignment(o, collector)
587
+ case o.right
588
+ when Arel::Nodes::Node, Arel::Attributes::Attribute
589
+ collector = visit o.left, collector
590
+ collector << " = "
591
+ visit o.right, collector
592
+ else
593
+ collector = visit o.left, collector
594
+ collector << " = "
595
+ collector << quote(o.right).to_s
596
+ end
597
+ end
598
+
599
+ def visit_Arel_Nodes_Equality(o, collector)
600
+ right = o.right
601
+
602
+ return collector << "1=0" if unboundable?(right)
603
+
604
+ collector = visit o.left, collector
605
+
606
+ if right.nil?
607
+ collector << " IS NULL"
608
+ else
609
+ collector << " = "
610
+ visit right, collector
611
+ end
612
+ end
613
+
614
+ def visit_Arel_Nodes_IsNotDistinctFrom(o, collector)
615
+ if o.right.nil?
616
+ collector = visit o.left, collector
617
+ collector << " IS NULL"
618
+ else
619
+ collector = is_distinct_from(o, collector)
620
+ collector << " = 0"
621
+ end
622
+ end
623
+
624
+ def visit_Arel_Nodes_IsDistinctFrom(o, collector)
625
+ if o.right.nil?
626
+ collector = visit o.left, collector
627
+ collector << " IS NOT NULL"
628
+ else
629
+ collector = is_distinct_from(o, collector)
630
+ collector << " = 1"
631
+ end
632
+ end
633
+
634
+ def visit_Arel_Nodes_NotEqual(o, collector)
635
+ right = o.right
636
+
637
+ return collector << "1=1" if unboundable?(right)
638
+
639
+ collector = visit o.left, collector
640
+
641
+ if right.nil?
642
+ collector << " IS NOT NULL"
643
+ else
644
+ collector << " != "
645
+ visit right, collector
646
+ end
647
+ end
648
+
649
+ def visit_Arel_Nodes_As(o, collector)
650
+ collector = visit o.left, collector
651
+ collector << " AS "
652
+ visit o.right, collector
653
+ end
654
+
655
+ def visit_Arel_Nodes_Case(o, collector)
656
+ collector << "CASE "
657
+ if o.case
658
+ visit o.case, collector
659
+ collector << " "
660
+ end
661
+ o.conditions.each do |condition|
662
+ visit condition, collector
663
+ collector << " "
664
+ end
665
+ if o.default
666
+ visit o.default, collector
667
+ collector << " "
668
+ end
669
+ collector << "END"
670
+ end
671
+
672
+ def visit_Arel_Nodes_When(o, collector)
673
+ collector << "WHEN "
674
+ visit o.left, collector
675
+ collector << " THEN "
676
+ visit o.right, collector
677
+ end
678
+
679
+ def visit_Arel_Nodes_Else(o, collector)
680
+ collector << "ELSE "
681
+ visit o.expr, collector
682
+ end
683
+
684
+ def visit_Arel_Nodes_UnqualifiedColumn(o, collector)
685
+ collector << quote_column_name(o.name)
686
+ end
687
+
688
+ def visit_Arel_Attributes_Attribute(o, collector)
689
+ join_name = o.relation.table_alias || o.relation.name
690
+ collector << quote_table_name(join_name) << "." << quote_column_name(o.name)
691
+ end
692
+
693
+ BIND_BLOCK = proc { "?" }
694
+ private_constant :BIND_BLOCK
695
+
696
+ def bind_block; BIND_BLOCK; end
697
+
698
+ def visit_Arel_Nodes_BindParam(o, collector)
699
+ collector.add_bind(o.value, &bind_block)
700
+ end
701
+
702
+ def visit_Arel_Nodes_SqlLiteral(o, collector)
703
+ collector.preparable = false
704
+ collector << o.to_s
705
+ end
706
+
707
+ def visit_Integer(o, collector)
708
+ collector << o.to_s
709
+ end
710
+
711
+ def unsupported(o, collector)
712
+ raise UnsupportedVisitError.new(o)
713
+ end
714
+
715
+ alias :visit_ActiveSupport_Multibyte_Chars :unsupported
716
+ alias :visit_ActiveSupport_StringInquirer :unsupported
717
+ alias :visit_BigDecimal :unsupported
718
+ alias :visit_Class :unsupported
719
+ alias :visit_Date :unsupported
720
+ alias :visit_DateTime :unsupported
721
+ alias :visit_FalseClass :unsupported
722
+ alias :visit_Float :unsupported
723
+ alias :visit_Hash :unsupported
724
+ alias :visit_NilClass :unsupported
725
+ alias :visit_String :unsupported
726
+ alias :visit_Symbol :unsupported
727
+ alias :visit_Time :unsupported
728
+ alias :visit_TrueClass :unsupported
729
+
730
+ def visit_Arel_Nodes_InfixOperation(o, collector)
731
+ collector = visit o.left, collector
732
+ collector << " #{o.operator} "
733
+ visit o.right, collector
734
+ end
735
+
736
+ def visit_Arel_Nodes_UnaryOperation(o, collector)
737
+ collector << " #{o.operator} "
738
+ visit o.expr, collector
739
+ end
740
+
741
+ def visit_Array(o, collector)
742
+ inject_join o, collector, ", "
743
+ end
744
+ alias :visit_Set :visit_Array
745
+
746
+ def quote(value)
747
+ return value if Arel::Nodes::SqlLiteral === value
748
+ @connection.quote value
749
+ end
750
+
751
+ def quote_table_name(name)
752
+ return name if Arel::Nodes::SqlLiteral === name
753
+ @connection.quote_table_name(name)
754
+ end
755
+
756
+ def quote_column_name(name)
757
+ return name if Arel::Nodes::SqlLiteral === name
758
+ @connection.quote_column_name(name)
759
+ end
760
+
761
+ def sanitize_as_sql_comment(value)
762
+ return value if Arel::Nodes::SqlLiteral === value
763
+ @connection.sanitize_as_sql_comment(value)
764
+ end
765
+
766
+ def collect_optimizer_hints(o, collector)
767
+ maybe_visit o.optimizer_hints, collector
768
+ end
769
+
770
+ def maybe_visit(thing, collector)
771
+ return collector unless thing
772
+ collector << " "
773
+ visit thing, collector
774
+ end
775
+
776
+ def inject_join(list, collector, join_str)
777
+ list.each_with_index do |x, i|
778
+ collector << join_str unless i == 0
779
+ collector = visit(x, collector)
780
+ end
781
+ collector
782
+ end
783
+
784
+ def unboundable?(value)
785
+ value.respond_to?(:unboundable?) && value.unboundable?
786
+ end
787
+
788
+ def has_join_sources?(o)
789
+ o.relation.is_a?(Nodes::JoinSource) && !o.relation.right.empty?
790
+ end
791
+
792
+ def has_limit_or_offset_or_orders?(o)
793
+ o.limit || o.offset || !o.orders.empty?
794
+ end
795
+
796
+ # The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
797
+ # on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
798
+ # an UPDATE statement, so in the MySQL visitor we redefine this to do that.
799
+ def prepare_update_statement(o)
800
+ if o.key && (has_limit_or_offset_or_orders?(o) || has_join_sources?(o))
801
+ stmt = o.clone
802
+ stmt.limit = nil
803
+ stmt.offset = nil
804
+ stmt.orders = []
805
+ stmt.wheres = [Nodes::In.new(o.key, [build_subselect(o.key, o)])]
806
+ stmt.relation = o.relation.left if has_join_sources?(o)
807
+ stmt
808
+ else
809
+ o
810
+ end
811
+ end
812
+ alias :prepare_delete_statement :prepare_update_statement
813
+
814
+ # FIXME: we should probably have a 2-pass visitor for this
815
+ def build_subselect(key, o)
816
+ stmt = Nodes::SelectStatement.new
817
+ core = stmt.cores.first
818
+ core.froms = o.relation
819
+ core.wheres = o.wheres
820
+ core.projections = [key]
821
+ stmt.limit = o.limit
822
+ stmt.offset = o.offset
823
+ stmt.orders = o.orders
824
+ stmt
825
+ end
826
+
827
+ def infix_value(o, collector, value)
828
+ collector = visit o.left, collector
829
+ collector << value
830
+ visit o.right, collector
831
+ end
832
+
833
+ def infix_value_with_paren(o, collector, value, suppress_parens = false)
834
+ collector << "( " unless suppress_parens
835
+ collector = if o.left.class == o.class
836
+ infix_value_with_paren(o.left, collector, value, true)
837
+ else
838
+ visit o.left, collector
839
+ end
840
+ collector << value
841
+ collector = if o.right.class == o.class
842
+ infix_value_with_paren(o.right, collector, value, true)
843
+ else
844
+ visit o.right, collector
845
+ end
846
+ collector << " )" unless suppress_parens
847
+ collector
848
+ end
849
+
850
+ def aggregate(name, o, collector)
851
+ collector << "#{name}("
852
+ if o.distinct
853
+ collector << "DISTINCT "
854
+ end
855
+ collector = inject_join(o.expressions, collector, ", ") << ")"
856
+ if o.alias
857
+ collector << " AS "
858
+ visit o.alias, collector
859
+ else
860
+ collector
861
+ end
862
+ end
863
+
864
+ def is_distinct_from(o, collector)
865
+ collector << "CASE WHEN "
866
+ collector = visit o.left, collector
867
+ collector << " = "
868
+ collector = visit o.right, collector
869
+ collector << " OR ("
870
+ collector = visit o.left, collector
871
+ collector << " IS NULL AND "
872
+ collector = visit o.right, collector
873
+ collector << " IS NULL)"
874
+ collector << " THEN 0 ELSE 1 END"
875
+ end
876
+
877
+ def collect_ctes(children, collector)
878
+ children.each_with_index do |child, i|
879
+ collector << ", " unless i == 0
880
+
881
+ case child
882
+ when Arel::Nodes::As
883
+ name = child.left.name
884
+ relation = child.right
885
+ when Arel::Nodes::TableAlias
886
+ name = child.name
887
+ relation = child.relation
888
+ end
889
+
890
+ collector << quote_table_name(name)
891
+ collector << " AS "
892
+ visit relation, collector
893
+ end
894
+
895
+ collector
896
+ end
897
+ end
898
+ end
899
+ end