prowdsponsor / esqueleto

Bare bones, type-safe EDSL for SQL queries on persistent backends.
http://hackage.haskell.org/package/esqueleto
BSD 3-Clause "New" or "Revised" License
177 stars 51 forks source link

sum_ and friends can cause runtime type errors #148

Open enolan opened 7 years ago

enolan commented 7 years ago

sum_'s type is (PersistField a, PersistField b) => expr (Value a) -> expr (Value (Maybe b)). But sum of course cannot return any type. In Postgres, it returns numeric for bigints, which is represented as PersistRational. Details here. Example:

module Main where

import Control.Monad.IO.Class
import Control.Monad.Logger
import Database.Esqueleto
import Database.Persist
import Database.Persist.Postgresql
import Database.Persist.TH

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Number
   value Int
|]

connStr = "host=localhost dbname=test user=test password=test port=5432"

main :: IO ()
main = runStderrLoggingT $ withPostgresqlPool connStr 10 $ \pool -> liftIO $ do
    flip runSqlPersistMPool pool $ do
        runMigration migrateAll

        johnId <- insert $ Number 5
        janeId <- insert $ Number 22
        return ()
        _ :: [Value (Maybe Int)] <- select $
          from $ \number -> do
            return $ sum_ $ number ^. NumberValue
        return ()
enolan at behemoth in ~/junk/esqueleto-bug  
$ stack exec esqueleto-bug
[Debug#SQL] INSERT INTO "number"("value") VALUES(?) RETURNING "id"; [PersistInt64 5]
[Debug#SQL] INSERT INTO "number"("value") VALUES(?) RETURNING "id"; [PersistInt64 22]
[Debug#SQL] SELECT SUM("number"."value")
FROM "number"
; []
esqueleto-bug: PersistMarshalError "int Expected Integer, received: PersistRational (27 % 1)"

I suppose it needs a type family/fundep. Test case repo here.