From 2182419d81e9b23f68aeddce6526580a20af5e34 Mon Sep 17 00:00:00 2001 From: "Ben Sheldon [he/him]" Date: Thu, 4 Apr 2024 21:20:10 -0700 Subject: [PATCH] Allow `IN` with subselect to be preparable --- activerecord/lib/arel/visitors/to_sql.rb | 6 ++-- .../test/cases/arel/visitors/to_sql_test.rb | 36 +++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/arel/visitors/to_sql.rb b/activerecord/lib/arel/visitors/to_sql.rb index 78360fd5b9bec..16f417c79d433 100644 --- a/activerecord/lib/arel/visitors/to_sql.rb +++ b/activerecord/lib/arel/visitors/to_sql.rb @@ -586,10 +586,11 @@ def visit_Arel_Table(o, collector) end def visit_Arel_Nodes_In(o, collector) - collector.preparable = false attr, values = o.left, o.right if Array === values + collector.preparable = false + unless values.empty? values.delete_if { |value| unboundable?(value) } end @@ -602,10 +603,11 @@ def visit_Arel_Nodes_In(o, collector) end def visit_Arel_Nodes_NotIn(o, collector) - collector.preparable = false attr, values = o.left, o.right if Array === values + collector.preparable = false + unless values.empty? values.delete_if { |value| unboundable?(value) } end diff --git a/activerecord/test/cases/arel/visitors/to_sql_test.rb b/activerecord/test/cases/arel/visitors/to_sql_test.rb index 67601765166af..5557d67175aed 100644 --- a/activerecord/test/cases/arel/visitors/to_sql_test.rb +++ b/activerecord/test/cases/arel/visitors/to_sql_test.rb @@ -520,6 +520,24 @@ def dispatch "users"."id" IN (SELECT id FROM "users" WHERE "users"."name" = 'Aaron') } end + + it "is not preparable when an array" do + node = @attr.in [1, 2, 3] + + collector = Collectors::SQLString.new.tap { |c| c.preparable = true } + @visitor.accept(node, collector) + _(collector.preparable).must_equal false + end + + it "is preparable when a subselect" do + table = Table.new(:users) + subquery = table.project(table[:id]).where(table[:name].eq("Aaron")) + node = @attr.in subquery + + collector = Collectors::SQLString.new.tap { |c| c.preparable = true } + @visitor.accept(node, collector) + _(collector.preparable).must_equal true + end end describe "Nodes::InfixOperation" do @@ -682,6 +700,24 @@ def dispatch "users"."id" NOT IN (SELECT id FROM "users" WHERE "users"."name" = 'Aaron') } end + + it "is not preparable when an array" do + node = @attr.not_in [1, 2, 3] + + collector = Collectors::SQLString.new.tap { |c| c.preparable = true } + @visitor.accept(node, collector) + _(collector.preparable).must_equal false + end + + it "is preparable when a subselect" do + table = Table.new(:users) + subquery = table.project(table[:id]).where(table[:name].eq("Aaron")) + node = @attr.not_in subquery + + collector = Collectors::SQLString.new.tap { |c| c.preparable = true } + @visitor.accept(node, collector) + _(collector.preparable).must_equal true + end end describe "Constants" do