activerecord 5.2.3 → 6.1.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 (316) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +898 -532
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +7 -5
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record/aggregations.rb +5 -4
  7. data/lib/active_record/association_relation.rb +22 -12
  8. data/lib/active_record/associations/alias_tracker.rb +19 -16
  9. data/lib/active_record/associations/association.rb +95 -42
  10. data/lib/active_record/associations/association_scope.rb +21 -21
  11. data/lib/active_record/associations/belongs_to_association.rb +50 -46
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -5
  13. data/lib/active_record/associations/builder/association.rb +23 -21
  14. data/lib/active_record/associations/builder/belongs_to.rb +29 -59
  15. data/lib/active_record/associations/builder/collection_association.rb +10 -19
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
  17. data/lib/active_record/associations/builder/has_many.rb +8 -2
  18. data/lib/active_record/associations/builder/has_one.rb +33 -2
  19. data/lib/active_record/associations/builder/singular_association.rb +3 -1
  20. data/lib/active_record/associations/collection_association.rb +31 -29
  21. data/lib/active_record/associations/collection_proxy.rb +25 -21
  22. data/lib/active_record/associations/foreign_association.rb +20 -0
  23. data/lib/active_record/associations/has_many_association.rb +26 -13
  24. data/lib/active_record/associations/has_many_through_association.rb +27 -28
  25. data/lib/active_record/associations/has_one_association.rb +43 -31
  26. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  27. data/lib/active_record/associations/join_dependency/join_association.rb +54 -12
  28. data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
  29. data/lib/active_record/associations/join_dependency.rb +91 -60
  30. data/lib/active_record/associations/preloader/association.rb +71 -43
  31. data/lib/active_record/associations/preloader/through_association.rb +49 -40
  32. data/lib/active_record/associations/preloader.rb +48 -35
  33. data/lib/active_record/associations/singular_association.rb +3 -17
  34. data/lib/active_record/associations/through_association.rb +1 -1
  35. data/lib/active_record/associations.rb +133 -25
  36. data/lib/active_record/attribute_assignment.rb +17 -19
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
  38. data/lib/active_record/attribute_methods/dirty.rb +101 -40
  39. data/lib/active_record/attribute_methods/primary_key.rb +20 -25
  40. data/lib/active_record/attribute_methods/query.rb +4 -8
  41. data/lib/active_record/attribute_methods/read.rb +14 -56
  42. data/lib/active_record/attribute_methods/serialization.rb +12 -7
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  44. data/lib/active_record/attribute_methods/write.rb +18 -34
  45. data/lib/active_record/attribute_methods.rb +81 -143
  46. data/lib/active_record/attributes.rb +45 -8
  47. data/lib/active_record/autosave_association.rb +76 -47
  48. data/lib/active_record/base.rb +4 -17
  49. data/lib/active_record/callbacks.rb +158 -43
  50. data/lib/active_record/coders/yaml_column.rb +1 -2
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +293 -132
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +21 -17
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +203 -90
  59. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
  60. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +381 -146
  61. data/lib/active_record/connection_adapters/abstract/transaction.rb +155 -68
  62. data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -98
  63. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
  64. data/lib/active_record/connection_adapters/column.rb +30 -12
  65. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  66. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  67. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  68. data/lib/active_record/connection_adapters/mysql/database_statements.rb +86 -32
  69. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  70. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  71. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
  72. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
  73. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  74. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
  75. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
  76. data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
  77. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  78. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  79. data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
  80. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +38 -54
  81. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  84. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  85. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  92. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
  94. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
  95. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  96. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  97. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
  98. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  99. data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
  100. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  101. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
  102. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  103. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  104. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
  105. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
  106. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  107. data/lib/active_record/connection_adapters/postgresql_adapter.rb +222 -112
  108. data/lib/active_record/connection_adapters/schema_cache.rb +127 -21
  109. data/lib/active_record/connection_adapters/sql_type_metadata.rb +19 -6
  110. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
  111. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
  112. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  113. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
  114. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +175 -187
  115. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  116. data/lib/active_record/connection_adapters.rb +50 -0
  117. data/lib/active_record/connection_handling.rb +285 -33
  118. data/lib/active_record/core.rb +308 -100
  119. data/lib/active_record/counter_cache.rb +8 -30
  120. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  121. data/lib/active_record/database_configurations/database_config.rb +80 -0
  122. data/lib/active_record/database_configurations/hash_config.rb +96 -0
  123. data/lib/active_record/database_configurations/url_config.rb +53 -0
  124. data/lib/active_record/database_configurations.rb +272 -0
  125. data/lib/active_record/delegated_type.rb +209 -0
  126. data/lib/active_record/destroy_association_async_job.rb +36 -0
  127. data/lib/active_record/dynamic_matchers.rb +3 -4
  128. data/lib/active_record/enum.rb +71 -17
  129. data/lib/active_record/errors.rb +62 -19
  130. data/lib/active_record/explain.rb +10 -6
  131. data/lib/active_record/explain_subscriber.rb +1 -1
  132. data/lib/active_record/fixture_set/file.rb +10 -17
  133. data/lib/active_record/fixture_set/model_metadata.rb +32 -0
  134. data/lib/active_record/fixture_set/render_context.rb +17 -0
  135. data/lib/active_record/fixture_set/table_row.rb +152 -0
  136. data/lib/active_record/fixture_set/table_rows.rb +46 -0
  137. data/lib/active_record/fixtures.rb +197 -481
  138. data/lib/active_record/gem_version.rb +3 -3
  139. data/lib/active_record/inheritance.rb +53 -24
  140. data/lib/active_record/insert_all.rb +208 -0
  141. data/lib/active_record/integration.rb +67 -17
  142. data/lib/active_record/internal_metadata.rb +26 -9
  143. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  144. data/lib/active_record/locking/optimistic.rb +26 -22
  145. data/lib/active_record/locking/pessimistic.rb +9 -5
  146. data/lib/active_record/log_subscriber.rb +34 -35
  147. data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
  148. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  149. data/lib/active_record/middleware/database_selector.rb +77 -0
  150. data/lib/active_record/migration/command_recorder.rb +96 -44
  151. data/lib/active_record/migration/compatibility.rb +141 -64
  152. data/lib/active_record/migration/join_table.rb +0 -1
  153. data/lib/active_record/migration.rb +205 -156
  154. data/lib/active_record/model_schema.rb +148 -22
  155. data/lib/active_record/nested_attributes.rb +4 -7
  156. data/lib/active_record/no_touching.rb +8 -1
  157. data/lib/active_record/null_relation.rb +0 -1
  158. data/lib/active_record/persistence.rb +267 -59
  159. data/lib/active_record/query_cache.rb +21 -4
  160. data/lib/active_record/querying.rb +40 -23
  161. data/lib/active_record/railtie.rb +115 -58
  162. data/lib/active_record/railties/controller_runtime.rb +30 -35
  163. data/lib/active_record/railties/databases.rake +402 -78
  164. data/lib/active_record/readonly_attributes.rb +4 -0
  165. data/lib/active_record/reflection.rb +113 -101
  166. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  167. data/lib/active_record/relation/batches.rb +44 -35
  168. data/lib/active_record/relation/calculations.rb +157 -93
  169. data/lib/active_record/relation/delegation.rb +35 -50
  170. data/lib/active_record/relation/finder_methods.rb +65 -40
  171. data/lib/active_record/relation/from_clause.rb +5 -1
  172. data/lib/active_record/relation/merger.rb +32 -40
  173. data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
  174. data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -7
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  179. data/lib/active_record/relation/predicate_builder.rb +58 -40
  180. data/lib/active_record/relation/query_attribute.rb +13 -8
  181. data/lib/active_record/relation/query_methods.rb +487 -199
  182. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  183. data/lib/active_record/relation/spawn_methods.rb +9 -9
  184. data/lib/active_record/relation/where_clause.rb +108 -58
  185. data/lib/active_record/relation.rb +375 -104
  186. data/lib/active_record/result.rb +64 -38
  187. data/lib/active_record/runtime_registry.rb +2 -2
  188. data/lib/active_record/sanitization.rb +22 -41
  189. data/lib/active_record/schema.rb +2 -11
  190. data/lib/active_record/schema_dumper.rb +54 -9
  191. data/lib/active_record/schema_migration.rb +7 -9
  192. data/lib/active_record/scoping/default.rb +6 -8
  193. data/lib/active_record/scoping/named.rb +17 -24
  194. data/lib/active_record/scoping.rb +8 -9
  195. data/lib/active_record/secure_token.rb +16 -8
  196. data/lib/active_record/serialization.rb +5 -3
  197. data/lib/active_record/signed_id.rb +116 -0
  198. data/lib/active_record/statement_cache.rb +51 -8
  199. data/lib/active_record/store.rb +88 -9
  200. data/lib/active_record/suppressor.rb +2 -2
  201. data/lib/active_record/table_metadata.rb +39 -43
  202. data/lib/active_record/tasks/database_tasks.rb +276 -81
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
  206. data/lib/active_record/test_databases.rb +24 -0
  207. data/lib/active_record/test_fixtures.rb +246 -0
  208. data/lib/active_record/timestamp.rb +43 -32
  209. data/lib/active_record/touch_later.rb +23 -22
  210. data/lib/active_record/transactions.rb +59 -117
  211. data/lib/active_record/translation.rb +1 -1
  212. data/lib/active_record/type/adapter_specific_registry.rb +3 -13
  213. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  214. data/lib/active_record/type/serialized.rb +6 -3
  215. data/lib/active_record/type/time.rb +10 -0
  216. data/lib/active_record/type/type_map.rb +0 -1
  217. data/lib/active_record/type/unsigned_integer.rb +0 -1
  218. data/lib/active_record/type.rb +10 -5
  219. data/lib/active_record/type_caster/connection.rb +15 -15
  220. data/lib/active_record/type_caster/map.rb +8 -8
  221. data/lib/active_record/validations/associated.rb +1 -2
  222. data/lib/active_record/validations/numericality.rb +35 -0
  223. data/lib/active_record/validations/uniqueness.rb +38 -30
  224. data/lib/active_record/validations.rb +4 -3
  225. data/lib/active_record.rb +13 -12
  226. data/lib/arel/alias_predication.rb +9 -0
  227. data/lib/arel/attributes/attribute.rb +41 -0
  228. data/lib/arel/collectors/bind.rb +29 -0
  229. data/lib/arel/collectors/composite.rb +39 -0
  230. data/lib/arel/collectors/plain_string.rb +20 -0
  231. data/lib/arel/collectors/sql_string.rb +27 -0
  232. data/lib/arel/collectors/substitute_binds.rb +35 -0
  233. data/lib/arel/crud.rb +42 -0
  234. data/lib/arel/delete_manager.rb +18 -0
  235. data/lib/arel/errors.rb +9 -0
  236. data/lib/arel/expressions.rb +29 -0
  237. data/lib/arel/factory_methods.rb +49 -0
  238. data/lib/arel/insert_manager.rb +49 -0
  239. data/lib/arel/math.rb +45 -0
  240. data/lib/arel/nodes/and.rb +32 -0
  241. data/lib/arel/nodes/ascending.rb +23 -0
  242. data/lib/arel/nodes/binary.rb +126 -0
  243. data/lib/arel/nodes/bind_param.rb +44 -0
  244. data/lib/arel/nodes/case.rb +55 -0
  245. data/lib/arel/nodes/casted.rb +62 -0
  246. data/lib/arel/nodes/comment.rb +29 -0
  247. data/lib/arel/nodes/count.rb +12 -0
  248. data/lib/arel/nodes/delete_statement.rb +45 -0
  249. data/lib/arel/nodes/descending.rb +23 -0
  250. data/lib/arel/nodes/equality.rb +15 -0
  251. data/lib/arel/nodes/extract.rb +24 -0
  252. data/lib/arel/nodes/false.rb +16 -0
  253. data/lib/arel/nodes/full_outer_join.rb +8 -0
  254. data/lib/arel/nodes/function.rb +44 -0
  255. data/lib/arel/nodes/grouping.rb +11 -0
  256. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  257. data/lib/arel/nodes/in.rb +15 -0
  258. data/lib/arel/nodes/infix_operation.rb +92 -0
  259. data/lib/arel/nodes/inner_join.rb +8 -0
  260. data/lib/arel/nodes/insert_statement.rb +37 -0
  261. data/lib/arel/nodes/join_source.rb +20 -0
  262. data/lib/arel/nodes/matches.rb +18 -0
  263. data/lib/arel/nodes/named_function.rb +23 -0
  264. data/lib/arel/nodes/node.rb +51 -0
  265. data/lib/arel/nodes/node_expression.rb +13 -0
  266. data/lib/arel/nodes/ordering.rb +27 -0
  267. data/lib/arel/nodes/outer_join.rb +8 -0
  268. data/lib/arel/nodes/over.rb +15 -0
  269. data/lib/arel/nodes/regexp.rb +16 -0
  270. data/lib/arel/nodes/right_outer_join.rb +8 -0
  271. data/lib/arel/nodes/select_core.rb +67 -0
  272. data/lib/arel/nodes/select_statement.rb +41 -0
  273. data/lib/arel/nodes/sql_literal.rb +19 -0
  274. data/lib/arel/nodes/string_join.rb +11 -0
  275. data/lib/arel/nodes/table_alias.rb +31 -0
  276. data/lib/arel/nodes/terminal.rb +16 -0
  277. data/lib/arel/nodes/true.rb +16 -0
  278. data/lib/arel/nodes/unary.rb +44 -0
  279. data/lib/arel/nodes/unary_operation.rb +20 -0
  280. data/lib/arel/nodes/unqualified_column.rb +22 -0
  281. data/lib/arel/nodes/update_statement.rb +41 -0
  282. data/lib/arel/nodes/values_list.rb +9 -0
  283. data/lib/arel/nodes/window.rb +126 -0
  284. data/lib/arel/nodes/with.rb +11 -0
  285. data/lib/arel/nodes.rb +70 -0
  286. data/lib/arel/order_predications.rb +13 -0
  287. data/lib/arel/predications.rb +250 -0
  288. data/lib/arel/select_manager.rb +270 -0
  289. data/lib/arel/table.rb +118 -0
  290. data/lib/arel/tree_manager.rb +72 -0
  291. data/lib/arel/update_manager.rb +34 -0
  292. data/lib/arel/visitors/dot.rb +308 -0
  293. data/lib/arel/visitors/mysql.rb +93 -0
  294. data/lib/arel/visitors/postgresql.rb +120 -0
  295. data/lib/arel/visitors/sqlite.rb +38 -0
  296. data/lib/arel/visitors/to_sql.rb +899 -0
  297. data/lib/arel/visitors/visitor.rb +45 -0
  298. data/lib/arel/visitors.rb +13 -0
  299. data/lib/arel/window_predications.rb +9 -0
  300. data/lib/arel.rb +54 -0
  301. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  302. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
  303. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
  304. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
  305. data/lib/rails/generators/active_record/migration.rb +19 -2
  306. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  307. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  308. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  309. metadata +117 -32
  310. data/lib/active_record/attribute_decorators.rb +0 -90
  311. data/lib/active_record/collection_cache_key.rb +0 -53
  312. data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
  313. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
  314. data/lib/active_record/define_callbacks.rb +0 -22
  315. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
  316. data/lib/active_record/relation/where_clause_factory.rb +0 -34
