Interpolating Lists into Ecto.Query.fragment/1

I had this problem once before, and maybe there’s a better way to do this, but I’ll share how I solved it.

If you look closely at the error, Postgrex is telling you that instead of an integer type (or multiple integers separated by a comma), e.g. ... IN (1,2,3) it’s getting a list type, e.g. ... IN ([1,2,3]). So to fix this, you’ll need to convert the list into a binary e.g. "1,2,3" and modify your fragment SQL to have PostgreSQL convert the incoming binary to an array of integers using the PostgreSQL string_to_array() function and casting it’s that to an integer type.

Here’s your example fragment with the changes:

...
        fragment(
          "EXISTS (SELECT NULL
                     FROM OBJECT_TAGS o_t
                     JOIN TAGS t ON t.id = o_t.tag_id
                    WHERE t.id = ANY(string_to_array(?, ',')::integer[]))
                      AND o_t.object_id = ?
                 GROUP BY o_t.object_id
                   HAVING COUNT(DISTINCT t.name) = ?)",
           ^Enum.join(tag_ids, ","), # [1, 3, 5] -> "1,3,5"
...

Of course I didn’t test that code, but it should work. The Enum.join(tag_ids, ",") converts the list of integers into a binary e.g. “1,3,5” and that gets inserted into the string_to_array(?, ',')::integer[] in the fragment.

PostgreSQL gets what it needs and everyone is happy :slight_smile: