omg-activerecord 8.0.0.alpha1

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 (412) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +355 -0
  3. data/MIT-LICENSE +22 -0
  4. data/README.rdoc +219 -0
  5. data/examples/performance.rb +185 -0
  6. data/examples/simple.rb +15 -0
  7. data/lib/active_record/aggregations.rb +287 -0
  8. data/lib/active_record/association_relation.rb +50 -0
  9. data/lib/active_record/associations/alias_tracker.rb +90 -0
  10. data/lib/active_record/associations/association.rb +417 -0
  11. data/lib/active_record/associations/association_scope.rb +175 -0
  12. data/lib/active_record/associations/belongs_to_association.rb +163 -0
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +50 -0
  14. data/lib/active_record/associations/builder/association.rb +170 -0
  15. data/lib/active_record/associations/builder/belongs_to.rb +160 -0
  16. data/lib/active_record/associations/builder/collection_association.rb +80 -0
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +107 -0
  18. data/lib/active_record/associations/builder/has_many.rb +23 -0
  19. data/lib/active_record/associations/builder/has_one.rb +61 -0
  20. data/lib/active_record/associations/builder/singular_association.rb +48 -0
  21. data/lib/active_record/associations/collection_association.rb +535 -0
  22. data/lib/active_record/associations/collection_proxy.rb +1163 -0
  23. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  24. data/lib/active_record/associations/errors.rb +265 -0
  25. data/lib/active_record/associations/foreign_association.rb +40 -0
  26. data/lib/active_record/associations/has_many_association.rb +167 -0
  27. data/lib/active_record/associations/has_many_through_association.rb +232 -0
  28. data/lib/active_record/associations/has_one_association.rb +142 -0
  29. data/lib/active_record/associations/has_one_through_association.rb +45 -0
  30. data/lib/active_record/associations/join_dependency/join_association.rb +106 -0
  31. data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
  32. data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
  33. data/lib/active_record/associations/join_dependency.rb +301 -0
  34. data/lib/active_record/associations/nested_error.rb +47 -0
  35. data/lib/active_record/associations/preloader/association.rb +316 -0
  36. data/lib/active_record/associations/preloader/batch.rb +48 -0
  37. data/lib/active_record/associations/preloader/branch.rb +153 -0
  38. data/lib/active_record/associations/preloader/through_association.rb +150 -0
  39. data/lib/active_record/associations/preloader.rb +135 -0
  40. data/lib/active_record/associations/singular_association.rb +76 -0
  41. data/lib/active_record/associations/through_association.rb +132 -0
  42. data/lib/active_record/associations.rb +1897 -0
  43. data/lib/active_record/asynchronous_queries_tracker.rb +64 -0
  44. data/lib/active_record/attribute_assignment.rb +82 -0
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +106 -0
  46. data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
  47. data/lib/active_record/attribute_methods/dirty.rb +262 -0
  48. data/lib/active_record/attribute_methods/primary_key.rb +158 -0
  49. data/lib/active_record/attribute_methods/query.rb +50 -0
  50. data/lib/active_record/attribute_methods/read.rb +46 -0
  51. data/lib/active_record/attribute_methods/serialization.rb +232 -0
  52. data/lib/active_record/attribute_methods/time_zone_conversion.rb +94 -0
  53. data/lib/active_record/attribute_methods/write.rb +49 -0
  54. data/lib/active_record/attribute_methods.rb +542 -0
  55. data/lib/active_record/attributes.rb +307 -0
  56. data/lib/active_record/autosave_association.rb +586 -0
  57. data/lib/active_record/base.rb +338 -0
  58. data/lib/active_record/callbacks.rb +452 -0
  59. data/lib/active_record/coders/column_serializer.rb +61 -0
  60. data/lib/active_record/coders/json.rb +15 -0
  61. data/lib/active_record/coders/yaml_column.rb +95 -0
  62. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +290 -0
  63. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +210 -0
  64. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  65. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +923 -0
  66. data/lib/active_record/connection_adapters/abstract/database_limits.rb +31 -0
  67. data/lib/active_record/connection_adapters/abstract/database_statements.rb +747 -0
  68. data/lib/active_record/connection_adapters/abstract/query_cache.rb +319 -0
  69. data/lib/active_record/connection_adapters/abstract/quoting.rb +239 -0
  70. data/lib/active_record/connection_adapters/abstract/savepoints.rb +24 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +190 -0
  72. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +961 -0
  73. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +106 -0
  74. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1883 -0
  75. data/lib/active_record/connection_adapters/abstract/transaction.rb +676 -0
  76. data/lib/active_record/connection_adapters/abstract_adapter.rb +1218 -0
  77. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +1016 -0
  78. data/lib/active_record/connection_adapters/column.rb +122 -0
  79. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  80. data/lib/active_record/connection_adapters/mysql/column.rb +28 -0
  81. data/lib/active_record/connection_adapters/mysql/database_statements.rb +95 -0
  82. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +71 -0
  83. data/lib/active_record/connection_adapters/mysql/quoting.rb +114 -0
  84. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +106 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +106 -0
  86. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +97 -0
  87. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +300 -0
  88. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +40 -0
  89. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +96 -0
  90. data/lib/active_record/connection_adapters/mysql2_adapter.rb +196 -0
  91. data/lib/active_record/connection_adapters/pool_config.rb +83 -0
  92. data/lib/active_record/connection_adapters/pool_manager.rb +57 -0
  93. data/lib/active_record/connection_adapters/postgresql/column.rb +82 -0
  94. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +231 -0
  95. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +91 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +54 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +31 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +20 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +109 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +44 -0
  110. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +42 -0
  112. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  113. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +74 -0
  114. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +124 -0
  115. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  116. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  117. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  118. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +125 -0
  119. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +45 -0
  120. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  121. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  122. data/lib/active_record/connection_adapters/postgresql/oid.rb +38 -0
  123. data/lib/active_record/connection_adapters/postgresql/quoting.rb +238 -0
  124. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +71 -0
  125. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +169 -0
  126. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +392 -0
  127. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +127 -0
  128. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +1162 -0
  129. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +44 -0
  130. data/lib/active_record/connection_adapters/postgresql/utils.rb +79 -0
  131. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1182 -0
  132. data/lib/active_record/connection_adapters/schema_cache.rb +478 -0
  133. data/lib/active_record/connection_adapters/sql_type_metadata.rb +45 -0
  134. data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
  135. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +145 -0
  136. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  137. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +116 -0
  138. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +37 -0
  139. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +39 -0
  140. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +47 -0
  141. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +221 -0
  142. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +843 -0
  143. data/lib/active_record/connection_adapters/statement_pool.rb +67 -0
  144. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +69 -0
  145. data/lib/active_record/connection_adapters/trilogy_adapter.rb +212 -0
  146. data/lib/active_record/connection_adapters.rb +176 -0
  147. data/lib/active_record/connection_handling.rb +413 -0
  148. data/lib/active_record/core.rb +836 -0
  149. data/lib/active_record/counter_cache.rb +230 -0
  150. data/lib/active_record/database_configurations/connection_url_resolver.rb +105 -0
  151. data/lib/active_record/database_configurations/database_config.rb +104 -0
  152. data/lib/active_record/database_configurations/hash_config.rb +172 -0
  153. data/lib/active_record/database_configurations/url_config.rb +78 -0
  154. data/lib/active_record/database_configurations.rb +309 -0
  155. data/lib/active_record/delegated_type.rb +289 -0
  156. data/lib/active_record/deprecator.rb +7 -0
  157. data/lib/active_record/destroy_association_async_job.rb +38 -0
  158. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  159. data/lib/active_record/dynamic_matchers.rb +121 -0
  160. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  161. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  162. data/lib/active_record/encryption/cipher.rb +53 -0
  163. data/lib/active_record/encryption/config.rb +70 -0
  164. data/lib/active_record/encryption/configurable.rb +60 -0
  165. data/lib/active_record/encryption/context.rb +42 -0
  166. data/lib/active_record/encryption/contexts.rb +76 -0
  167. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  168. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  169. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  170. data/lib/active_record/encryption/encrypted_attribute_type.rb +184 -0
  171. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  172. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  173. data/lib/active_record/encryption/encryptor.rb +177 -0
  174. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  175. data/lib/active_record/encryption/errors.rb +15 -0
  176. data/lib/active_record/encryption/extended_deterministic_queries.rb +159 -0
  177. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  178. data/lib/active_record/encryption/key.rb +28 -0
  179. data/lib/active_record/encryption/key_generator.rb +53 -0
  180. data/lib/active_record/encryption/key_provider.rb +46 -0
  181. data/lib/active_record/encryption/message.rb +33 -0
  182. data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
  183. data/lib/active_record/encryption/message_serializer.rb +96 -0
  184. data/lib/active_record/encryption/null_encryptor.rb +25 -0
  185. data/lib/active_record/encryption/properties.rb +76 -0
  186. data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
  187. data/lib/active_record/encryption/scheme.rb +107 -0
  188. data/lib/active_record/encryption.rb +58 -0
  189. data/lib/active_record/enum.rb +424 -0
  190. data/lib/active_record/errors.rb +614 -0
  191. data/lib/active_record/explain.rb +63 -0
  192. data/lib/active_record/explain_registry.rb +37 -0
  193. data/lib/active_record/explain_subscriber.rb +34 -0
  194. data/lib/active_record/fixture_set/file.rb +89 -0
  195. data/lib/active_record/fixture_set/model_metadata.rb +42 -0
  196. data/lib/active_record/fixture_set/render_context.rb +19 -0
  197. data/lib/active_record/fixture_set/table_row.rb +208 -0
  198. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  199. data/lib/active_record/fixtures.rb +850 -0
  200. data/lib/active_record/future_result.rb +182 -0
  201. data/lib/active_record/gem_version.rb +17 -0
  202. data/lib/active_record/inheritance.rb +366 -0
  203. data/lib/active_record/insert_all.rb +328 -0
  204. data/lib/active_record/integration.rb +209 -0
  205. data/lib/active_record/internal_metadata.rb +164 -0
  206. data/lib/active_record/legacy_yaml_adapter.rb +15 -0
  207. data/lib/active_record/locale/en.yml +48 -0
  208. data/lib/active_record/locking/optimistic.rb +228 -0
  209. data/lib/active_record/locking/pessimistic.rb +102 -0
  210. data/lib/active_record/log_subscriber.rb +149 -0
  211. data/lib/active_record/marshalling.rb +56 -0
  212. data/lib/active_record/message_pack.rb +124 -0
  213. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  214. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  215. data/lib/active_record/middleware/database_selector.rb +87 -0
  216. data/lib/active_record/middleware/shard_selector.rb +62 -0
  217. data/lib/active_record/migration/command_recorder.rb +406 -0
  218. data/lib/active_record/migration/compatibility.rb +490 -0
  219. data/lib/active_record/migration/default_strategy.rb +22 -0
  220. data/lib/active_record/migration/execution_strategy.rb +19 -0
  221. data/lib/active_record/migration/join_table.rb +16 -0
  222. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  223. data/lib/active_record/migration.rb +1626 -0
  224. data/lib/active_record/model_schema.rb +635 -0
  225. data/lib/active_record/nested_attributes.rb +633 -0
  226. data/lib/active_record/no_touching.rb +65 -0
  227. data/lib/active_record/normalization.rb +163 -0
  228. data/lib/active_record/persistence.rb +968 -0
  229. data/lib/active_record/promise.rb +84 -0
  230. data/lib/active_record/query_cache.rb +56 -0
  231. data/lib/active_record/query_logs.rb +247 -0
  232. data/lib/active_record/query_logs_formatter.rb +30 -0
  233. data/lib/active_record/querying.rb +122 -0
  234. data/lib/active_record/railtie.rb +440 -0
  235. data/lib/active_record/railties/console_sandbox.rb +5 -0
  236. data/lib/active_record/railties/controller_runtime.rb +65 -0
  237. data/lib/active_record/railties/databases.rake +641 -0
  238. data/lib/active_record/railties/job_runtime.rb +23 -0
  239. data/lib/active_record/readonly_attributes.rb +66 -0
  240. data/lib/active_record/reflection.rb +1287 -0
  241. data/lib/active_record/relation/batches/batch_enumerator.rb +115 -0
  242. data/lib/active_record/relation/batches.rb +491 -0
  243. data/lib/active_record/relation/calculations.rb +679 -0
  244. data/lib/active_record/relation/delegation.rb +154 -0
  245. data/lib/active_record/relation/finder_methods.rb +661 -0
  246. data/lib/active_record/relation/from_clause.rb +30 -0
  247. data/lib/active_record/relation/merger.rb +192 -0
  248. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  249. data/lib/active_record/relation/predicate_builder/association_query_value.rb +76 -0
  250. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  251. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +60 -0
  252. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  253. data/lib/active_record/relation/predicate_builder/relation_handler.rb +24 -0
  254. data/lib/active_record/relation/predicate_builder.rb +181 -0
  255. data/lib/active_record/relation/query_attribute.rb +68 -0
  256. data/lib/active_record/relation/query_methods.rb +2235 -0
  257. data/lib/active_record/relation/record_fetch_warning.rb +52 -0
  258. data/lib/active_record/relation/spawn_methods.rb +78 -0
  259. data/lib/active_record/relation/where_clause.rb +218 -0
  260. data/lib/active_record/relation.rb +1495 -0
  261. data/lib/active_record/result.rb +249 -0
  262. data/lib/active_record/runtime_registry.rb +82 -0
  263. data/lib/active_record/sanitization.rb +254 -0
  264. data/lib/active_record/schema.rb +77 -0
  265. data/lib/active_record/schema_dumper.rb +364 -0
  266. data/lib/active_record/schema_migration.rb +106 -0
  267. data/lib/active_record/scoping/default.rb +205 -0
  268. data/lib/active_record/scoping/named.rb +202 -0
  269. data/lib/active_record/scoping.rb +136 -0
  270. data/lib/active_record/secure_password.rb +60 -0
  271. data/lib/active_record/secure_token.rb +66 -0
  272. data/lib/active_record/serialization.rb +29 -0
  273. data/lib/active_record/signed_id.rb +137 -0
  274. data/lib/active_record/statement_cache.rb +164 -0
  275. data/lib/active_record/store.rb +299 -0
  276. data/lib/active_record/suppressor.rb +59 -0
  277. data/lib/active_record/table_metadata.rb +85 -0
  278. data/lib/active_record/tasks/database_tasks.rb +681 -0
  279. data/lib/active_record/tasks/mysql_database_tasks.rb +120 -0
  280. data/lib/active_record/tasks/postgresql_database_tasks.rb +147 -0
  281. data/lib/active_record/tasks/sqlite_database_tasks.rb +89 -0
  282. data/lib/active_record/test_databases.rb +24 -0
  283. data/lib/active_record/test_fixtures.rb +321 -0
  284. data/lib/active_record/testing/query_assertions.rb +121 -0
  285. data/lib/active_record/timestamp.rb +177 -0
  286. data/lib/active_record/token_for.rb +123 -0
  287. data/lib/active_record/touch_later.rb +70 -0
  288. data/lib/active_record/transaction.rb +132 -0
  289. data/lib/active_record/transactions.rb +523 -0
  290. data/lib/active_record/translation.rb +22 -0
  291. data/lib/active_record/type/adapter_specific_registry.rb +144 -0
  292. data/lib/active_record/type/date.rb +9 -0
  293. data/lib/active_record/type/date_time.rb +9 -0
  294. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  295. data/lib/active_record/type/hash_lookup_type_map.rb +57 -0
  296. data/lib/active_record/type/internal/timezone.rb +22 -0
  297. data/lib/active_record/type/json.rb +30 -0
  298. data/lib/active_record/type/serialized.rb +76 -0
  299. data/lib/active_record/type/text.rb +11 -0
  300. data/lib/active_record/type/time.rb +35 -0
  301. data/lib/active_record/type/type_map.rb +58 -0
  302. data/lib/active_record/type/unsigned_integer.rb +16 -0
  303. data/lib/active_record/type.rb +83 -0
  304. data/lib/active_record/type_caster/connection.rb +33 -0
  305. data/lib/active_record/type_caster/map.rb +23 -0
  306. data/lib/active_record/type_caster.rb +9 -0
  307. data/lib/active_record/validations/absence.rb +25 -0
  308. data/lib/active_record/validations/associated.rb +65 -0
  309. data/lib/active_record/validations/length.rb +26 -0
  310. data/lib/active_record/validations/numericality.rb +36 -0
  311. data/lib/active_record/validations/presence.rb +45 -0
  312. data/lib/active_record/validations/uniqueness.rb +295 -0
  313. data/lib/active_record/validations.rb +101 -0
  314. data/lib/active_record/version.rb +10 -0
  315. data/lib/active_record.rb +616 -0
  316. data/lib/arel/alias_predication.rb +9 -0
  317. data/lib/arel/attributes/attribute.rb +33 -0
  318. data/lib/arel/collectors/bind.rb +31 -0
  319. data/lib/arel/collectors/composite.rb +46 -0
  320. data/lib/arel/collectors/plain_string.rb +20 -0
  321. data/lib/arel/collectors/sql_string.rb +27 -0
  322. data/lib/arel/collectors/substitute_binds.rb +35 -0
  323. data/lib/arel/crud.rb +48 -0
  324. data/lib/arel/delete_manager.rb +32 -0
  325. data/lib/arel/errors.rb +19 -0
  326. data/lib/arel/expressions.rb +29 -0
  327. data/lib/arel/factory_methods.rb +53 -0
  328. data/lib/arel/filter_predications.rb +9 -0
  329. data/lib/arel/insert_manager.rb +48 -0
  330. data/lib/arel/math.rb +45 -0
  331. data/lib/arel/nodes/ascending.rb +23 -0
  332. data/lib/arel/nodes/binary.rb +125 -0
  333. data/lib/arel/nodes/bind_param.rb +44 -0
  334. data/lib/arel/nodes/bound_sql_literal.rb +65 -0
  335. data/lib/arel/nodes/case.rb +55 -0
  336. data/lib/arel/nodes/casted.rb +62 -0
  337. data/lib/arel/nodes/comment.rb +29 -0
  338. data/lib/arel/nodes/count.rb +12 -0
  339. data/lib/arel/nodes/cte.rb +36 -0
  340. data/lib/arel/nodes/delete_statement.rb +44 -0
  341. data/lib/arel/nodes/descending.rb +23 -0
  342. data/lib/arel/nodes/equality.rb +15 -0
  343. data/lib/arel/nodes/extract.rb +24 -0
  344. data/lib/arel/nodes/false.rb +16 -0
  345. data/lib/arel/nodes/filter.rb +10 -0
  346. data/lib/arel/nodes/fragments.rb +35 -0
  347. data/lib/arel/nodes/full_outer_join.rb +8 -0
  348. data/lib/arel/nodes/function.rb +45 -0
  349. data/lib/arel/nodes/grouping.rb +11 -0
  350. data/lib/arel/nodes/homogeneous_in.rb +68 -0
  351. data/lib/arel/nodes/in.rb +15 -0
  352. data/lib/arel/nodes/infix_operation.rb +92 -0
  353. data/lib/arel/nodes/inner_join.rb +8 -0
  354. data/lib/arel/nodes/insert_statement.rb +37 -0
  355. data/lib/arel/nodes/join_source.rb +20 -0
  356. data/lib/arel/nodes/leading_join.rb +8 -0
  357. data/lib/arel/nodes/matches.rb +18 -0
  358. data/lib/arel/nodes/named_function.rb +23 -0
  359. data/lib/arel/nodes/nary.rb +39 -0
  360. data/lib/arel/nodes/node.rb +161 -0
  361. data/lib/arel/nodes/node_expression.rb +13 -0
  362. data/lib/arel/nodes/ordering.rb +27 -0
  363. data/lib/arel/nodes/outer_join.rb +8 -0
  364. data/lib/arel/nodes/over.rb +15 -0
  365. data/lib/arel/nodes/regexp.rb +16 -0
  366. data/lib/arel/nodes/right_outer_join.rb +8 -0
  367. data/lib/arel/nodes/select_core.rb +67 -0
  368. data/lib/arel/nodes/select_statement.rb +41 -0
  369. data/lib/arel/nodes/sql_literal.rb +32 -0
  370. data/lib/arel/nodes/string_join.rb +11 -0
  371. data/lib/arel/nodes/table_alias.rb +35 -0
  372. data/lib/arel/nodes/terminal.rb +16 -0
  373. data/lib/arel/nodes/true.rb +16 -0
  374. data/lib/arel/nodes/unary.rb +44 -0
  375. data/lib/arel/nodes/unary_operation.rb +20 -0
  376. data/lib/arel/nodes/unqualified_column.rb +22 -0
  377. data/lib/arel/nodes/update_statement.rb +46 -0
  378. data/lib/arel/nodes/values_list.rb +9 -0
  379. data/lib/arel/nodes/window.rb +126 -0
  380. data/lib/arel/nodes/with.rb +11 -0
  381. data/lib/arel/nodes.rb +75 -0
  382. data/lib/arel/order_predications.rb +13 -0
  383. data/lib/arel/predications.rb +260 -0
  384. data/lib/arel/select_manager.rb +276 -0
  385. data/lib/arel/table.rb +121 -0
  386. data/lib/arel/tree_manager.rb +65 -0
  387. data/lib/arel/update_manager.rb +49 -0
  388. data/lib/arel/visitors/dot.rb +299 -0
  389. data/lib/arel/visitors/mysql.rb +111 -0
  390. data/lib/arel/visitors/postgresql.rb +99 -0
  391. data/lib/arel/visitors/sqlite.rb +38 -0
  392. data/lib/arel/visitors/to_sql.rb +1033 -0
  393. data/lib/arel/visitors/visitor.rb +45 -0
  394. data/lib/arel/visitors.rb +13 -0
  395. data/lib/arel/window_predications.rb +9 -0
  396. data/lib/arel.rb +73 -0
  397. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  398. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +26 -0
  399. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  400. data/lib/rails/generators/active_record/migration/migration_generator.rb +76 -0
  401. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +29 -0
  402. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
  403. data/lib/rails/generators/active_record/migration.rb +54 -0
  404. data/lib/rails/generators/active_record/model/USAGE +113 -0
  405. data/lib/rails/generators/active_record/model/model_generator.rb +94 -0
  406. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  407. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  408. data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
  409. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  410. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  411. data/lib/rails/generators/active_record.rb +19 -0
  412. metadata +505 -0
@@ -0,0 +1,1033 @@
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
+ collector.retryable = false
24
+ o = prepare_delete_statement(o)
25
+
26
+ if has_join_sources?(o)
27
+ collector << "DELETE "
28
+ visit o.relation.left, collector
29
+ collector << " FROM "
30
+ else
31
+ collector << "DELETE FROM "
32
+ end
33
+ collector = visit o.relation, collector
34
+
35
+ collect_nodes_for o.wheres, collector, " WHERE ", " AND "
36
+ collect_nodes_for o.orders, collector, " ORDER BY "
37
+ maybe_visit o.limit, collector
38
+ end
39
+
40
+ def visit_Arel_Nodes_UpdateStatement(o, collector)
41
+ collector.retryable = false
42
+ o = prepare_update_statement(o)
43
+
44
+ collector << "UPDATE "
45
+ collector = visit o.relation, collector
46
+ collect_nodes_for o.values, collector, " SET "
47
+
48
+ collect_nodes_for o.wheres, collector, " WHERE ", " AND "
49
+ collect_nodes_for o.orders, collector, " ORDER BY "
50
+ maybe_visit o.limit, collector
51
+ end
52
+
53
+ def visit_Arel_Nodes_InsertStatement(o, collector)
54
+ collector.retryable = false
55
+ collector << "INSERT INTO "
56
+ collector = visit o.relation, collector
57
+
58
+ unless o.columns.empty?
59
+ collector << " ("
60
+ o.columns.each_with_index do |x, i|
61
+ collector << ", " unless i == 0
62
+ collector << quote_column_name(x.name)
63
+ end
64
+ collector << ")"
65
+ end
66
+
67
+ if o.values
68
+ maybe_visit o.values, collector
69
+ elsif o.select
70
+ maybe_visit o.select, collector
71
+ else
72
+ collector
73
+ end
74
+ end
75
+
76
+ def visit_Arel_Nodes_Exists(o, collector)
77
+ collector << "EXISTS ("
78
+ collector = visit(o.expressions, collector) << ")"
79
+ if o.alias
80
+ collector << " AS "
81
+ visit o.alias, collector
82
+ else
83
+ collector
84
+ end
85
+ end
86
+
87
+ def visit_Arel_Nodes_Casted(o, collector)
88
+ collector << quote(o.value_for_database).to_s
89
+ end
90
+ alias :visit_Arel_Nodes_Quoted :visit_Arel_Nodes_Casted
91
+
92
+ def visit_Arel_Nodes_True(o, collector)
93
+ collector << "TRUE"
94
+ end
95
+
96
+ def visit_Arel_Nodes_False(o, collector)
97
+ collector << "FALSE"
98
+ end
99
+
100
+ def visit_Arel_Nodes_ValuesList(o, collector)
101
+ collector << "VALUES "
102
+
103
+ o.rows.each_with_index do |row, i|
104
+ collector << ", " unless i == 0
105
+ collector << "("
106
+ row.each_with_index do |value, k|
107
+ collector << ", " unless k == 0
108
+ case value
109
+ when Nodes::SqlLiteral, Nodes::BindParam, ActiveModel::Attribute
110
+ collector = visit(value, collector)
111
+ else
112
+ collector << quote(value).to_s
113
+ end
114
+ end
115
+ collector << ")"
116
+ end
117
+ collector
118
+ end
119
+
120
+ def visit_Arel_Nodes_SelectStatement(o, collector)
121
+ if o.with
122
+ collector = visit o.with, collector
123
+ collector << " "
124
+ end
125
+
126
+ collector = o.cores.inject(collector) { |c, x|
127
+ visit_Arel_Nodes_SelectCore(x, c)
128
+ }
129
+
130
+ unless o.orders.empty?
131
+ collector << " ORDER BY "
132
+ o.orders.each_with_index do |x, i|
133
+ collector << ", " unless i == 0
134
+ collector = visit(x, collector)
135
+ end
136
+ end
137
+
138
+ visit_Arel_Nodes_SelectOptions(o, collector)
139
+ end
140
+
141
+ # The Oracle enhanced adapter uses this private method,
142
+ # see https://github.com/rsim/oracle-enhanced/issues/2186
143
+ def visit_Arel_Nodes_SelectOptions(o, collector)
144
+ collector = maybe_visit o.limit, collector
145
+ collector = maybe_visit o.offset, collector
146
+ maybe_visit o.lock, collector
147
+ end
148
+
149
+ def visit_Arel_Nodes_SelectCore(o, collector)
150
+ collector << "SELECT"
151
+
152
+ collector = collect_optimizer_hints(o, collector)
153
+ collector = maybe_visit o.set_quantifier, collector
154
+
155
+ collect_nodes_for o.projections, collector, " "
156
+
157
+ if o.source && !o.source.empty?
158
+ collector << " FROM "
159
+ collector = visit o.source, collector
160
+ end
161
+
162
+ collect_nodes_for o.wheres, collector, " WHERE ", " AND "
163
+ collect_nodes_for o.groups, collector, " GROUP BY "
164
+ collect_nodes_for o.havings, collector, " HAVING ", " AND "
165
+ collect_nodes_for o.windows, collector, " WINDOW "
166
+
167
+ maybe_visit o.comment, collector
168
+ end
169
+
170
+ def visit_Arel_Nodes_OptimizerHints(o, collector)
171
+ hints = o.expr.map { |v| sanitize_as_sql_comment(v) }.join(" ")
172
+ collector << "/*+ #{hints} */"
173
+ end
174
+
175
+ def visit_Arel_Nodes_Comment(o, collector)
176
+ collector << o.values.map { |v| "/* #{sanitize_as_sql_comment(v)} */" }.join(" ")
177
+ end
178
+
179
+ def collect_nodes_for(nodes, collector, spacer, connector = ", ")
180
+ unless nodes.empty?
181
+ collector << spacer
182
+ inject_join nodes, collector, connector
183
+ end
184
+ end
185
+
186
+ def visit_Arel_Nodes_Bin(o, collector)
187
+ visit o.expr, collector
188
+ end
189
+
190
+ def visit_Arel_Nodes_Distinct(o, collector)
191
+ collector << "DISTINCT"
192
+ end
193
+
194
+ def visit_Arel_Nodes_DistinctOn(o, collector)
195
+ raise NotImplementedError, "DISTINCT ON not implemented for this db"
196
+ end
197
+
198
+ def visit_Arel_Nodes_With(o, collector)
199
+ collector << "WITH "
200
+ collect_ctes(o.children, collector)
201
+ end
202
+
203
+ def visit_Arel_Nodes_WithRecursive(o, collector)
204
+ collector << "WITH RECURSIVE "
205
+ collect_ctes(o.children, collector)
206
+ end
207
+
208
+ def visit_Arel_Nodes_Union(o, collector)
209
+ infix_value_with_paren(o, collector, " UNION ")
210
+ end
211
+
212
+ def visit_Arel_Nodes_UnionAll(o, collector)
213
+ infix_value_with_paren(o, collector, " UNION ALL ")
214
+ end
215
+
216
+ def visit_Arel_Nodes_Intersect(o, collector)
217
+ collector << "( "
218
+ infix_value(o, collector, " INTERSECT ") << " )"
219
+ end
220
+
221
+ def visit_Arel_Nodes_Except(o, collector)
222
+ collector << "( "
223
+ infix_value(o, collector, " EXCEPT ") << " )"
224
+ end
225
+
226
+ def visit_Arel_Nodes_NamedWindow(o, collector)
227
+ collector << quote_column_name(o.name)
228
+ collector << " AS "
229
+ visit_Arel_Nodes_Window o, collector
230
+ end
231
+
232
+ def visit_Arel_Nodes_Window(o, collector)
233
+ collector << "("
234
+
235
+ collect_nodes_for o.partitions, collector, "PARTITION BY "
236
+
237
+ if o.orders.any?
238
+ collector << " " if o.partitions.any?
239
+ collector << "ORDER BY "
240
+ collector = inject_join o.orders, collector, ", "
241
+ end
242
+
243
+ if o.framing
244
+ collector << " " if o.partitions.any? || o.orders.any?
245
+ collector = visit o.framing, collector
246
+ end
247
+
248
+ collector << ")"
249
+ end
250
+
251
+ def visit_Arel_Nodes_Filter(o, collector)
252
+ visit o.left, collector
253
+ collector << " FILTER (WHERE "
254
+ visit o.right, collector
255
+ collector << ")"
256
+ end
257
+
258
+ def visit_Arel_Nodes_Rows(o, collector)
259
+ if o.expr
260
+ collector << "ROWS "
261
+ visit o.expr, collector
262
+ else
263
+ collector << "ROWS"
264
+ end
265
+ end
266
+
267
+ def visit_Arel_Nodes_Range(o, collector)
268
+ if o.expr
269
+ collector << "RANGE "
270
+ visit o.expr, collector
271
+ else
272
+ collector << "RANGE"
273
+ end
274
+ end
275
+
276
+ def visit_Arel_Nodes_Preceding(o, collector)
277
+ collector = if o.expr
278
+ visit o.expr, collector
279
+ else
280
+ collector << "UNBOUNDED"
281
+ end
282
+
283
+ collector << " PRECEDING"
284
+ end
285
+
286
+ def visit_Arel_Nodes_Following(o, collector)
287
+ collector = if o.expr
288
+ visit o.expr, collector
289
+ else
290
+ collector << "UNBOUNDED"
291
+ end
292
+
293
+ collector << " FOLLOWING"
294
+ end
295
+
296
+ def visit_Arel_Nodes_CurrentRow(o, collector)
297
+ collector << "CURRENT ROW"
298
+ end
299
+
300
+ def visit_Arel_Nodes_Over(o, collector)
301
+ case o.right
302
+ when nil
303
+ visit(o.left, collector) << " OVER ()"
304
+ when Arel::Nodes::SqlLiteral
305
+ infix_value o, collector, " OVER "
306
+ when String, Symbol
307
+ visit(o.left, collector) << " OVER #{quote_column_name o.right.to_s}"
308
+ else
309
+ infix_value o, collector, " OVER "
310
+ end
311
+ end
312
+
313
+ def visit_Arel_Nodes_Offset(o, collector)
314
+ collector << "OFFSET "
315
+ visit o.expr, collector
316
+ end
317
+
318
+ def visit_Arel_Nodes_Limit(o, collector)
319
+ collector << "LIMIT "
320
+ visit o.expr, collector
321
+ end
322
+
323
+ def visit_Arel_Nodes_Lock(o, collector)
324
+ visit o.expr, collector
325
+ end
326
+
327
+ def visit_Arel_Nodes_Grouping(o, collector)
328
+ if o.expr.is_a? Nodes::Grouping
329
+ visit(o.expr, collector)
330
+ else
331
+ collector << "("
332
+ visit(o.expr, collector) << ")"
333
+ end
334
+ end
335
+
336
+ def visit_Arel_Nodes_HomogeneousIn(o, collector)
337
+ collector.preparable = false
338
+
339
+ visit o.left, collector
340
+
341
+ if o.type == :in
342
+ collector << " IN ("
343
+ else
344
+ collector << " NOT IN ("
345
+ end
346
+
347
+ values = o.casted_values
348
+
349
+ if values.empty?
350
+ collector << @connection.quote(nil)
351
+ else
352
+ collector.add_binds(values, o.proc_for_binds, &bind_block)
353
+ end
354
+
355
+ collector << ")"
356
+ end
357
+
358
+ def visit_Arel_SelectManager(o, collector)
359
+ collector << "("
360
+ visit(o.ast, collector) << ")"
361
+ end
362
+
363
+ def visit_Arel_Nodes_Ascending(o, collector)
364
+ visit(o.expr, collector) << " ASC"
365
+ end
366
+
367
+ def visit_Arel_Nodes_Descending(o, collector)
368
+ visit(o.expr, collector) << " DESC"
369
+ end
370
+
371
+ # NullsFirst is available on all but MySQL, where it is redefined.
372
+ def visit_Arel_Nodes_NullsFirst(o, collector)
373
+ visit o.expr, collector
374
+ collector << " NULLS FIRST"
375
+ end
376
+
377
+ def visit_Arel_Nodes_NullsLast(o, collector)
378
+ visit o.expr, collector
379
+ collector << " NULLS LAST"
380
+ end
381
+
382
+ def visit_Arel_Nodes_Group(o, collector)
383
+ visit o.expr, collector
384
+ end
385
+
386
+ def visit_Arel_Nodes_NamedFunction(o, collector)
387
+ collector.retryable = false
388
+ collector << o.name
389
+ collector << "("
390
+ collector << "DISTINCT " if o.distinct
391
+ collector = inject_join(o.expressions, collector, ", ") << ")"
392
+ if o.alias
393
+ collector << " AS "
394
+ visit o.alias, collector
395
+ else
396
+ collector
397
+ end
398
+ end
399
+
400
+ def visit_Arel_Nodes_Extract(o, collector)
401
+ collector << "EXTRACT(#{o.field.to_s.upcase} FROM "
402
+ visit(o.expr, collector) << ")"
403
+ end
404
+
405
+ def visit_Arel_Nodes_Count(o, collector)
406
+ aggregate "COUNT", o, collector
407
+ end
408
+
409
+ def visit_Arel_Nodes_Sum(o, collector)
410
+ aggregate "SUM", o, collector
411
+ end
412
+
413
+ def visit_Arel_Nodes_Max(o, collector)
414
+ aggregate "MAX", o, collector
415
+ end
416
+
417
+ def visit_Arel_Nodes_Min(o, collector)
418
+ aggregate "MIN", o, collector
419
+ end
420
+
421
+ def visit_Arel_Nodes_Avg(o, collector)
422
+ aggregate "AVG", o, collector
423
+ end
424
+
425
+ def visit_Arel_Nodes_TableAlias(o, collector)
426
+ collector = visit o.relation, collector
427
+ collector << " "
428
+ collector << quote_table_name(o.name)
429
+ end
430
+
431
+ def visit_Arel_Nodes_Between(o, collector)
432
+ collector = visit o.left, collector
433
+ collector << " BETWEEN "
434
+ visit o.right, collector
435
+ end
436
+
437
+ def visit_Arel_Nodes_GreaterThanOrEqual(o, collector)
438
+ case unboundable?(o.right)
439
+ when 1
440
+ return collector << "1=0"
441
+ when -1
442
+ return collector << "1=1"
443
+ end
444
+ collector = visit o.left, collector
445
+ collector << " >= "
446
+ visit o.right, collector
447
+ end
448
+
449
+ def visit_Arel_Nodes_GreaterThan(o, collector)
450
+ case unboundable?(o.right)
451
+ when 1
452
+ return collector << "1=0"
453
+ when -1
454
+ return collector << "1=1"
455
+ end
456
+ collector = visit o.left, collector
457
+ collector << " > "
458
+ visit o.right, collector
459
+ end
460
+
461
+ def visit_Arel_Nodes_LessThanOrEqual(o, collector)
462
+ case unboundable?(o.right)
463
+ when 1
464
+ return collector << "1=1"
465
+ when -1
466
+ return collector << "1=0"
467
+ end
468
+ collector = visit o.left, collector
469
+ collector << " <= "
470
+ visit o.right, collector
471
+ end
472
+
473
+ def visit_Arel_Nodes_LessThan(o, collector)
474
+ case unboundable?(o.right)
475
+ when 1
476
+ return collector << "1=1"
477
+ when -1
478
+ return collector << "1=0"
479
+ end
480
+ collector = visit o.left, collector
481
+ collector << " < "
482
+ visit o.right, collector
483
+ end
484
+
485
+ def visit_Arel_Nodes_Matches(o, collector)
486
+ collector = visit o.left, collector
487
+ collector << " LIKE "
488
+ collector = visit o.right, collector
489
+ if o.escape
490
+ collector << " ESCAPE "
491
+ visit o.escape, collector
492
+ else
493
+ collector
494
+ end
495
+ end
496
+
497
+ def visit_Arel_Nodes_DoesNotMatch(o, collector)
498
+ collector = visit o.left, collector
499
+ collector << " NOT LIKE "
500
+ collector = visit o.right, collector
501
+ if o.escape
502
+ collector << " ESCAPE "
503
+ visit o.escape, collector
504
+ else
505
+ collector
506
+ end
507
+ end
508
+
509
+ def visit_Arel_Nodes_JoinSource(o, collector)
510
+ if o.left
511
+ collector = visit o.left, collector
512
+ end
513
+ if o.right.any?
514
+ collector << " " if o.left
515
+ collector = inject_join o.right, collector, " "
516
+ end
517
+ collector
518
+ end
519
+
520
+ def visit_Arel_Nodes_Regexp(o, collector)
521
+ raise NotImplementedError, "~ not implemented for this db"
522
+ end
523
+
524
+ def visit_Arel_Nodes_NotRegexp(o, collector)
525
+ raise NotImplementedError, "!~ not implemented for this db"
526
+ end
527
+
528
+ def visit_Arel_Nodes_StringJoin(o, collector)
529
+ visit o.left, collector
530
+ end
531
+
532
+ def visit_Arel_Nodes_FullOuterJoin(o, collector)
533
+ collector << "FULL OUTER JOIN "
534
+ collector = visit o.left, collector
535
+ collector << " "
536
+ visit o.right, collector
537
+ end
538
+
539
+ def visit_Arel_Nodes_OuterJoin(o, collector)
540
+ collector << "LEFT OUTER JOIN "
541
+ collector = visit o.left, collector
542
+ collector << " "
543
+ visit o.right, collector
544
+ end
545
+
546
+ def visit_Arel_Nodes_RightOuterJoin(o, collector)
547
+ collector << "RIGHT OUTER JOIN "
548
+ collector = visit o.left, collector
549
+ collector << " "
550
+ visit o.right, collector
551
+ end
552
+
553
+ def visit_Arel_Nodes_InnerJoin(o, collector)
554
+ collector << "INNER JOIN "
555
+ collector = visit o.left, collector
556
+ if o.right
557
+ collector << " "
558
+ visit(o.right, collector)
559
+ else
560
+ collector
561
+ end
562
+ end
563
+
564
+ def visit_Arel_Nodes_On(o, collector)
565
+ collector << "ON "
566
+ visit o.expr, collector
567
+ end
568
+
569
+ def visit_Arel_Nodes_Not(o, collector)
570
+ collector << "NOT ("
571
+ visit(o.expr, collector) << ")"
572
+ end
573
+
574
+ def visit_Arel_Table(o, collector)
575
+ if Arel::Nodes::Node === o.name
576
+ visit o.name, collector
577
+ else
578
+ collector << quote_table_name(o.name)
579
+ end
580
+
581
+ if o.table_alias
582
+ collector << " " << quote_table_name(o.table_alias)
583
+ end
584
+
585
+ collector
586
+ end
587
+
588
+ def visit_Arel_Nodes_In(o, collector)
589
+ attr, values = o.left, o.right
590
+
591
+ if Array === values
592
+ collector.preparable = false
593
+
594
+ unless values.empty?
595
+ values.delete_if { |value| unboundable?(value) }
596
+ end
597
+
598
+ return collector << "1=0" if values.empty?
599
+ end
600
+
601
+ visit(attr, collector) << " IN ("
602
+ visit(values, collector) << ")"
603
+ end
604
+
605
+ def visit_Arel_Nodes_NotIn(o, collector)
606
+ attr, values = o.left, o.right
607
+
608
+ if Array === values
609
+ collector.preparable = false
610
+
611
+ unless values.empty?
612
+ values.delete_if { |value| unboundable?(value) }
613
+ end
614
+
615
+ return collector << "1=1" if values.empty?
616
+ end
617
+
618
+ visit(attr, collector) << " NOT IN ("
619
+ visit(values, collector) << ")"
620
+ end
621
+
622
+ def visit_Arel_Nodes_And(o, collector)
623
+ inject_join o.children, collector, " AND "
624
+ end
625
+
626
+ def visit_Arel_Nodes_Or(o, collector)
627
+ inject_join o.children, collector, " OR "
628
+ end
629
+
630
+ def visit_Arel_Nodes_Assignment(o, collector)
631
+ case o.right
632
+ when Arel::Nodes::Node, Arel::Attributes::Attribute, ActiveModel::Attribute
633
+ collector = visit o.left, collector
634
+ collector << " = "
635
+ visit o.right, collector
636
+ else
637
+ collector = visit o.left, collector
638
+ collector << " = "
639
+ collector << quote(o.right).to_s
640
+ end
641
+ end
642
+
643
+ def visit_Arel_Nodes_Equality(o, collector)
644
+ right = o.right
645
+
646
+ return collector << "1=0" if unboundable?(right)
647
+
648
+ collector = visit o.left, collector
649
+
650
+ if right.nil?
651
+ collector << " IS NULL"
652
+ else
653
+ collector << " = "
654
+ visit right, collector
655
+ end
656
+ end
657
+
658
+ def visit_Arel_Nodes_IsNotDistinctFrom(o, collector)
659
+ if o.right.nil?
660
+ collector = visit o.left, collector
661
+ collector << " IS NULL"
662
+ else
663
+ collector = is_distinct_from(o, collector)
664
+ collector << " = 0"
665
+ end
666
+ end
667
+
668
+ def visit_Arel_Nodes_IsDistinctFrom(o, collector)
669
+ if o.right.nil?
670
+ collector = visit o.left, collector
671
+ collector << " IS NOT NULL"
672
+ else
673
+ collector = is_distinct_from(o, collector)
674
+ collector << " = 1"
675
+ end
676
+ end
677
+
678
+ def visit_Arel_Nodes_NotEqual(o, collector)
679
+ right = o.right
680
+
681
+ return collector << "1=1" if unboundable?(right)
682
+
683
+ collector = visit o.left, collector
684
+
685
+ if right.nil?
686
+ collector << " IS NOT NULL"
687
+ else
688
+ collector << " != "
689
+ visit right, collector
690
+ end
691
+ end
692
+
693
+ def visit_Arel_Nodes_As(o, collector)
694
+ collector = visit o.left, collector
695
+ collector << " AS "
696
+ visit o.right, collector
697
+ end
698
+
699
+ def visit_Arel_Nodes_Case(o, collector)
700
+ collector << "CASE "
701
+ if o.case
702
+ visit o.case, collector
703
+ collector << " "
704
+ end
705
+ o.conditions.each do |condition|
706
+ visit condition, collector
707
+ collector << " "
708
+ end
709
+ if o.default
710
+ visit o.default, collector
711
+ collector << " "
712
+ end
713
+ collector << "END"
714
+ end
715
+
716
+ def visit_Arel_Nodes_When(o, collector)
717
+ collector << "WHEN "
718
+ visit o.left, collector
719
+ collector << " THEN "
720
+ visit o.right, collector
721
+ end
722
+
723
+ def visit_Arel_Nodes_Else(o, collector)
724
+ collector << "ELSE "
725
+ visit o.expr, collector
726
+ end
727
+
728
+ def visit_Arel_Nodes_UnqualifiedColumn(o, collector)
729
+ collector << quote_column_name(o.name)
730
+ end
731
+
732
+ def visit_Arel_Nodes_Cte(o, collector)
733
+ collector << quote_table_name(o.name)
734
+ collector << " AS "
735
+
736
+ case o.materialized
737
+ when true
738
+ collector << "MATERIALIZED "
739
+ when false
740
+ collector << "NOT MATERIALIZED "
741
+ end
742
+
743
+ visit o.relation, collector
744
+ end
745
+
746
+ def visit_Arel_Attributes_Attribute(o, collector)
747
+ join_name = o.relation.table_alias || o.relation.name
748
+ collector << quote_table_name(join_name) << "." << quote_column_name(o.name)
749
+ end
750
+
751
+ BIND_BLOCK = proc { "?" }
752
+ private_constant :BIND_BLOCK
753
+
754
+ def bind_block; BIND_BLOCK; end
755
+
756
+ def visit_ActiveModel_Attribute(o, collector)
757
+ collector.add_bind(o, &bind_block)
758
+ end
759
+
760
+ def visit_Arel_Nodes_BindParam(o, collector)
761
+ collector.add_bind(o.value, &bind_block)
762
+ end
763
+
764
+ def visit_Arel_Nodes_SqlLiteral(o, collector)
765
+ collector.preparable = false
766
+ collector.retryable = o.retryable
767
+ collector << o.to_s
768
+ end
769
+
770
+ def visit_Arel_Nodes_BoundSqlLiteral(o, collector)
771
+ collector.retryable = false
772
+ bind_index = 0
773
+
774
+ new_bind = lambda do |value|
775
+ if Arel.arel_node?(value)
776
+ visit value, collector
777
+ elsif value.is_a?(Array)
778
+ if value.empty?
779
+ collector << @connection.quote(nil)
780
+ else
781
+ if value.none? { |v| Arel.arel_node?(v) }
782
+ collector.add_binds(value.map { |v| @connection.cast_bound_value(v) }, &bind_block)
783
+ else
784
+ value.each_with_index do |v, i|
785
+ collector << ", " unless i == 0
786
+ if Arel.arel_node?(v)
787
+ visit v, collector
788
+ else
789
+ collector.add_bind(@connection.cast_bound_value(v), &bind_block)
790
+ end
791
+ end
792
+ end
793
+ end
794
+ else
795
+ collector.add_bind(@connection.cast_bound_value(value), &bind_block)
796
+ end
797
+ end
798
+
799
+ if o.positional_binds
800
+ o.sql_with_placeholders.scan(/\?|([^?]+)/) do
801
+ if $1
802
+ collector << $1
803
+ else
804
+ value = o.positional_binds[bind_index]
805
+ bind_index += 1
806
+
807
+ new_bind.call(value)
808
+ end
809
+ end
810
+ else
811
+ o.sql_with_placeholders.scan(/:(?<!::)([a-zA-Z]\w*)|([^:]+|.)/) do
812
+ if $2
813
+ collector << $2
814
+ else
815
+ value = o.named_binds[$1.to_sym]
816
+ new_bind.call(value)
817
+ end
818
+ end
819
+ end
820
+
821
+ collector
822
+ end
823
+
824
+ def visit_Integer(o, collector)
825
+ collector << o.to_s
826
+ end
827
+
828
+ def unsupported(o, collector)
829
+ raise UnsupportedVisitError.new(o)
830
+ end
831
+
832
+ alias :visit_ActiveSupport_Multibyte_Chars :unsupported
833
+ alias :visit_ActiveSupport_StringInquirer :unsupported
834
+ alias :visit_BigDecimal :unsupported
835
+ alias :visit_Class :unsupported
836
+ alias :visit_Date :unsupported
837
+ alias :visit_DateTime :unsupported
838
+ alias :visit_FalseClass :unsupported
839
+ alias :visit_Float :unsupported
840
+ alias :visit_Hash :unsupported
841
+ alias :visit_NilClass :unsupported
842
+ alias :visit_String :unsupported
843
+ alias :visit_Symbol :unsupported
844
+ alias :visit_Time :unsupported
845
+ alias :visit_TrueClass :unsupported
846
+
847
+ def visit_Arel_Nodes_InfixOperation(o, collector)
848
+ collector = visit o.left, collector
849
+ collector << " #{o.operator} "
850
+ visit o.right, collector
851
+ end
852
+
853
+ def visit_Arel_Nodes_UnaryOperation(o, collector)
854
+ collector << " #{o.operator} "
855
+ visit o.expr, collector
856
+ end
857
+
858
+ def visit_Array(o, collector)
859
+ inject_join o, collector, ", "
860
+ end
861
+ alias :visit_Set :visit_Array
862
+
863
+ def visit_Arel_Nodes_Fragments(o, collector)
864
+ inject_join o.values, collector, " "
865
+ end
866
+
867
+ def quote(value)
868
+ return value if Arel::Nodes::SqlLiteral === value
869
+ @connection.quote value
870
+ end
871
+
872
+ def quote_table_name(name)
873
+ return name if Arel::Nodes::SqlLiteral === name
874
+ @connection.quote_table_name(name)
875
+ end
876
+
877
+ def quote_column_name(name)
878
+ return name if Arel::Nodes::SqlLiteral === name
879
+ @connection.quote_column_name(name)
880
+ end
881
+
882
+ def sanitize_as_sql_comment(value)
883
+ return value if Arel::Nodes::SqlLiteral === value
884
+ @connection.sanitize_as_sql_comment(value)
885
+ end
886
+
887
+ def collect_optimizer_hints(o, collector)
888
+ maybe_visit o.optimizer_hints, collector
889
+ end
890
+
891
+ def maybe_visit(thing, collector)
892
+ return collector unless thing
893
+ collector << " "
894
+ visit thing, collector
895
+ end
896
+
897
+ def inject_join(list, collector, join_str)
898
+ list.each_with_index do |x, i|
899
+ collector << join_str unless i == 0
900
+ collector = visit(x, collector)
901
+ end
902
+ collector
903
+ end
904
+
905
+ def unboundable?(value)
906
+ value.respond_to?(:unboundable?) && value.unboundable?
907
+ end
908
+
909
+ def has_join_sources?(o)
910
+ o.relation.is_a?(Nodes::JoinSource) && !o.relation.right.empty?
911
+ end
912
+
913
+ def has_limit_or_offset_or_orders?(o)
914
+ o.limit || o.offset || !o.orders.empty?
915
+ end
916
+
917
+ def has_group_by_and_having?(o)
918
+ !o.groups.empty? && !o.havings.empty?
919
+ end
920
+
921
+ # The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
922
+ # on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
923
+ # an UPDATE statement, so in the MySQL visitor we redefine this to do that.
924
+ def prepare_update_statement(o)
925
+ if o.key && (has_limit_or_offset_or_orders?(o) || has_join_sources?(o))
926
+ stmt = o.clone
927
+ stmt.limit = nil
928
+ stmt.offset = nil
929
+ stmt.orders = []
930
+ columns = Arel::Nodes::Grouping.new(o.key)
931
+ stmt.wheres = [Nodes::In.new(columns, [build_subselect(o.key, o)])]
932
+ stmt.relation = o.relation.left if has_join_sources?(o)
933
+ stmt.groups = o.groups unless o.groups.empty?
934
+ stmt.havings = o.havings unless o.havings.empty?
935
+ stmt
936
+ else
937
+ o
938
+ end
939
+ end
940
+ alias :prepare_delete_statement :prepare_update_statement
941
+
942
+ # FIXME: we should probably have a 2-pass visitor for this
943
+ def build_subselect(key, o)
944
+ stmt = Nodes::SelectStatement.new
945
+ core = stmt.cores.first
946
+ core.froms = o.relation
947
+ core.wheres = o.wheres
948
+ core.projections = [key]
949
+ core.groups = o.groups unless o.groups.empty?
950
+ core.havings = o.havings unless o.havings.empty?
951
+ stmt.limit = o.limit
952
+ stmt.offset = o.offset
953
+ stmt.orders = o.orders
954
+ stmt
955
+ end
956
+
957
+ def infix_value(o, collector, value)
958
+ collector = visit o.left, collector
959
+ collector << value
960
+ visit o.right, collector
961
+ end
962
+
963
+ def infix_value_with_paren(o, collector, value, suppress_parens = false)
964
+ collector << "( " unless suppress_parens
965
+ collector = if o.left.class == o.class
966
+ infix_value_with_paren(o.left, collector, value, true)
967
+ else
968
+ grouping_parentheses o.left, collector, false
969
+ end
970
+ collector << value
971
+ collector = if o.right.class == o.class
972
+ infix_value_with_paren(o.right, collector, value, true)
973
+ else
974
+ grouping_parentheses o.right, collector, false
975
+ end
976
+ collector << " )" unless suppress_parens
977
+ collector
978
+ end
979
+
980
+ # Used by some visitors to enclose select queries in parentheses
981
+ def grouping_parentheses(o, collector, always_wrap_selects = true)
982
+ if o.is_a?(Nodes::SelectStatement) && (always_wrap_selects || require_parentheses?(o))
983
+ collector << "("
984
+ visit o, collector
985
+ collector << ")"
986
+ collector
987
+ else
988
+ visit o, collector
989
+ end
990
+ end
991
+
992
+ def require_parentheses?(o)
993
+ !o.orders.empty? || o.limit || o.offset
994
+ end
995
+
996
+ def aggregate(name, o, collector)
997
+ collector << "#{name}("
998
+ if o.distinct
999
+ collector << "DISTINCT "
1000
+ end
1001
+ collector = inject_join(o.expressions, collector, ", ") << ")"
1002
+ if o.alias
1003
+ collector << " AS "
1004
+ visit o.alias, collector
1005
+ else
1006
+ collector
1007
+ end
1008
+ end
1009
+
1010
+ def is_distinct_from(o, collector)
1011
+ collector << "CASE WHEN "
1012
+ collector = visit o.left, collector
1013
+ collector << " = "
1014
+ collector = visit o.right, collector
1015
+ collector << " OR ("
1016
+ collector = visit o.left, collector
1017
+ collector << " IS NULL AND "
1018
+ collector = visit o.right, collector
1019
+ collector << " IS NULL)"
1020
+ collector << " THEN 0 ELSE 1 END"
1021
+ end
1022
+
1023
+ def collect_ctes(children, collector)
1024
+ children.each_with_index do |child, i|
1025
+ collector << ", " unless i == 0
1026
+ visit child.to_cte, collector
1027
+ end
1028
+
1029
+ collector
1030
+ end
1031
+ end
1032
+ end
1033
+ end