@@ -16,10 +16,10 @@ module ActiveRecord
16
16
  def exec_queries
17
17
  QueryRegistry.reset
18
18
 
19
- super.tap do
19
+ super.tap do |records|
20
20
  if logger && warn_on_records_fetched_greater_than
21
- if @records.length > warn_on_records_fetched_greater_than
22
- logger.warn "Query fetched #{@records.size} #{@klass} records: #{QueryRegistry.queries.join(";")}"
21
+ if records.length > warn_on_records_fetched_greater_than
22
+ logger.warn "Query fetched #{records.size} #{@klass} records: #{QueryRegistry.queries.join(";")}"
23
23
  end
24
24
  end
25
25
  end
@@ -8,7 +8,7 @@ module ActiveRecord
8
8
  module SpawnMethods
9
9
  # This is overridden by Associations::CollectionProxy
10
10
  def spawn #:nodoc:
11
- @delegate_to_klass ? klass.all : clone
11
+ already_in_scope? ? klass.all : clone
12
12
  end
13
13
 
14
14
  # Merges in the conditions from <tt>other</tt>, if <tt>other</tt> is an ActiveRecord::Relation.
@@ -28,21 +28,22 @@ module ActiveRecord
28
28
  # # => Post.where(published: true).joins(:comments)
29
29
  #
