postgresqlhaskellpostgresql-simple

Error of `Incompatible {errSQLType = "varchar",...` for simple select query using postgresql-simple


I have defined a PostgreSQL table as follows:

> \d+ public."Users"
                                                                   Table "public.Users"
   Column    |           Type           | Collation | Nullable |               Default               | Storage  | Compression | Stats target | Description 
-------------+--------------------------+-----------+----------+-------------------------------------+----------+-------------+--------------+-------------
 id          | integer                  |           | not null | nextval('"Users_id_seq"'::regclass) | plain    |             |              | 
 username    | character varying(255)   |           | not null |                                     | extended |             |              | 
 userId      | character varying(255)   |           |          |                                     | extended |             |              | 

I am trying to query that table using postgresql-simple:

  maybeUsername <- liftIO (listToMaybe <$> query conn "SELECT username FROM public.\"Users\" WHERE \"userId\" = ?" (Only userId) :: IO (Maybe String))
  case maybeUsername of
    Just username -> liftIO $ putStrLn $ "Username is " ++ username
    Nothing -> liftIO $ putStrLn $ "Could not find a record for userId " ++ userId

For some reason I am getting a following error:

Incompatible {errSQLType = "varchar", errSQLTableOid = Just (Oid 24782), errSQLField = "username", errHaskellType = "Char", errMessage = ""}

Any ideas how to fix it?


Solution

  • The library struggles to infer the type when a single column is returned (documented here: https://hackage.haskell.org/package/postgresql-simple-0.6.5/docs/Database-PostgreSQL-Simple.html#g:4). Hence we need to fix that by doing Only String instead of String.

    This way it works as expected:

      usernames <- liftIO (query conn "SELECT username FROM public.\"Users\" WHERE \"userId\" = ?" (Only userId) :: IO [Only String])
      liftIO $ putStrLn $ "Usernames are " ++ intercalate ", " (map fromOnly usernames)