alevy / postgresql-orm

An Haskell ORM (Object Relational Mapping) and migrations DSL for PostgreSQL.
http://simple.cx
GNU General Public License v3.0
77 stars 12 forks source link

Does this library support array column types? #34

Closed chrissound closed 1 year ago

chrissound commented 1 year ago

I tried using a table column that is of type text[] NOT NULL, where the haskell type was [String], that does not seem to work as it fails with:

with error: SqlError {sqlState = "22P02", sqlExecStatus = FatalError, sqlErrorMsg = "malformed array literal: \"[\"testing\"]\"", sqlErrorDetail = "\"[\" must introduce explicitly-specified array dimensions.", sqlErrorHint = ""

The generated query seems to be something like:

INSERT INTO "server" ("name", tags") VALUES ('Test', '["testing"]');

Which seems to be JSON syntax instead of postgresql array syntax.


I've also tried a jsonb postgresql type, and a Data.Aeson.Value haskell type but get an error along the lines of:

with error: SqlError {sqlState = "22P02", sqlExecStatus = FatalError, sqlErrorMsg = "malformed array literal: \"[\"hiiiiiiii\"]\"", sqlErrorDetail = "\"[\" must introduce explicitly-specified array dimensions.", sqlErrorHint = ""
alevy commented 1 year ago

Hi!

The library defers to postgresql-simple for type conversion (and generally for communication with Postgres).

SQL arrays work but, but not with haskell lists, instead with Vectors. See https://hackage.haskell.org/package/postgresql-simple-0.6.5/docs/Database-PostgreSQL-Simple-ToField.html#t:ToField for the exact field types supported.

In your case, your Haskell type should probably be a Vector [String], though I'd generally recommend using the more performant ByteString or Text (so Vector [ByteString] or Vector [Text])

chrissound commented 1 year ago

Great thanks! Couldn't we write an instance for [] automatically though?

instance (ToField a) => ToField ([a]) where, or does this make things a bit wonky when it comes to GHC finding an instance?

I mean looking at the vector instance:

instance (ToField a) => ToField (Vector a) where
    toField = toField . PGArray . V.toList

I think the difference is just removing the V.toList.

I just tried this:

instance ToField a => ToField [a] where
  toField = toField . PGArray

And indeed it seems to hit the annoying overlapping instance issue. Oh well.

alevy commented 1 year ago

That's right. You can implement it in the module that ToField is defined (which is in a different library) or the module that [] is defined (which is somewhere in the bowls of GHC).