Repository: rails/rails
File: activerecord/test/cases/relation/where_clause_test.rb (Ruby)

Code before:

    test "merge with or/and correctly handles SQL literals and attributes" do
      a = WhereClause.new([
        table["id"].eq(1),
        Arel::Nodes::Grouping.new(Arel.sql("foo = bar"))
      ])
      b = (a + WhereClause.new([table["attr_1"].eq("val_1")])).or(
        WhereClause.new([table["attr_2"].eq("val_2")])
      )

      expected = WhereClause.new([
        table["id"].eq(1),
        Arel::Nodes::Grouping.new(Arel.sql("foo = bar")),
        Arel::Nodes::Grouping.new(
          Arel::Nodes::Or.new([
            Arel::Nodes::And.new([
              table["id"].eq(1),
              Arel::Nodes::Grouping.new(Arel.sql("foo = bar")),
              table["attr_1"].eq("val_1")
            ]),
            table["attr_2"].eq("val_2")
          ])
        )
      ])

      assert_equal expected, a.merge(b)
    end

    test "a clause knows if it is empty" do
      assert_empty WhereClause.empty
      assert_not_empty WhereClause.new(["anything"])
    end

    test "invert cannot handle nil" do
      where_clause = WhereClause.new([nil])

      assert_raises ArgumentError do
        where_clause.invert
      end
    end

    test "invert wraps the ast inside a NAND node" do
      original = WhereClause.new([
        table["id"].in([1, 2, 3]),
        table["id"].not_in([1, 2, 3]),
        table["id"].eq(1),
        table["id"].not_eq(2),
        table["id"].gt(1),
        table["id"].gteq(2),
        table["id"].lt(1),
        table["id"].lteq(2),

Review comment (bug):
Without patch:
![Screenshot 2025-01-09 at 7 38 56 pm](https://github.com/user-attachments/assets/1ae7be48-f8d0-4cb2-a13a-f5cb124cfad2)

The matching expectation for the failure would be:
```ruby
      expected = WhereClause.new([
        # table["id"].eq(1),
        Arel::Nodes::Grouping.new(Arel.sql("foo = bar")),
        Arel::Nodes::Grouping.new(
          Arel::Nodes::Or.new([
            Arel::Nodes::And.new([
              table["id"].eq(1),
              Arel::Nodes::Grouping.new(Arel.sql("foo = bar")),
              table["attr_1"].eq("val_1")
            ]),
            table["attr_2"].eq("val_2")
          ])
        )
      ])
```

Code after:

    test "merge with or/and correctly handles SQL literals and attributes" do
      a = WhereClause.new([
        table["id"].eq(1),
        Arel::Nodes::Grouping.new(Arel.sql("foo = bar"))
      ])
      b = (a + WhereClause.new([table["attr_1"].eq("val_1")])).or(
        WhereClause.new([table["attr_2"].eq("val_2")])
      )

      expected = WhereClause.new([
        table["id"].eq(1),
        Arel::Nodes::Grouping.new(Arel.sql("foo = bar")),
        Arel::Nodes::Grouping.new(
          Arel::Nodes::Or.new([
            Arel::Nodes::And.new([
              table["id"].eq(1),
              Arel::Nodes::Grouping.new(Arel.sql("foo = bar")),
              table["attr_1"].eq("val_1")
            ]),
            table["attr_2"].eq("val_2")
          ])
        )
      ])

      assert_equal expected, a.merge(b)
    end

    test "a clause knows if it is empty" do
      assert_empty WhereClause.empty
      assert_not_empty WhereClause.new([Arel.sql("anything")])
    end

    test "invert cannot handle nil" do
      where_clause = WhereClause.new([nil])

      assert_raises ArgumentError do
        where_clause.invert
      end
    end

    test "invert wraps the ast inside a NAND node" do
      original = WhereClause.new([
        table["id"].in([1, 2, 3]),
        table["id"].not_in([1, 2, 3]),
        table["id"].eq(1),
        table["id"].not_eq(2),
        table["id"].gt(1),
        table["id"].gteq(2),
        table["id"].lt(1),
        table["id"].lteq(2),