Translating SQL query with row constructors (?) into Ecto

Hi all,

I have a table books with columns name and version. I want to search for books matching one of the provided pairs of (name, version). The SQL query looks like this:

select * from public.books
where (name, version) in (('ruby', 'v1'), ('ruby', 'v2'), ('elixir', 'v1'))

What I have tried:

signatures = [{"ruby", "v1"}, {"ruby", "v2"}, {"elixir", "v1"}]
from(b in Book,
  where: fragment("(?, ?) IN (?)", b.name, b.version, ^signatures)
)

This fails with:

** (DBConnection.EncodeError) Postgrex expected a tuple, got [{“ruby”, “v1”}, {“ruby”, “v2”}, {“elixir”, “v1”}]. Please make sure the value you are passing matches the definition in your table or in your query or convert the value accordingly.

Well, I tried a few more options, but they made even less sense. I feel like such a simple expression should be possible to express in Ecto?

(I am not even sure how this constructions (col1, col2, …) are called in SQL but I suspect this is row constructors, because I can replace my query with select * from public.books where ROW(name, version) in (ROW('ruby', '1'), ROW(...), ...)) and it works the same.

Thanks!

This can be accomplished with the values query API. Ecto.Query.API — Ecto v3.14.0
You can join with the values using the name and version column.

This comes up from time to time, but I haven’t seen a “great” solution for it. Here’s some previous threads you might find relevant:

You might even be interested in not translating at all and just implementing Enumerable on top of GitHub - elixir-dbvisor/sql: SQL provides state-of-the-art, high-performance SQL integration for Elixir, built to handle extreme concurrency with unmatched expressiveness and ergonomic query composition. Write safe, composable, parameterized queries directly, without translating to Ecto or any ORM. · GitHub it’s still in active development but main is conformant to SQL 2016

Thanks for the links to the past threads!

I think the solution described in one of the answers works for me and generates exactly the query that I want.

Great library!