30
30
  # This is mainly intended for sharing common conditions between multiple associations.
31
- def merge(other)
31
+ def merge(other, *rest)
32
32
  if other.is_a?(Array)
33
33
  records & other
34
34
  elsif other
35
- spawn.merge!(other)
35
+ spawn.merge!(other, *rest)
36
36
  else
37
37
  raise ArgumentError, "invalid argument: #{other.inspect}."
38
38
  end
39
39
  end
40
40
 
41
- def merge!(other) # :nodoc:
41
+ def merge!(other, *rest) # :nodoc:
42
+ options = rest.extract_options!
42
43
  if other.is_a?(Hash)
43
- Relation::HashMerger.new(self, other).merge
44
+ Relation::HashMerger.new(self, other, options[:rewhere]).merge
44
45
  elsif other.is_a?(Relation)
45
- Relation::Merger.new(self, other).merge
46
+ Relation::Merger.new(self, other, options[:rewhere]).merge
46
47
  elsif other.respond_to?(:to_proc)
47
48
  instance_exec(&other)
48
49
  else
@@ -67,10 +68,9 @@ module ActiveRecord
67
68
  end
68
69
 
69
70
  private
70
-
71
71
  def relation_with(values)
72
- result = Relation.create(klass, values: values)
73
- result.extend(*extending_values) if extending_values.any?
72
+ result = spawn
73
+ result.instance_variable_set(:@values, values)
74
74
  result
