activerecord 6.0.1 → 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 (268) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +843 -626
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -3
  5. data/lib/active_record/aggregations.rb +1 -2
  6. data/lib/active_record/association_relation.rb +18 -17
  7. data/lib/active_record/associations/alias_tracker.rb +19 -16
  8. data/lib/active_record/associations/association.rb +49 -37
  9. data/lib/active_record/associations/association_scope.rb +17 -15
  10. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  12. data/lib/active_record/associations/builder/association.rb +9 -3
  13. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  14. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -3
  16. data/lib/active_record/associations/builder/has_many.rb +6 -2
  17. data/lib/active_record/associations/builder/has_one.rb +11 -14
  18. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  19. data/lib/active_record/associations/collection_association.rb +25 -8
  20. data/lib/active_record/associations/collection_proxy.rb +14 -7
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -3
  23. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  24. data/lib/active_record/associations/has_one_association.rb +15 -1
  25. data/lib/active_record/associations/join_dependency/join_association.rb +36 -14
  26. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  27. data/lib/active_record/associations/join_dependency.rb +73 -42
  28. data/lib/active_record/associations/preloader/association.rb +51 -25
  29. data/lib/active_record/associations/preloader/through_association.rb +2 -2
  30. data/lib/active_record/associations/preloader.rb +12 -7
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations/through_association.rb +1 -1
  33. data/lib/active_record/associations.rb +115 -12
  34. data/lib/active_record/attribute_assignment.rb +10 -9
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -10
  36. data/lib/active_record/attribute_methods/dirty.rb +3 -13
  37. data/lib/active_record/attribute_methods/primary_key.rb +6 -4
  38. data/lib/active_record/attribute_methods/query.rb +3 -6
  39. data/lib/active_record/attribute_methods/read.rb +8 -12
  40. data/lib/active_record/attribute_methods/serialization.rb +11 -6
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
  42. data/lib/active_record/attribute_methods/write.rb +12 -21
  43. data/lib/active_record/attribute_methods.rb +64 -54
  44. data/lib/active_record/attributes.rb +32 -8
  45. data/lib/active_record/autosave_association.rb +56 -41
  46. data/lib/active_record/base.rb +2 -14
  47. data/lib/active_record/callbacks.rb +153 -24
  48. data/lib/active_record/coders/yaml_column.rb +1 -2
  49. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +190 -136
  50. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +82 -37
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -8
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  54. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  55. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +152 -116
  56. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +137 -52
  57. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  58. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +263 -107
  59. data/lib/active_record/connection_adapters/abstract/transaction.rb +82 -35
  60. data/lib/active_record/connection_adapters/abstract_adapter.rb +60 -73
  61. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +136 -111
  62. data/lib/active_record/connection_adapters/column.rb +15 -1
  63. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  64. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  65. data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/database_statements.rb +28 -36
  67. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
  68. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
  69. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -7
  70. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  71. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  72. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +17 -13
  73. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  74. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -13
  75. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  76. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -56
  79. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +0 -1
  80. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  81. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  83. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +0 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -3
  87. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -3
  90. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -6
  91. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
  92. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -2
  93. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  95. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
  96. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +7 -3
  97. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +1 -1
  98. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
  99. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +72 -54
  100. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  101. data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +77 -57
  103. data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
  104. data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
  105. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +36 -12
  106. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -2
  107. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  108. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +38 -5
  109. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +57 -57
  110. data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
  111. data/lib/active_record/connection_adapters.rb +50 -0
  112. data/lib/active_record/connection_handling.rb +210 -87
  113. data/lib/active_record/core.rb +229 -65
  114. data/lib/active_record/counter_cache.rb +4 -1
  115. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  116. data/lib/active_record/database_configurations/database_config.rb +52 -9
  117. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  118. data/lib/active_record/database_configurations/url_config.rb +15 -41
  119. data/lib/active_record/database_configurations.rb +124 -85
  120. data/lib/active_record/delegated_type.rb +209 -0
  121. data/lib/active_record/destroy_association_async_job.rb +36 -0
  122. data/lib/active_record/dynamic_matchers.rb +2 -3
  123. data/lib/active_record/enum.rb +40 -16
  124. data/lib/active_record/errors.rb +47 -12
  125. data/lib/active_record/explain.rb +9 -5
  126. data/lib/active_record/explain_subscriber.rb +1 -1
  127. data/lib/active_record/fixture_set/file.rb +10 -17
  128. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  129. data/lib/active_record/fixture_set/render_context.rb +1 -1
  130. data/lib/active_record/fixture_set/table_row.rb +2 -3
  131. data/lib/active_record/fixture_set/table_rows.rb +0 -1
  132. data/lib/active_record/fixtures.rb +54 -11
  133. data/lib/active_record/gem_version.rb +2 -2
  134. data/lib/active_record/inheritance.rb +40 -21
  135. data/lib/active_record/insert_all.rb +38 -9
  136. data/lib/active_record/integration.rb +3 -5
  137. data/lib/active_record/internal_metadata.rb +16 -7
  138. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  139. data/lib/active_record/locking/optimistic.rb +22 -17
  140. data/lib/active_record/locking/pessimistic.rb +6 -2
  141. data/lib/active_record/log_subscriber.rb +27 -9
  142. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  143. data/lib/active_record/middleware/database_selector/resolver.rb +6 -2
  144. data/lib/active_record/middleware/database_selector.rb +4 -2
  145. data/lib/active_record/migration/command_recorder.rb +53 -45
  146. data/lib/active_record/migration/compatibility.rb +70 -20
  147. data/lib/active_record/migration/join_table.rb +0 -1
  148. data/lib/active_record/migration.rb +114 -84
  149. data/lib/active_record/model_schema.rb +117 -15
  150. data/lib/active_record/nested_attributes.rb +2 -5
  151. data/lib/active_record/no_touching.rb +1 -1
  152. data/lib/active_record/null_relation.rb +0 -1
  153. data/lib/active_record/persistence.rb +50 -46
  154. data/lib/active_record/query_cache.rb +15 -5
  155. data/lib/active_record/querying.rb +12 -7
  156. data/lib/active_record/railtie.rb +65 -45
  157. data/lib/active_record/railties/databases.rake +267 -93
  158. data/lib/active_record/readonly_attributes.rb +4 -0
  159. data/lib/active_record/reflection.rb +77 -63
  160. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  161. data/lib/active_record/relation/batches.rb +38 -32
  162. data/lib/active_record/relation/calculations.rb +102 -45
  163. data/lib/active_record/relation/delegation.rb +9 -7
  164. data/lib/active_record/relation/finder_methods.rb +45 -16
  165. data/lib/active_record/relation/from_clause.rb +5 -1
  166. data/lib/active_record/relation/merger.rb +27 -26
  167. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  168. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  169. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
  170. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  171. data/lib/active_record/relation/predicate_builder.rb +55 -35
  172. data/lib/active_record/relation/query_methods.rb +335 -187
  173. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  174. data/lib/active_record/relation/spawn_methods.rb +8 -8
  175. data/lib/active_record/relation/where_clause.rb +104 -58
  176. data/lib/active_record/relation.rb +108 -68
  177. data/lib/active_record/result.rb +41 -34
  178. data/lib/active_record/runtime_registry.rb +2 -2
  179. data/lib/active_record/sanitization.rb +6 -17
  180. data/lib/active_record/schema_dumper.rb +34 -4
  181. data/lib/active_record/schema_migration.rb +2 -8
  182. data/lib/active_record/scoping/default.rb +0 -1
  183. data/lib/active_record/scoping/named.rb +7 -18
  184. data/lib/active_record/scoping.rb +0 -1
  185. data/lib/active_record/secure_token.rb +16 -8
  186. data/lib/active_record/serialization.rb +5 -3
  187. data/lib/active_record/signed_id.rb +116 -0
  188. data/lib/active_record/statement_cache.rb +20 -4
  189. data/lib/active_record/store.rb +3 -3
  190. data/lib/active_record/suppressor.rb +2 -2
  191. data/lib/active_record/table_metadata.rb +39 -36
  192. data/lib/active_record/tasks/database_tasks.rb +139 -113
  193. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -36
  194. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -27
  195. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -10
  196. data/lib/active_record/test_databases.rb +5 -4
  197. data/lib/active_record/test_fixtures.rb +38 -16
  198. data/lib/active_record/timestamp.rb +4 -7
  199. data/lib/active_record/touch_later.rb +20 -21
  200. data/lib/active_record/transactions.rb +21 -70
  201. data/lib/active_record/type/adapter_specific_registry.rb +2 -5
  202. data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
  203. data/lib/active_record/type/serialized.rb +6 -3
  204. data/lib/active_record/type/time.rb +10 -0
  205. data/lib/active_record/type/type_map.rb +0 -1
  206. data/lib/active_record/type/unsigned_integer.rb +0 -1
  207. data/lib/active_record/type.rb +8 -2
  208. data/lib/active_record/type_caster/connection.rb +0 -1
  209. data/lib/active_record/type_caster/map.rb +8 -5
  210. data/lib/active_record/validations/associated.rb +1 -2
  211. data/lib/active_record/validations/numericality.rb +35 -0
  212. data/lib/active_record/validations/uniqueness.rb +24 -4
  213. data/lib/active_record/validations.rb +3 -3
  214. data/lib/active_record.rb +7 -13
  215. data/lib/arel/attributes/attribute.rb +4 -0
  216. data/lib/arel/collectors/bind.rb +5 -0
  217. data/lib/arel/collectors/composite.rb +8 -0
  218. data/lib/arel/collectors/sql_string.rb +7 -0
  219. data/lib/arel/collectors/substitute_binds.rb +7 -0
  220. data/lib/arel/nodes/binary.rb +82 -8
  221. data/lib/arel/nodes/bind_param.rb +8 -0
  222. data/lib/arel/nodes/casted.rb +21 -9
  223. data/lib/arel/nodes/equality.rb +6 -9
  224. data/lib/arel/nodes/grouping.rb +3 -0
  225. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  226. data/lib/arel/nodes/in.rb +8 -1
  227. data/lib/arel/nodes/infix_operation.rb +13 -1
  228. data/lib/arel/nodes/join_source.rb +1 -1
  229. data/lib/arel/nodes/node.rb +7 -6
  230. data/lib/arel/nodes/ordering.rb +27 -0
  231. data/lib/arel/nodes/sql_literal.rb +3 -0
  232. data/lib/arel/nodes/table_alias.rb +7 -3
  233. data/lib/arel/nodes/unary.rb +0 -1
  234. data/lib/arel/nodes.rb +3 -1
  235. data/lib/arel/predications.rb +17 -24
  236. data/lib/arel/select_manager.rb +1 -2
  237. data/lib/arel/table.rb +13 -5
  238. data/lib/arel/visitors/dot.rb +14 -3
  239. data/lib/arel/visitors/mysql.rb +11 -1
  240. data/lib/arel/visitors/postgresql.rb +15 -5
  241. data/lib/arel/visitors/sqlite.rb +0 -1
  242. data/lib/arel/visitors/to_sql.rb +89 -79
  243. data/lib/arel/visitors/visitor.rb +0 -1
  244. data/lib/arel/visitors.rb +0 -7
  245. data/lib/arel.rb +5 -9
  246. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
  247. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  248. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  249. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -4
  250. data/lib/rails/generators/active_record/migration.rb +6 -2
  251. data/lib/rails/generators/active_record/model/model_generator.rb +38 -2
  252. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  253. metadata +26 -26
  254. data/lib/active_record/attribute_decorators.rb +0 -90
  255. data/lib/active_record/connection_adapters/connection_specification.rb +0 -297
  256. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  257. data/lib/active_record/define_callbacks.rb +0 -22
  258. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  259. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  260. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  261. data/lib/arel/attributes.rb +0 -22
  262. data/lib/arel/visitors/depth_first.rb +0 -204
  263. data/lib/arel/visitors/ibm_db.rb +0 -34
  264. data/lib/arel/visitors/informix.rb +0 -62
  265. data/lib/arel/visitors/mssql.rb +0 -157
  266. data/lib/arel/visitors/oracle.rb +0 -159
  267. data/lib/arel/visitors/oracle12.rb +0 -66
  268. data/lib/arel/visitors/where_sql.rb +0 -23
