Use visitor pattern in ToSql#HomogeneousIn to produce Attribute sql

In `ToSql`, operators that generate the sql for an `Attribute` use `visit(o.left, collector)`
This can be seen in `Equality` (and friends), `Case`, `SelectStatement`, and `In`.

`HomogeneousIn` manually produces the sql for an `Attribute`, introduced in 72fd0bae
This change makes `HomogeneousIn` follow the pattern.
This commit is contained in:
Keenan Brock 2022-07-22 13:13:42 -04:00
parent 80ba888cc1
commit 07d2407bee
No known key found for this signature in database
GPG Key ID: DDF03448455882FC
3 changed files with 53 additions and 10 deletions

@ -36,14 +36,6 @@ def right
attribute.quoted_array(values)
end
def table_name
attribute.relation.table_alias || attribute.relation.name
end
def column_name
attribute.name
end
def casted_values
type = attribute.type_caster

@ -333,7 +333,7 @@ def visit_Arel_Nodes_Grouping(o, collector)
def visit_Arel_Nodes_HomogeneousIn(o, collector)
collector.preparable = false
collector << quote_table_name(o.table_name) << "." << quote_column_name(o.column_name)
visit o.left, collector
if o.type == :in
collector << " IN ("
@ -350,7 +350,6 @@ def visit_Arel_Nodes_HomogeneousIn(o, collector)
end
collector << ")"
collector
end
def visit_Arel_SelectManager(o, collector)

@ -0,0 +1,52 @@
# frozen_string_literal: true
require_relative "../helper"
require "active_record/type_caster/map"
require "active_model"
class Arel::Nodes::HomogeneousInTest < Arel::Spec
def test_in
table = Arel::Table.new :users, type_caster: fake_pg_caster
expr = Arel::Nodes::HomogeneousIn.new(["Bobby", "Robert"], table[:name], :in)
_(expr.to_sql).must_be_like %{
"users"."name" IN (?, ?)
}
end
def test_custom_attribute_node
table = Arel::Table.new :users, type_caster: fake_pg_caster
node = TypedNode.new("COALESCE",
[table[:nickname], table[:name]],
STRING_TYPE
)
expr = Arel::Nodes::HomogeneousIn.new(["Bobby", "Robert"], node, :in)
_(expr.to_sql).must_be_like %{
COALESCE("users"."nickname", "users"."name") IN (?, ?)
}
end
private
STRING_TYPE = ActiveModel::Type::String.new.freeze
# this is a named function that also has a data type
class TypedNode < Arel::Nodes::NamedFunction
attr_reader :type_caster
def initialize(name, expr, type)
super(name, expr, nil)
@type_caster = type
end
end
# map that converts attribute names to a caster
def fake_pg_caster
Object.new.tap do |caster|
def caster.type_for_attribute(attr_name)
STRING_TYPE
end
end
end
end