75
75
  end
76
76
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/array/extract"
4
+
3
5
  module ActiveRecord
4
6
  class Relation
5
7
  class WhereClause # :nodoc:
@@ -10,21 +12,25 @@ module ActiveRecord
10
12
  end
11
13
 
12
14
  def +(other)
13
- WhereClause.new(
14
- predicates + other.predicates,
15
- )
15
+ WhereClause.new(predicates + other.predicates)
16
16
  end
17
17
 
18
18
  def -(other)
19
- WhereClause.new(
20
- predicates - other.predicates,
21
- )
19
+ WhereClause.new(predicates - other.predicates)
22
20
  end
23
21
 
24
- def merge(other)
25
- WhereClause.new(
26
- predicates_unreferenced_by(other) + other.predicates,
27
- )
22
+ def |(other)
23
+ WhereClause.new(predicates | other.predicates)
24
+ end
25
+
26
+ def merge(other, rewhere = nil)
27
+ predicates = if rewhere
28
+ except_predicates(other.extract_attributes)
29
+ else
30
+ predicates_unreferenced_by(other)
31
+ end
32
+
33
+ WhereClause.new(predicates | other.predicates)
28
34
  end
29
35
 
30
36
  def except(*columns)
@@ -39,30 +45,31 @@ module ActiveRecord
39
45
  if left.empty? || right.empty?