@@ -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
@@ -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)
20
+ end
21
+
22
+ def |(other)
23
+ WhereClause.new(predicates | other.predicates)
22
24
  end
23
25
 
24
- def merge(other)
25
- WhereClause.new(
26
- predicates_unreferenced_by(other) + other.predicates,
27
- )
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)
@@ -70,11 +77,9 @@ module ActiveRecord
70
77
  predicates == other.predicates
71
78
  end
72
79
 
73
- def invert(as = :nand)
80
+ def invert
74
81
  if predicates.size == 1
75
82
  inverted_predicates = [ invert_predicate(predicates.first) ]
76
- elsif as == :nor
77
- inverted_predicates = predicates.map { |node| invert_predicate(node) }
78
83
  else
79
84
  inverted_predicates = [ Arel::Nodes::Not.new(ast) ]
80
85
  end
@@ -83,29 +88,59 @@ module ActiveRecord
83
88
  end
84
89
 
85
90
  def self.empty
86
- @empty ||= new([])
91
+ @empty ||= new([]).freeze
87
92
  end
88
93
 
89
- 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
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
90
113
 
114
+ protected
91
115
  attr_reader :predicates
92
116
 
93
117
  def referenced_columns
94
- @referenced_columns ||= begin
95
- equality_nodes = predicates.select { |n| equality_node?(n) }
96
- 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
97
124
  end
