Why Can't Haskell Separate PosgreSQL String into Fields?

Viewed 100

I am new to PostgreSQL.Simple so please forgive if question is dumb.

I am going through this tutorial: Postgresql Data Access with Haskell

I got the first demo program to run.

Now I am taking this function:

retrieveClient :: Connection -> Int -> IO [Only String]
retrieveClient conn cid = query conn "SELECT ticker FROM spot_daily WHERE id = ?" $ (Only cid)

and wish to modify it to return IO [(String, Integer, Float)].

So I wrote:

retrieveClient2 :: Connection -> Float -> IO [(String, Integer, Float)]
retrieveClient2 conn cid =  query conn "SELECT (ticker, timestamp, some_val) FROM spot_daily WHERE p_open > ?" $ (Only cid)

main :: IO ()
main = do
  conn <- connect localPG
  mapM_ print =<< (retrieveClient2 conn 50.0)

and I get this:

MyApp-exe.EXE: Incompatible {errSQLType = "record", errSQLTableOid = Nothing, errSQLField = "row", errHaskellType = "Text", errMessage = "types incompatible"}

It's common in the Haskell world to say, "Search for the type signature you want on Hackage!" but it's not clear to me from the error message what type signature would make GHC happy.

Is there a conversion function for this sort of thing? I tried doing this:

data MyStruct = { field1 :: String, field2 :: Integer, field3 :: Float} deriving (Eq, Show)

retrieveClient3 :: Connection -> Int -> IO [Only MyStruct]
retrieveClient3 conn cid = MyStruct (query conn "SELECT ticker FROM spot_daily WHERE id = ?" $ (Only cid))

but that results in a different error.

In response to a comment, here is schema for spot_daily:

                                     Table "public.spot_daily"
  Column   |         Type          | Collation | Nullable |                Default
-----------+-----------------------+-----------+----------+----------------------------------------
 id        | integer               |           | not null | nextval('spot_daily_id_seq'::regclass)
 ticker    | character varying(20) |           | not null |
 epoch     | bigint                |           | not null |
 p_open    | double precision      |           |          |
 p_close   | double precision      |           |          |
 p_high    | double precision      |           |          |
 p_low     | double precision      |           |          |
 synthetic | boolean               |           |          |
Indexes:
    "spot_daily_pkey" PRIMARY KEY, btree (id)
1 Answers

PostgreSQL types make a distinction between a "row" and a "record". As written (with parentheses), your SQL query is returning a record, which isn't handled by the FromRow instance for tuples.

SELECT (ticker, timestamp, some_val) FROM prices_daily WHERE p_open > ?

Changing the query (by removing the parentheses), makes it return a row, which postgresql-simple should be able to handle:

SELECT ticker, timestamp, some_val FROM prices_daily WHERE p_open > ?
Related