40
46
  common
41
47
  else
42
- or_clause = WhereClause.new(
43
- [left.ast.or(right.ast)],
44
- )
45
- common + or_clause
48
+ left = left.ast
49
+ left = left.expr if left.is_a?(Arel::Nodes::Grouping)
50
+
51
+ right = right.ast
52
+ right = right.expr if right.is_a?(Arel::Nodes::Grouping)
53
+
54
+ or_clause = Arel::Nodes::Or.new(left, right)
55
+
56
+ common.predicates << Arel::Nodes::Grouping.new(or_clause)
57
+ common
46
58
  end
47
59
  end
48
60
 
49
61
  def to_h(table_name = nil)
50
- equalities = equalities(predicates)
51
- if table_name
52
- equalities = equalities.select do |node|
53
- node.left.relation.name == table_name
54
- end
55
- end
56
-
57
- equalities.map { |node|
62
+ equalities(predicates).each_with_object({}) do |node, hash|
63
+ next if table_name&.!= node.left.relation.name
58
64
  name = node.left.name.to_s
59
65
  value = extract_node_value(node.right)
60
- [name, value]
61
- }.to_h
66
+ hash[name] = value
67
+ end
62
68
  end
63
69
 
64
70
  def ast
65
- Arel::Nodes::And.new(predicates_with_wrapped_sql_literals)
71
+ predicates = predicates_with_wrapped_sql_literals
72
+ predicates.one? ? predicates.first : Arel::Nodes::And.new(predicates)
66
73
  end
