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
178 stars 51 forks source link

can't use existing Value in delete where_ #52

Closed joeyh closed 10 years ago

joeyh commented 10 years ago

Can't use an existing Value in a delete where_

I found the test case below very confusing. As far as I could tell, the select query returned a Value Key, which should have been the type needed in the delete where_.

However this caused a error:

   Couldn't match type `KeyBackend
                       SqlBackend (CachedKeyGeneric SqlBackend)'
              with `Value (KeyBackend backend0 (CachedKeyGeneric backend0))'

The fix seems to be to unpack the Value, and re-pack it with val inside the where_ clause. (Specifically, replace the first k2 with Value k2, and the second k2 with val k2.)

Am I missing something in the documentation that explains how to do this, or is the inability to unify these types a bug?

{-# LANGUAGE QuasiQuotes, TypeFamilies, GeneralizedNewtypeDeriving,     TemplateHaskell,
         OverloadedStrings, GADTs, FlexibleContexts #-}
import Database.Persist.TH
import Database.Persist.Sqlite (runSqlite)
import Control.Monad.IO.Class (liftIO)
import Control.Monad
import Database.Esqueleto hiding (Key)

share [mkPersist sqlSettings, mkSave "entityDefs", mkMigrate "migrateAll"] [persistLowerCase|
CachedKey
  key String
  UniqueKey key
  deriving Show

AssociatedFiles
  key CachedKeyId Eq
  file FilePath
  UniqueKeyFile key file
  deriving Show
|]

main :: IO ()
main = runSqlite "foo.db" $ do
    runMigration migrateAll

    forM_ [1..30000] $ \i -> do
            k <- insert $ CachedKey (show i)
            liftIO $ print k
            insert $ AssociatedFiles k (show i)

            [(k2)] <- select $ from $ \k -> do
                    where_ (k ^. CachedKeyKey ==. val (show i))
                    return (k ^. CachedKeyId)
            liftIO $ print (2, k2)
            delete $ from $ \f -> do
                    where_ (f ^. AssociatedFilesKey ==. k2)
meteficha commented 10 years ago
Value :: typ -> Value typ
val :: PersistField typ => typ -> expr (Value typ)

Everything is working as expected. Value is just a newtype used to tag values and distinguish them from Entitiys. OTOH, val does a lot more by creating an expression.

On most cases you should unpack the Value as soon as you get it.