How to insert array using postgresql simple (Haskell)?

427 Views Asked by At

I am working on a Haskell API using Scotty and PostgreSQL-simple. I cannot figure out how to do an insert of a column containing an Array of Text. So far my queries have worked, but something about this one does not seem to compile well.

This is what I have:

addOrder :: Postgres r m => OrderIntent -> m ()
addOrder param =
  void . withConn $ \conn -> execute conn qry (orderIntentTable param, orderIntentItemsSlug param)
  where
    qry = "insert into orders (table, items, created_at, updated_at) values (?, ?, now(), now())"

My OrderIntent and its FromRow are:

data OrderIntent = OrderIntent
{ orderIntentTable :: Integer
, orderIntentItemsSlug :: [Text] 
} deriving(Eq, Show)

instance FromRow OrderIntent where
  fromRow = OrderIntent 
    <$> field
    <*> (fromPGArray <$> field)

And the error I am getting is:

• Could not deduce (Database.PostgreSQL.Simple.ToField.ToField
                          [Data.Text.Internal.Text])
        arising from a use of ‘execute’
      from the context: Postgres r m
        bound by the type signature for:
                   addOrder :: forall r (m :: * -> *).
                               Postgres r m =>
                               OrderIntent -> m ()
        at Core/Order/DAO.hs:11:1-47

I could not figure out how to use the PostgreSQL library to parse an Array of Text so that i can be inserted to the database. If any of you could help me I would really appreciate it!

PS: I also have this other blocker from a couple of days ago, if you happen to know about Scotty auth.

2

There are 2 best solutions below

1
On BEST ANSWER

Use PGArray.

execute conn qry (orderIntentTable param, PGArray (orderIntentItemsSlug param))
2
On

As you're inserting orderIntentItemsSlugs, you need a ToField instance for orderIntentItemsSlug (which is a [Text]). This is what your error tells you.

I recommend looking at the sources of other ToField instances to figure out how you want to do that (one hacky way would be to turn your field into a Text first, which already gas a ToField instance).

You could also write an orders table that relates an orderID to one item at a time, then you wouldn't have to write any instances at all.