Skip to content

Commit 19a1680

Browse files
committed
Fix update_all/delete_all on CPK model relation with join subquery
1 parent 1007cc8 commit 19a1680

File tree

6 files changed

+39
-9
lines changed

6 files changed

+39
-9
lines changed

activerecord/lib/active_record/relation.rb

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -591,7 +591,12 @@ def update_all(updates)
591591

592592
group_values_arel_columns = arel_columns(group_values.uniq)
593593
having_clause_ast = having_clause.ast unless having_clause.empty?
594-
stmt = arel.compile_update(values, table[primary_key], having_clause_ast, group_values_arel_columns)
594+
key = if klass.composite_primary_key?
595+
primary_key.map { |pk| table[pk] }
596+
else
597+
table[primary_key]
598+
end
599+
stmt = arel.compile_update(values, key, having_clause_ast, group_values_arel_columns)
595600
klass.connection.update(stmt, "#{klass} Update All").tap { reset }
596601
end
597602

@@ -724,7 +729,12 @@ def delete_all
724729

725730
group_values_arel_columns = arel_columns(group_values.uniq)
726731
having_clause_ast = having_clause.ast unless having_clause.empty?
727-
stmt = arel.compile_delete(table[primary_key], having_clause_ast, group_values_arel_columns)
732+
key = if klass.composite_primary_key?
733+
primary_key.map { |pk| table[pk] }
734+
else
735+
table[primary_key]
736+
end
737+
stmt = arel.compile_delete(key, having_clause_ast, group_values_arel_columns)
728738

729739
klass.connection.delete(stmt, "#{klass} Delete All").tap { reset }
730740
end

activerecord/lib/arel/tree_manager.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ def order(*expr)
2121
end
2222

2323
def key=(key)
24-
@ast.key = Nodes.build_quoted(key)
24+
@ast.key = if key.is_a?(Array)
25+
key.map { |k| Nodes.build_quoted(k) }
26+
else
27+
Nodes.build_quoted(key)
28+
end
2529
end
2630

2731
def key

activerecord/lib/arel/visitors/to_sql.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -930,7 +930,8 @@ def prepare_update_statement(o)
930930
stmt.limit = nil
931931
stmt.offset = nil
932932
stmt.orders = []
933-
stmt.wheres = [Nodes::In.new(o.key, [build_subselect(o.key, o)])]
933+
columns = Arel::Nodes::Grouping.new(o.key)
934+
stmt.wheres = [Nodes::In.new(columns, [build_subselect(o.key, o)])]
934935
stmt.relation = o.relation.left if has_join_sources?(o)
935936
stmt.groups = o.groups unless o.groups.empty?
936937
stmt.havings = o.havings unless o.havings.empty?

activerecord/test/cases/arel/select_manager_test.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,7 +1014,7 @@ def test_join_sources
10141014

10151015
_(stmt.to_sql).must_be_like %{
10161016
UPDATE "users" SET foo = bar
1017-
WHERE "users"."id" IN (SELECT "users"."id" FROM "users" LIMIT 1)
1017+
WHERE ("users"."id") IN (SELECT "users"."id" FROM "users" LIMIT 1)
10181018
}
10191019
end
10201020

@@ -1028,7 +1028,7 @@ def test_join_sources
10281028

10291029
_(stmt.to_sql).must_be_like %{
10301030
UPDATE "users" SET foo = bar
1031-
WHERE "users"."id" IN (SELECT "users"."id" FROM "users" ORDER BY foo)
1031+
WHERE ("users"."id") IN (SELECT "users"."id" FROM "users" ORDER BY foo)
10321032
}
10331033
end
10341034

@@ -1053,7 +1053,7 @@ def test_join_sources
10531053
stmt = manager.compile_update({ table[:id] => 1 }, Arel::Attributes::Attribute.new(table, "id"))
10541054

10551055
_(stmt.to_sql).must_be_like %{
1056-
UPDATE "users" SET "id" = 1 WHERE "users"."id" IN (SELECT "users"."id" FROM "users" WHERE "users"."foo" = 10 LIMIT 42)
1056+
UPDATE "users" SET "id" = 1 WHERE ("users"."id") IN (SELECT "users"."id" FROM "users" WHERE "users"."foo" = 10 LIMIT 42)
10571057
}
10581058
end
10591059
end

activerecord/test/cases/relation/delete_all_test.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
require "models/pet"
77
require "models/toy"
88
require "models/comment"
9+
require "models/cpk"
910

1011
class DeleteAllTest < ActiveRecord::TestCase
11-
fixtures :authors, :author_addresses, :comments, :posts, :pets, :toys
12+
fixtures :authors, :author_addresses, :comments, :posts, :pets, :toys, :cpk_orders, :cpk_order_agreements
1213

1314
def test_destroy_all
1415
davids = Author.where(name: "David")
@@ -128,4 +129,10 @@ def test_delete_all_with_order_and_limit_and_offset_deletes_subset_only
128129
assert_raise(ActiveRecord::RecordNotFound) { posts(:thinking) }
129130
assert posts(:welcome)
130131
end
132+
133+
def test_delete_all_composite_model_with_join_subquery
134+
agreement = cpk_order_agreements(:order_agreement_three)
135+
join_scope = Cpk::Order.joins(:order_agreements).where(order_agreements: { signature: agreement.signature })
136+
assert_equal 1, join_scope.delete_all
137+
end
131138
end

activerecord/test/cases/relation/update_all_test.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@
1414
require "models/tag"
1515
require "models/tagging"
1616
require "models/warehouse_thing"
17+
require "models/cpk"
1718

1819
class UpdateAllTest < ActiveRecord::TestCase
19-
fixtures :authors, :author_addresses, :comments, :developers, :posts, :people, :pets, :toys, :tags, :taggings, "warehouse-things"
20+
fixtures :authors, :author_addresses, :comments, :developers, :posts, :people, :pets, :toys, :tags,
21+
:taggings, "warehouse-things", :cpk_orders, :cpk_order_agreements
2022

2123
class TopicWithCallbacks < ActiveRecord::Base
2224
self.table_name = :topics
@@ -300,6 +302,12 @@ def test_klass_level_touch_all
300302
end
301303
end
302304

305+
def test_update_all_composite_model_with_join_subquery
306+
agreement = cpk_order_agreements(:order_agreement_three)
307+
join_scope = Cpk::Order.joins(:order_agreements).where(order_agreements: { signature: agreement.signature })
308+
assert_equal 1, join_scope.update_all(status: "shipped")
309+
end
310+
303311
# Oracle UPDATE does not support ORDER BY
304312
unless current_adapter?(:OracleAdapter)
305313
def test_update_all_ignores_order_without_limit_from_association

0 commit comments

Comments
 (0)