67
74
 
68
75
  def ==(other)
@@ -71,33 +78,69 @@ module ActiveRecord
71
78
  end
72
79
 
73
80
  def invert
81
+ if predicates.size == 1
82
+ inverted_predicates = [ invert_predicate(predicates.first) ]
83
+ else
84
+ inverted_predicates = [ Arel::Nodes::Not.new(ast) ]
85
+ end
86
+
74
87
  WhereClause.new(inverted_predicates)
75
88
  end
76
89
 
77
90
  def self.empty
78
- @empty ||= new([])
91
+ @empty ||= new([]).freeze
79
92
  end
80
93
 
81
- protected
94
+ def contradiction?
95
+ predicates.any? do |x|
96
+ case x
97
+ when Arel::Nodes::In
98
+ Array === x.right && x.right.empty?
99
+ when Arel::Nodes::Equality
100
+ x.right.respond_to?(:unboundable?) && x.right.unboundable?
101
+ end
102
+ end
103
+ end
82
104
 
105
+ def extract_attributes
106
+ predicates.each_with_object([]) do |node, attrs|
107
+ attr = extract_attribute(node) || begin
108
+ node.left if node.equality? && node.left.is_a?(Arel::Predications)
109
+ end
110
+ attrs << attr if attr
111
+ end
112
+ end
113
+
114
+ protected
83
115
  attr_reader :predicates
84
116
 
85
117
  def referenced_columns
86
- @referenced_columns ||= begin
87
- equality_nodes = predicates.select { |n| equality_node?(n) }
88
- Set.new(equality_nodes, &:left)
118
+ predicates.each_with_object({}) do |node, hash|
119
+ attr = extract_attribute(node) || begin
120
+ node.left if equality_node?(node) && node.left.is_a?(Arel::Predications)
121
+ end
122
+
123
+ hash[attr] = node if attr
89
124
  end
90
125
  end
91
126
 
92
127
  private
128
+ def extract_attribute(node)
129
+ attr_node = nil
130
+ Arel.fetch_attribute(node) do |attr|
131
+ return if attr_node&.!= attr # all attr nodes should be the same
132
+ attr_node = attr
133
+ end
134
+ attr_node
135
+ end
136
+
93
137
  def equalities(predicates)
94
138
  equalities = []
95
139
 
96
140
  predicates.each do |node|