98
125
  end
99
126
 
100
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
+
101
137
  def equalities(predicates)
102
138
  equalities = []
103
139
 
104
140
  predicates.each do |node|
105
- case node
106
- when Arel::Nodes::Equality
141
+ if equality_node?(node)
107
142
  equalities << node
108
- when Arel::Nodes::And
143
+ elsif node.is_a?(Arel::Nodes::And)
109
144
  equalities.concat equalities(node.children)
110
145
  end
111
146
  end
@@ -114,37 +149,55 @@ module ActiveRecord
114
149
  end
115
150
 
116
151
  def predicates_unreferenced_by(other)
117
- predicates.reject do |n|
118
- 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
119
173
  end
120
174
  end
121
175
 
122
176
  def equality_node?(node)
123
- node.respond_to?(:operator) && node.operator == :==
177
+ !node.is_a?(String) && node.equality?
124
178
  end
125
179
 
126
180
  def invert_predicate(node)
127
181
  case node
128
182
  when NilClass
129
183
  raise ArgumentError, "Invalid argument for .where.not(), got nil."
130
- when Arel::Nodes::In
131
- Arel::Nodes::NotIn.new(node.left, node.right)
132
- when Arel::Nodes::IsNotDistinctFrom
133
- Arel::Nodes::IsDistinctFrom.new(node.left, node.right)
134
- when Arel::Nodes::IsDistinctFrom
135
- Arel::Nodes::IsNotDistinctFrom.new(node.left, node.right)
136
- when Arel::Nodes::Equality
137
- Arel::Nodes::NotEqual.new(node.left, node.right)
138
184
  when String
139
185
  Arel::Nodes::Not.new(Arel::Nodes::SqlLiteral.new(node))
140
186
  else
141
- Arel::Nodes::Not.new(node)
187
+ node.invert
142
188
  end
143
189
  end
144
190
 
145
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
+
146
195
  predicates.reject do |node|
147
- Arel.fetch_attribute(node) { |attr| columns.include?(attr.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)
200
+ end
148
201
  end
149
202
  end
150
203
 
@@ -174,15 +227,8 @@ module ActiveRecord
174
227
  case node
175
228
  when Array
176
229
  node.map { |v| extract_node_value(v) }
177
- when Arel::Nodes::Casted, Arel::Nodes::Quoted
178
- node.val
179
- when Arel::Nodes::BindParam
180
- value = node.value
181
- if value.respond_to?(:value_before_type_cast)
182
- value.value_before_type_cast
183
- else
184
- value
185
- end
230
+ when Arel::Nodes::BindParam, Arel::Nodes::Casted, Arel::Nodes::Quoted
231
+ node.value_before_type_cast
186
232
  end
187
233
  end
188
234
  end