beam icon indicating copy to clipboard operation
beam copied to clipboard

Literal expressions fail to parse when returned from Postgres query

Open ollef opened this issue 6 years ago • 5 comments

Hey again!

Running this:

import Database.Beam
import Database.Beam.Postgres
import Database.Beam.Postgres.Syntax
import Data.Text (Text)

test :: Connection -> IO ()
test conn = do
  let
    t :: QExpr PgExpressionSyntax s Text
    t = "abc"

  result <- withDatabaseDebug putStrLn conn (runSelectReturningOne (select (pure t)) :: Pg (Maybe Text))
  print result

results in:

SELECT 'abc' AS "res0"
testapp: PgRowParseError (PgRowCouldNotParseField 0)

It seems like the error can be fixed by casting the value to the right type, i.e. by making the query SELECT ('abc'::text) AS "res0". I suppose the parser (which might be inherited from postgres-simple?) is strict about what types it allows whereas the printer outputs string literals which have unknown type until you cast them (pg_typeof('abc') is unknown).

Several (most?) other types also have this problem.

Cheers!

ollef avatar Jan 25 '19 15:01 ollef

Opaleye chose to cast all literals explicitly. There might be some useful information in the pull request (https://github.com/tomjaguarpaw/haskell-opaleye/pull/412) and issue (https://github.com/tomjaguarpaw/haskell-opaleye/issues/253). https://github.com/tomjaguarpaw/haskell-opaleye/issues/377 was a result of this work, so it may be worth also pre-empting that.

ocharles avatar Jan 25 '19 15:01 ocharles

Interesting. I hadn't thought of that use case, but yeah, explicit casting is a good idea.

tathougies avatar Jan 25 '19 22:01 tathougies

So I've been trying to implement this. One issue is that there is no 1-to-1 mapping of haskell to postgres types, so it's not always clear what type should be given.

There is a notion of default type, but it's not necessarily the only type that could fit. For example, beam would normally allow a literal Int to be used as a byte-value integer, even if that's not 100% correct. This fix could introduce many type errors.

Any thoughts?

tathougies avatar Feb 01 '19 17:02 tathougies

In rel8 I decided that one Haskell type = one postgresql type (note that doesn't imply the other direction). I just found that much easier, you're basically generating SQL from Haskell so it's easiest to be able to say "this type maps to this database type".

ocharles avatar Feb 01 '19 18:02 ocharles

That certainly seems reasonable...

tathougies avatar Feb 01 '19 18:02 tathougies