97
- case node
98
- when Arel::Nodes::Equality
141
+ if equality_node?(node)
99
142
  equalities << node
100
- when Arel::Nodes::And
143
+ elsif node.is_a?(Arel::Nodes::And)
101
144
  equalities.concat equalities(node.children)
102
145
  end
103
146
  end
@@ -106,40 +149,54 @@ module ActiveRecord
106
149
  end
107
150
 
108
151
  def predicates_unreferenced_by(other)
109
- predicates.reject do |n|
110
- equality_node?(n) && other.referenced_columns.include?(n.left)
152
+ referenced_columns = other.referenced_columns
153
+
154
+ predicates.reject do |node|
155
+ attr = extract_attribute(node) || begin
156
+ node.left if equality_node?(node) && node.left.is_a?(Arel::Predications)
157
+ end
158
+ next false unless attr
159
+
160
+ ref = referenced_columns[attr]
161
+ next false unless ref
162
+
163
+ if equality_node?(node) && equality_node?(ref) || node == ref
164
+ true
165
+ else
166
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
167
+ Merging (#{node.to_sql}) and (#{ref.to_sql}) no longer maintain
168
+ both conditions, and will be replaced by the latter in Rails 6.2.
169
+ To migrate to Rails 6.2's behavior, use `relation.merge(other, rewhere: true)`.
170
+ MSG
171
+ false
172
+ end
111
173
  end
112
174
  end
113
175
 
114
176
  def equality_node?(node)
115
- node.respond_to?(:operator) && node.operator == :==
116
- end
117
-
118
- def inverted_predicates
119
- predicates.map { |node| invert_predicate(node) }
177
+ !node.is_a?(String) && node.equality?
120
178
  end
121
179
 
122
180
  def invert_predicate(node)
123
181
  case node
124
182
  when NilClass
125
183
  raise ArgumentError, "Invalid argument for .where.not(), got nil."
126
- when Arel::Nodes::In
127
- Arel::Nodes::NotIn.new(node.left, node.right)
128
- when Arel::Nodes::Equality
129
- Arel::Nodes::NotEqual.new(node.left, node.right)
130
184
  when String
131
185
  Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new(node))
132
186
  else
133
- Arel::Nodes::Not.new(node)
187
+ node.invert
134
188
  end
135
189
  end
136
190
 
137
191
  def except_predicates(columns)
192
+ attrs = columns.extract! { |node| node.is_a?(Arel::Attribute) }
193
+ non_attrs = columns.extract! { |node| node.is_a?(Arel::Predications) }
194
+
138
195
  predicates.reject do |node|
139
- case node
140
- when Arel::Nodes::Between, Arel::Nodes::In, Arel::Nodes::NotIn, Arel::Nodes::Equality, Arel::Nodes::NotEqual, Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
141
- subrelation = (node.left.kind_of?(Arel::Attributes::Attribute) ? node.left : node.right)
142
- columns.include?(subrelation.name.to_s)
196
+ if !non_attrs.empty? && node.equality? && node.left.is_a?(Arel::Predications)
197
+ non_attrs.include?(node.left)
198
+ end || Arel.fetch_attribute(node) do |attr|
199
+ attrs.include?(attr) || columns.include?(attr.name.to_s)
143
200
  end
144
201
  end
145
202
  end
@@ -170,15 +227,8 @@ module ActiveRecord
170
227
  case node
171
228
  when Array
172
229
  node.map { |v| extract_node_value(v) }
173
- when Arel::Nodes::Casted, Arel::Nodes::Quoted
174
- node.val
175
- when Arel::Nodes::BindParam
176
- value = node.value
177
- if value.respond_to?(:value_before_type_cast)
178
- value.value_before_type_cast
179
- else
180
- value
181
- end
230
+ when Arel::Nodes::BindParam, Arel::Nodes::Casted, Arel::Nodes::Quoted
231
+ node.value_before_type_cast
182
232
  end
183
233
  end
184
234
  end