dup rewritten predicates for multi-use relations

This commit is contained in:
Dylan Knutson
2025-07-29 23:15:40 +00:00
parent 3016a17480
commit 3d882fe6b7
2 changed files with 19 additions and 6 deletions

View File

@@ -107,7 +107,7 @@ module HasAuxTable
all_predicates = all_predicates =
T.cast( T.cast(
relation.where_clause.instance_variable_get(:@predicates), relation.where_clause.instance_variable_get(:@predicates),
T::Array[Arel::Nodes::Binary] T::Array[T.any(Arel::Nodes::Binary, Arel::Nodes::HomogeneousIn)]
) )
filtered_predicates = filtered_predicates =
@@ -132,13 +132,20 @@ module HasAuxTable
if all_on_aux_table if all_on_aux_table
# the eager load generates a join which creates table alias nodes on attributes instead # the eager load generates a join which creates table alias nodes on attributes instead
# of the original table, so we need to replace those with the original table # of the original table, so we need to replace those with the original table
filtered_predicates.each do |node| filtered_predicates.map! do |node|
if (attribute = node.left) && (table_alias = attribute.relation) && if node.left&.relation&.is_a?(Arel::Nodes::TableAlias)
table_alias.is_a?(Arel::Nodes::TableAlias) left = node.left.dup
attribute.relation = table_alias.left left.relation = left.relation.left
node = node.dup
case node
when Arel::Nodes::HomogeneousIn
node.instance_variable_set(:@attribute, left)
when Arel::Nodes::Binary
node.instance_variable_set(:@left, left)
end
end end
node
end end
filtered_predicates filtered_predicates
else else
nil nil

View File

@@ -371,6 +371,12 @@ RSpec.describe HasAuxTable do
expect(car_names).to eq(["Tesla Model 3", "Toyota Prius"]) expect(car_names).to eq(["Tesla Model 3", "Toyota Prius"])
end end
it "works when using the same relation mulitiple times" do
cars = Car.where(fuel_type: %w[hybrid electric])
expect(cars.count).to eq(2)
expect(cars.find_by(name: "Toyota Prius").fuel_type).to eq("hybrid")
end
it "doesn't add joins for queries without auxiliary columns" do it "doesn't add joins for queries without auxiliary columns" do
toyota_cars = Car.where(name: "Toyota Prius") toyota_cars = Car.where(name: "Toyota Prius")
expect(toyota_cars.length).to eq(1) expect(toyota_cars.length).to eq(1)