1

Suppose we have this postgresql schema:

CREATE TABLE "temp" (id  int, fields text[]);
INSERT INTO "temp" VALUES
  (1, array['abc', 'def']),
  (2, array['abc', 'def', 'jkl']),
  (3, array['abd', 'def']),
  (4, '{"1{c}1", a}');

The following works in plain SQL, returning rows 1 and 2 (@> is the "contains" operator in pg):

SELECT id, fields FROM temp WHERE "fields" @> '{def, abc}';

But the same in Doobie (with its postgresql extension):

import doobie._
import doobie.implicits._
import doobie.postgres.implicits._
val searchTerms = List("def", "abc")
fr"SELECT id, fields FROM temp WHERE fields @> $searchTerms"

Fails with:

org.postgresql.util.PSQLException: ERROR: operator does not exist: text[] @> character varying[]
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.

Casting the interpolated searchTerms value to text[] seems to solve the problem:

val searchTerms = List("def", "abc")
fr"SELECT id, fields FROM temp WHERE fields @> CAST($searchTerms AS text[])"

Similarly, I can change the type of the fields column from text[] to varchar[] in the database schema to avoid the cast, and that would also compile and return the correct rows.

My main problem is that I don't know why Doobie behaves that way. I will probably run into this same issue again with custom types, so I need to understand why $searchTerms decodes into varying[] and not text[], and what, if anything, I can do to change this behaviour so that I can keep the text[] column type and avoid the cast. I'm guessing there's probably an implicit instance somewhere controlling this, but I couldn't figure out what it is.

Nikita
  • 2,924
  • 1
  • 19
  • 25
  • 1
    Doobie maps `String` to `varchar` (more info [here](https://tpolecat.github.io/doobie/docs/12-Custom-Mappings.html)), and I you can't change that easily. Under the hood, text and varchar are the same (according to [this](https://stackoverflow.com/questions/4848964/difference-between-text-and-varchar-character-varying)), so migrating your table to varchar makes most sense in that situation I think. Regarding unexpected mappings, there are some issues with datetimes with timezones, but other than that I haven't stumbled upon anything else. – Andrey Patseev Dec 08 '20 at 12:31
  • You could also convert to array (which has instances defined) or define your own Doobie Meta instance. – Mateusz Kubuszok Dec 12 '20 at 18:46

0 Answers0