activerecord 6.0.0

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 (340) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1013 -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.rb +195 -0
  8. data/lib/active_record/aggregations.rb +285 -0
  9. data/lib/active_record/association_relation.rb +40 -0
  10. data/lib/active_record/associations.rb +1865 -0
  11. data/lib/active_record/associations/alias_tracker.rb +81 -0
  12. data/lib/active_record/associations/association.rb +332 -0
  13. data/lib/active_record/associations/association_scope.rb +166 -0
  14. data/lib/active_record/associations/belongs_to_association.rb +124 -0
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +36 -0
  16. data/lib/active_record/associations/builder/association.rb +136 -0
  17. data/lib/active_record/associations/builder/belongs_to.rb +130 -0
  18. data/lib/active_record/associations/builder/collection_association.rb +72 -0
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +114 -0
  20. data/lib/active_record/associations/builder/has_many.rb +19 -0
  21. data/lib/active_record/associations/builder/has_one.rb +64 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +44 -0
  23. data/lib/active_record/associations/collection_association.rb +498 -0
  24. data/lib/active_record/associations/collection_proxy.rb +1128 -0
  25. data/lib/active_record/associations/foreign_association.rb +20 -0
  26. data/lib/active_record/associations/has_many_association.rb +136 -0
  27. data/lib/active_record/associations/has_many_through_association.rb +220 -0
  28. data/lib/active_record/associations/has_one_association.rb +118 -0
  29. data/lib/active_record/associations/has_one_through_association.rb +45 -0
  30. data/lib/active_record/associations/join_dependency.rb +258 -0
  31. data/lib/active_record/associations/join_dependency/join_association.rb +80 -0
  32. data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
  33. data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
  34. data/lib/active_record/associations/preloader.rb +201 -0
  35. data/lib/active_record/associations/preloader/association.rb +133 -0
  36. data/lib/active_record/associations/preloader/through_association.rb +116 -0
  37. data/lib/active_record/associations/singular_association.rb +59 -0
  38. data/lib/active_record/associations/through_association.rb +121 -0
  39. data/lib/active_record/attribute_assignment.rb +85 -0
  40. data/lib/active_record/attribute_decorators.rb +90 -0
  41. data/lib/active_record/attribute_methods.rb +420 -0
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +81 -0
  43. data/lib/active_record/attribute_methods/dirty.rb +221 -0
  44. data/lib/active_record/attribute_methods/primary_key.rb +136 -0
  45. data/lib/active_record/attribute_methods/query.rb +41 -0
  46. data/lib/active_record/attribute_methods/read.rb +47 -0
  47. data/lib/active_record/attribute_methods/serialization.rb +90 -0
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +91 -0
  49. data/lib/active_record/attribute_methods/write.rb +61 -0
  50. data/lib/active_record/attributes.rb +279 -0
  51. data/lib/active_record/autosave_association.rb +508 -0
  52. data/lib/active_record/base.rb +328 -0
  53. data/lib/active_record/callbacks.rb +339 -0
  54. data/lib/active_record/coders/json.rb +15 -0
  55. data/lib/active_record/coders/yaml_column.rb +50 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1165 -0
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +85 -0
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +512 -0
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +154 -0
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +251 -0
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +713 -0
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +93 -0
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1475 -0
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +323 -0
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +761 -0
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +821 -0
  69. data/lib/active_record/connection_adapters/column.rb +95 -0
  70. data/lib/active_record/connection_adapters/connection_specification.rb +297 -0
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +146 -0
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +182 -0
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +113 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +205 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +222 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +776 -0
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +949 -0
  117. data/lib/active_record/connection_adapters/schema_cache.rb +141 -0
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
  119. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +103 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +137 -0
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +557 -0
  127. data/lib/active_record/connection_adapters/statement_pool.rb +61 -0
  128. data/lib/active_record/connection_handling.rb +267 -0
  129. data/lib/active_record/core.rb +599 -0
  130. data/lib/active_record/counter_cache.rb +193 -0
  131. data/lib/active_record/database_configurations.rb +233 -0
  132. data/lib/active_record/database_configurations/database_config.rb +37 -0
  133. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  134. data/lib/active_record/database_configurations/url_config.rb +79 -0
  135. data/lib/active_record/define_callbacks.rb +22 -0
  136. data/lib/active_record/dynamic_matchers.rb +122 -0
  137. data/lib/active_record/enum.rb +274 -0
  138. data/lib/active_record/errors.rb +388 -0
  139. data/lib/active_record/explain.rb +50 -0
  140. data/lib/active_record/explain_registry.rb +32 -0
  141. data/lib/active_record/explain_subscriber.rb +34 -0
  142. data/lib/active_record/fixture_set/file.rb +82 -0
  143. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  144. data/lib/active_record/fixture_set/render_context.rb +17 -0
  145. data/lib/active_record/fixture_set/table_row.rb +153 -0
  146. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  147. data/lib/active_record/fixtures.rb +738 -0
  148. data/lib/active_record/gem_version.rb +17 -0
  149. data/lib/active_record/inheritance.rb +293 -0
  150. data/lib/active_record/insert_all.rb +179 -0
  151. data/lib/active_record/integration.rb +207 -0
  152. data/lib/active_record/internal_metadata.rb +53 -0
  153. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  154. data/lib/active_record/locale/en.yml +48 -0
  155. data/lib/active_record/locking/optimistic.rb +197 -0
  156. data/lib/active_record/locking/pessimistic.rb +89 -0
  157. data/lib/active_record/log_subscriber.rb +118 -0
  158. data/lib/active_record/middleware/database_selector.rb +75 -0
  159. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  160. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  161. data/lib/active_record/migration.rb +1397 -0
  162. data/lib/active_record/migration/command_recorder.rb +284 -0
  163. data/lib/active_record/migration/compatibility.rb +244 -0
  164. data/lib/active_record/migration/join_table.rb +17 -0
  165. data/lib/active_record/model_schema.rb +542 -0
  166. data/lib/active_record/nested_attributes.rb +600 -0
  167. data/lib/active_record/no_touching.rb +65 -0
  168. data/lib/active_record/null_relation.rb +68 -0
  169. data/lib/active_record/persistence.rb +967 -0
  170. data/lib/active_record/query_cache.rb +52 -0
  171. data/lib/active_record/querying.rb +82 -0
  172. data/lib/active_record/railtie.rb +263 -0
  173. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  174. data/lib/active_record/railties/console_sandbox.rb +7 -0
  175. data/lib/active_record/railties/controller_runtime.rb +51 -0
  176. data/lib/active_record/railties/databases.rake +527 -0
  177. data/lib/active_record/readonly_attributes.rb +24 -0
  178. data/lib/active_record/reflection.rb +1042 -0
  179. data/lib/active_record/relation.rb +859 -0
  180. data/lib/active_record/relation/batches.rb +290 -0
  181. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  182. data/lib/active_record/relation/calculations.rb +424 -0
  183. data/lib/active_record/relation/delegation.rb +130 -0
  184. data/lib/active_record/relation/finder_methods.rb +552 -0
  185. data/lib/active_record/relation/from_clause.rb +26 -0
  186. data/lib/active_record/relation/merger.rb +184 -0
  187. data/lib/active_record/relation/predicate_builder.rb +150 -0
  188. data/lib/active_record/relation/predicate_builder/array_handler.rb +49 -0
  189. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  190. data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
  191. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  192. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  193. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  194. data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
  195. data/lib/active_record/relation/query_attribute.rb +50 -0
  196. data/lib/active_record/relation/query_methods.rb +1359 -0
  197. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  198. data/lib/active_record/relation/spawn_methods.rb +77 -0
  199. data/lib/active_record/relation/where_clause.rb +190 -0
  200. data/lib/active_record/relation/where_clause_factory.rb +33 -0
  201. data/lib/active_record/result.rb +168 -0
  202. data/lib/active_record/runtime_registry.rb +24 -0
  203. data/lib/active_record/sanitization.rb +214 -0
  204. data/lib/active_record/schema.rb +61 -0
  205. data/lib/active_record/schema_dumper.rb +270 -0
  206. data/lib/active_record/schema_migration.rb +60 -0
  207. data/lib/active_record/scoping.rb +106 -0
  208. data/lib/active_record/scoping/default.rb +151 -0
  209. data/lib/active_record/scoping/named.rb +217 -0
  210. data/lib/active_record/secure_token.rb +40 -0
  211. data/lib/active_record/serialization.rb +22 -0
  212. data/lib/active_record/statement_cache.rb +148 -0
  213. data/lib/active_record/store.rb +290 -0
  214. data/lib/active_record/suppressor.rb +61 -0
  215. data/lib/active_record/table_metadata.rb +75 -0
  216. data/lib/active_record/tasks/database_tasks.rb +506 -0
  217. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  218. data/lib/active_record/tasks/postgresql_database_tasks.rb +141 -0
  219. data/lib/active_record/tasks/sqlite_database_tasks.rb +77 -0
  220. data/lib/active_record/test_databases.rb +23 -0
  221. data/lib/active_record/test_fixtures.rb +224 -0
  222. data/lib/active_record/timestamp.rb +167 -0
  223. data/lib/active_record/touch_later.rb +66 -0
  224. data/lib/active_record/transactions.rb +493 -0
  225. data/lib/active_record/translation.rb +24 -0
  226. data/lib/active_record/type.rb +78 -0
  227. data/lib/active_record/type/adapter_specific_registry.rb +129 -0
  228. data/lib/active_record/type/date.rb +9 -0
  229. data/lib/active_record/type/date_time.rb +9 -0
  230. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  231. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  232. data/lib/active_record/type/internal/timezone.rb +17 -0
  233. data/lib/active_record/type/json.rb +30 -0
  234. data/lib/active_record/type/serialized.rb +71 -0
  235. data/lib/active_record/type/text.rb +11 -0
  236. data/lib/active_record/type/time.rb +21 -0
  237. data/lib/active_record/type/type_map.rb +62 -0
  238. data/lib/active_record/type/unsigned_integer.rb +17 -0
  239. data/lib/active_record/type_caster.rb +9 -0
  240. data/lib/active_record/type_caster/connection.rb +34 -0
  241. data/lib/active_record/type_caster/map.rb +20 -0
  242. data/lib/active_record/validations.rb +94 -0
  243. data/lib/active_record/validations/absence.rb +25 -0
  244. data/lib/active_record/validations/associated.rb +60 -0
  245. data/lib/active_record/validations/length.rb +26 -0
  246. data/lib/active_record/validations/presence.rb +68 -0
  247. data/lib/active_record/validations/uniqueness.rb +226 -0
  248. data/lib/active_record/version.rb +10 -0
  249. data/lib/arel.rb +51 -0
  250. data/lib/arel/alias_predication.rb +9 -0
  251. data/lib/arel/attributes.rb +22 -0
  252. data/lib/arel/attributes/attribute.rb +37 -0
  253. data/lib/arel/collectors/bind.rb +24 -0
  254. data/lib/arel/collectors/composite.rb +31 -0
  255. data/lib/arel/collectors/plain_string.rb +20 -0
  256. data/lib/arel/collectors/sql_string.rb +20 -0
  257. data/lib/arel/collectors/substitute_binds.rb +28 -0
  258. data/lib/arel/crud.rb +42 -0
  259. data/lib/arel/delete_manager.rb +18 -0
  260. data/lib/arel/errors.rb +9 -0
  261. data/lib/arel/expressions.rb +29 -0
  262. data/lib/arel/factory_methods.rb +49 -0
  263. data/lib/arel/insert_manager.rb +49 -0
  264. data/lib/arel/math.rb +45 -0
  265. data/lib/arel/nodes.rb +68 -0
  266. data/lib/arel/nodes/and.rb +32 -0
  267. data/lib/arel/nodes/ascending.rb +23 -0
  268. data/lib/arel/nodes/binary.rb +52 -0
  269. data/lib/arel/nodes/bind_param.rb +36 -0
  270. data/lib/arel/nodes/case.rb +55 -0
  271. data/lib/arel/nodes/casted.rb +50 -0
  272. data/lib/arel/nodes/comment.rb +29 -0
  273. data/lib/arel/nodes/count.rb +12 -0
  274. data/lib/arel/nodes/delete_statement.rb +45 -0
  275. data/lib/arel/nodes/descending.rb +23 -0
  276. data/lib/arel/nodes/equality.rb +18 -0
  277. data/lib/arel/nodes/extract.rb +24 -0
  278. data/lib/arel/nodes/false.rb +16 -0
  279. data/lib/arel/nodes/full_outer_join.rb +8 -0
  280. data/lib/arel/nodes/function.rb +44 -0
  281. data/lib/arel/nodes/grouping.rb +8 -0
  282. data/lib/arel/nodes/in.rb +8 -0
  283. data/lib/arel/nodes/infix_operation.rb +80 -0
  284. data/lib/arel/nodes/inner_join.rb +8 -0
  285. data/lib/arel/nodes/insert_statement.rb +37 -0
  286. data/lib/arel/nodes/join_source.rb +20 -0
  287. data/lib/arel/nodes/matches.rb +18 -0
  288. data/lib/arel/nodes/named_function.rb +23 -0
  289. data/lib/arel/nodes/node.rb +50 -0
  290. data/lib/arel/nodes/node_expression.rb +13 -0
  291. data/lib/arel/nodes/outer_join.rb +8 -0
  292. data/lib/arel/nodes/over.rb +15 -0
  293. data/lib/arel/nodes/regexp.rb +16 -0
  294. data/lib/arel/nodes/right_outer_join.rb +8 -0
  295. data/lib/arel/nodes/select_core.rb +67 -0
  296. data/lib/arel/nodes/select_statement.rb +41 -0
  297. data/lib/arel/nodes/sql_literal.rb +16 -0
  298. data/lib/arel/nodes/string_join.rb +11 -0
  299. data/lib/arel/nodes/table_alias.rb +27 -0
  300. data/lib/arel/nodes/terminal.rb +16 -0
  301. data/lib/arel/nodes/true.rb +16 -0
  302. data/lib/arel/nodes/unary.rb +45 -0
  303. data/lib/arel/nodes/unary_operation.rb +20 -0
  304. data/lib/arel/nodes/unqualified_column.rb +22 -0
  305. data/lib/arel/nodes/update_statement.rb +41 -0
  306. data/lib/arel/nodes/values_list.rb +9 -0
  307. data/lib/arel/nodes/window.rb +126 -0
  308. data/lib/arel/nodes/with.rb +11 -0
  309. data/lib/arel/order_predications.rb +13 -0
  310. data/lib/arel/predications.rb +257 -0
  311. data/lib/arel/select_manager.rb +271 -0
  312. data/lib/arel/table.rb +110 -0
  313. data/lib/arel/tree_manager.rb +72 -0
  314. data/lib/arel/update_manager.rb +34 -0
  315. data/lib/arel/visitors.rb +20 -0
  316. data/lib/arel/visitors/depth_first.rb +204 -0
  317. data/lib/arel/visitors/dot.rb +297 -0
  318. data/lib/arel/visitors/ibm_db.rb +34 -0
  319. data/lib/arel/visitors/informix.rb +62 -0
  320. data/lib/arel/visitors/mssql.rb +157 -0
  321. data/lib/arel/visitors/mysql.rb +83 -0
  322. data/lib/arel/visitors/oracle.rb +159 -0
  323. data/lib/arel/visitors/oracle12.rb +66 -0
  324. data/lib/arel/visitors/postgresql.rb +110 -0
  325. data/lib/arel/visitors/sqlite.rb +39 -0
  326. data/lib/arel/visitors/to_sql.rb +889 -0
  327. data/lib/arel/visitors/visitor.rb +46 -0
  328. data/lib/arel/visitors/where_sql.rb +23 -0
  329. data/lib/arel/window_predications.rb +9 -0
  330. data/lib/rails/generators/active_record.rb +19 -0
  331. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  332. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  333. data/lib/rails/generators/active_record/migration.rb +48 -0
  334. data/lib/rails/generators/active_record/migration/migration_generator.rb +75 -0
  335. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  336. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
  337. data/lib/rails/generators/active_record/model/model_generator.rb +49 -0
  338. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  339. data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
  340. metadata +415 -0
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class Relation
5
+ class FromClause # :nodoc:
6
+ attr_reader :value, :name
7
+
8
+ def initialize(value, name)
9
+ @value = value
10
+ @name = name
11
+ end
12
+
13
+ def merge(other)
14
+ self
15
+ end
16
+
17
+ def empty?
18
+ value.nil?
19
+ end
20
+
21
+ def self.empty
22
+ @empty ||= new(nil, nil)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/hash/keys"
4
+
5
+ module ActiveRecord
6
+ class Relation
7
+ class HashMerger # :nodoc:
8
+ attr_reader :relation, :hash
9
+
10
+ def initialize(relation, hash)
11
+ hash.assert_valid_keys(*Relation::VALUE_METHODS)
12
+
13
+ @relation = relation
14
+ @hash = hash
15
+ end
16
+
17
+ def merge #:nodoc:
18
+ Merger.new(relation, other).merge
19
+ end
20
+
21
+ # Applying values to a relation has some side effects. E.g.
22
+ # interpolation might take place for where values. So we should
23
+ # build a relation to merge in rather than directly merging
24
+ # the values.
25
+ def other
26
+ other = Relation.create(
27
+ relation.klass,
28
+ table: relation.table,
29
+ predicate_builder: relation.predicate_builder
30
+ )
31
+ hash.each { |k, v|
32
+ if k == :joins
33
+ if Hash === v
34
+ other.joins!(v)
35
+ else
36
+ other.joins!(*v)
37
+ end
38
+ elsif k == :select
39
+ other._select!(v)
40
+ else
41
+ other.send("#{k}!", v)
42
+ end
43
+ }
44
+ other
45
+ end
46
+ end
47
+
48
+ class Merger # :nodoc:
49
+ attr_reader :relation, :values, :other
50
+
51
+ def initialize(relation, other)
52
+ @relation = relation
53
+ @values = other.values
54
+ @other = other
55
+ end
56
+
57
+ NORMAL_VALUES = Relation::VALUE_METHODS -
58
+ Relation::CLAUSE_METHODS -
59
+ [:includes, :preload, :joins, :left_outer_joins, :order, :reverse_order, :lock, :create_with, :reordering] # :nodoc:
60
+
61
+ def normal_values
62
+ NORMAL_VALUES
63
+ end
64
+
65
+ def merge
66
+ normal_values.each do |name|
67
+ value = values[name]
68
+ # The unless clause is here mostly for performance reasons (since the `send` call might be moderately
69
+ # expensive), most of the time the value is going to be `nil` or `.blank?`, the only catch is that
70
+ # `false.blank?` returns `true`, so there needs to be an extra check so that explicit `false` values
71
+ # don't fall through the cracks.
72
+ unless value.nil? || (value.blank? && false != value)
73
+ if name == :select
74
+ relation._select!(*value)
75
+ else
76
+ relation.send("#{name}!", *value)
77
+ end
78
+ end
79
+ end
80
+
81
+ merge_multi_values
82
+ merge_single_values
83
+ merge_clauses
84
+ merge_preloads
85
+ merge_joins
86
+ merge_outer_joins
87
+
88
+ relation
89
+ end
90
+
91
+ private
92
+
93
+ def merge_preloads
94
+ return if other.preload_values.empty? && other.includes_values.empty?
95
+
96
+ if other.klass == relation.klass
97
+ relation.preload!(*other.preload_values) unless other.preload_values.empty?
98
+ relation.includes!(other.includes_values) unless other.includes_values.empty?
99
+ else
100
+ reflection = relation.klass.reflect_on_all_associations.find do |r|
101
+ r.class_name == other.klass.name
102
+ end || return
103
+
104
+ unless other.preload_values.empty?
105
+ relation.preload! reflection.name => other.preload_values
106
+ end
107
+
108
+ unless other.includes_values.empty?
109
+ relation.includes! reflection.name => other.includes_values
110
+ end
111
+ end
112
+ end
113
+
114
+ def merge_joins
115
+ return if other.joins_values.blank?
116
+
117
+ if other.klass == relation.klass
118
+ relation.joins!(*other.joins_values)
119
+ else
120
+ associations, others = other.joins_values.partition do |join|
121
+ case join
122
+ when Hash, Symbol, Array; true
123
+ end
124
+ end
125
+
126
+ join_dependency = other.construct_join_dependency(
127
+ associations, Arel::Nodes::InnerJoin
128
+ )
129
+ relation.joins!(join_dependency, *others)
130
+ end
131
+ end
132
+
133
+ def merge_outer_joins
134
+ return if other.left_outer_joins_values.blank?
135
+
136
+ if other.klass == relation.klass
137
+ relation.left_outer_joins!(*other.left_outer_joins_values)
138
+ else
139
+ associations = other.left_outer_joins_values
140
+ join_dependency = other.construct_join_dependency(
141
+ associations, Arel::Nodes::OuterJoin
142
+ )
143
+ relation.joins!(join_dependency)
144
+ end
145
+ end
146
+
147
+ def merge_multi_values
148
+ if other.reordering_value
149
+ # override any order specified in the original relation
150
+ relation.reorder!(*other.order_values)
151
+ elsif other.order_values.any?
152
+ # merge in order_values from relation
153
+ relation.order!(*other.order_values)
154
+ end
155
+
156
+ extensions = other.extensions - relation.extensions
157
+ relation.extending!(*extensions) if extensions.any?
158
+ end
159
+
160
+ def merge_single_values
161
+ relation.lock_value ||= other.lock_value if other.lock_value
162
+
163
+ unless other.create_with_value.blank?
164
+ relation.create_with_value = (relation.create_with_value || {}).merge(other.create_with_value)
165
+ end
166
+ end
167
+
168
+ def merge_clauses
169
+ relation.from_clause = other.from_clause if replace_from_clause?
170
+
171
+ where_clause = relation.where_clause.merge(other.where_clause)
172
+ relation.where_clause = where_clause unless where_clause.empty?
173
+
174
+ having_clause = relation.having_clause.merge(other.having_clause)
175
+ relation.having_clause = having_clause unless having_clause.empty?
176
+ end
177
+
178
+ def replace_from_clause?
179
+ relation.from_clause.empty? && !other.from_clause.empty? &&
180
+ relation.klass.base_class == other.klass.base_class
181
+ end
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class PredicateBuilder # :nodoc:
5
+ delegate :resolve_column_aliases, to: :table
6
+
7
+ def initialize(table)
8
+ @table = table
9
+ @handlers = []
10
+
11
+ register_handler(BasicObject, BasicObjectHandler.new(self))
12
+ register_handler(Base, BaseHandler.new(self))
13
+ register_handler(Range, RangeHandler.new(self))
14
+ register_handler(Relation, RelationHandler.new)
15
+ register_handler(Array, ArrayHandler.new(self))
16
+ register_handler(Set, ArrayHandler.new(self))
17
+ end
18
+
19
+ def build_from_hash(attributes)
20
+ attributes = convert_dot_notation_to_hash(attributes)
21
+ expand_from_hash(attributes)
22
+ end
23
+
24
+ def self.references(attributes)
25
+ attributes.map do |key, value|
26
+ if value.is_a?(Hash)
27
+ key
28
+ else
29
+ key = key.to_s
30
+ key.split(".").first if key.include?(".")
31
+ end
32
+ end.compact
33
+ end
34
+
35
+ # Define how a class is converted to Arel nodes when passed to +where+.
36
+ # The handler can be any object that responds to +call+, and will be used
37
+ # for any value that +===+ the class given. For example:
38
+ #
39
+ # MyCustomDateRange = Struct.new(:start, :end)
40
+ # handler = proc do |column, range|
41
+ # Arel::Nodes::Between.new(column,
42
+ # Arel::Nodes::And.new([range.start, range.end])
43
+ # )
44
+ # end
45
+ # ActiveRecord::PredicateBuilder.new("users").register_handler(MyCustomDateRange, handler)
46
+ def register_handler(klass, handler)
47
+ @handlers.unshift([klass, handler])
48
+ end
49
+
50
+ def build(attribute, value)
51
+ if table.type(attribute.name).force_equality?(value)
52
+ bind = build_bind_attribute(attribute.name, value)
53
+ attribute.eq(bind)
54
+ else
55
+ handler_for(value).call(attribute, value)
56
+ end
57
+ end
58
+
59
+ def build_bind_attribute(column_name, value)
60
+ attr = Relation::QueryAttribute.new(column_name.to_s, value, table.type(column_name))
61
+ Arel::Nodes::BindParam.new(attr)
62
+ end
63
+
64
+ protected
65
+ def expand_from_hash(attributes)
66
+ return ["1=0"] if attributes.empty?
67
+
68
+ attributes.flat_map do |key, value|
69
+ if value.is_a?(Hash) && !table.has_column?(key)
70
+ associated_predicate_builder(key).expand_from_hash(value)
71
+ elsif table.associated_with?(key)
72
+ # Find the foreign key when using queries such as:
73
+ # Post.where(author: author)
74
+ #
75
+ # For polymorphic relationships, find the foreign key and type:
76
+ # PriceEstimate.where(estimate_of: treasure)
77
+ associated_table = table.associated_table(key)
78
+ if associated_table.polymorphic_association?
79
+ case value.is_a?(Array) ? value.first : value
80
+ when Base, Relation
81
+ value = [value] unless value.is_a?(Array)
82
+ klass = PolymorphicArrayValue
83
+ end
84
+ end
85
+
86
+ klass ||= AssociationQueryValue
87
+ queries = klass.new(associated_table, value).queries.map do |query|
88
+ expand_from_hash(query).reduce(&:and)
89
+ end
90
+ queries.reduce(&:or)
91
+ elsif table.aggregated_with?(key)
92
+ mapping = table.reflect_on_aggregation(key).mapping
93
+ values = value.nil? ? [nil] : Array.wrap(value)
94
+ if mapping.length == 1 || values.empty?
95
+ column_name, aggr_attr = mapping.first
96
+ values = values.map do |object|
97
+ object.respond_to?(aggr_attr) ? object.public_send(aggr_attr) : object
98
+ end
99
+ build(table.arel_attribute(column_name), values)
100
+ else
101
+ queries = values.map do |object|
102
+ mapping.map do |field_attr, aggregate_attr|
103
+ build(table.arel_attribute(field_attr), object.try!(aggregate_attr))
104
+ end.reduce(&:and)
105
+ end
106
+ queries.reduce(&:or)
107
+ end
108
+ else
109
+ build(table.arel_attribute(key), value)
110
+ end
111
+ end
112
+ end
113
+
114
+ private
115
+ attr_reader :table
116
+
117
+ def associated_predicate_builder(association_name)
118
+ self.class.new(table.associated_table(association_name))
119
+ end
120
+
121
+ def convert_dot_notation_to_hash(attributes)
122
+ dot_notation = attributes.select do |k, v|
123
+ k.include?(".") && !v.is_a?(Hash)
124
+ end
125
+
126
+ dot_notation.each_key do |key|
127
+ table_name, column_name = key.split(".")
128
+ value = attributes.delete(key)
129
+ attributes[table_name] ||= {}
130
+
131
+ attributes[table_name] = attributes[table_name].merge(column_name => value)
132
+ end
133
+
134
+ attributes
135
+ end
136
+
137
+ def handler_for(object)
138
+ @handlers.detect { |klass, _| klass === object }.last
139
+ end
140
+ end
141
+ end
142
+
143
+ require "active_record/relation/predicate_builder/array_handler"
144
+ require "active_record/relation/predicate_builder/base_handler"
145
+ require "active_record/relation/predicate_builder/basic_object_handler"
146
+ require "active_record/relation/predicate_builder/range_handler"
147
+ require "active_record/relation/predicate_builder/relation_handler"
148
+
149
+ require "active_record/relation/predicate_builder/association_query_value"
150
+ require "active_record/relation/predicate_builder/polymorphic_array_value"
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/array/extract"
4
+
5
+ module ActiveRecord
6
+ class PredicateBuilder
7
+ class ArrayHandler # :nodoc:
8
+ def initialize(predicate_builder)
9
+ @predicate_builder = predicate_builder
10
+ end
11
+
12
+ def call(attribute, value)
13
+ return attribute.in([]) if value.empty?
14
+
15
+ values = value.map { |x| x.is_a?(Base) ? x.id : x }
16
+ nils = values.extract!(&:nil?)
17
+ ranges = values.extract! { |v| v.is_a?(Range) }
18
+
19
+ values_predicate =
20
+ case values.length
21
+ when 0 then NullPredicate
22
+ when 1 then predicate_builder.build(attribute, values.first)
23
+ else
24
+ values.map! do |v|
25
+ predicate_builder.build_bind_attribute(attribute.name, v)
26
+ end
27
+ values.empty? ? NullPredicate : attribute.in(values)
28
+ end
29
+
30
+ unless nils.empty?
31
+ values_predicate = values_predicate.or(predicate_builder.build(attribute, nil))
32
+ end
33
+
34
+ array_predicates = ranges.map { |range| predicate_builder.build(attribute, range) }
35
+ array_predicates.unshift(values_predicate)
36
+ array_predicates.inject(&:or)
37
+ end
38
+
39
+ private
40
+ attr_reader :predicate_builder
41
+
42
+ module NullPredicate # :nodoc:
43
+ def self.or(other)
44
+ other
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ class PredicateBuilder
5
+ class AssociationQueryValue # :nodoc:
6
+ def initialize(associated_table, value)
7
+ @associated_table = associated_table
8
+ @value = value
9
+ end
10
+
11
+ def queries
12
+ [associated_table.association_join_foreign_key.to_s => ids]
13
+ end
14
+
15
+ private
16
+ attr_reader :associated_table, :value
17
+
18
+ def ids
19
+ case value
20
+ when Relation
21
+ value.select_values.empty? ? value.select(primary_key) : value
22
+ when Array
23
+ value.map { |v| convert_to_id(v) }
24
+ else
25
+ convert_to_id(value)
26
+ end
27
+ end
28
+
29
+ def primary_key
30
+ associated_table.association_join_primary_key
31
+ end
32
+
33
+ def convert_to_id(value)
34
+ case value
35
+ when Base
36
+ value._read_attribute(primary_key)
37
+ else
38
+ value
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end