123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- {-# LANGUAGE OverloadedStrings #-}
- {-# LANGUAGE QuasiQuotes #-}
- {-# LANGUAGE TypeFamilies #-}
- import Control.Monad.Logger
- import Control.Monad.Trans.Resource
- import Control.Monad.Reader
- import Data.List.NonEmpty (NonEmpty(..))
- import Data.Text (Text)
- import System.Log.FastLogger
- import Test.Hspec
- import Test.HUnit ((@?=))
- import UnliftIO
- import Database.Persist.Sql
- import Database.Persist.Sql.Raw.QQ
- import Database.Persist.Sqlite
- import PersistTestPetType
- import PersistentTestModels
- main :: IO ()
- main = hspec specs
- _debugOn :: Bool
- _debugOn = False
- sqlite_database_file :: Text
- sqlite_database_file = "testdb.sqlite3"
- sqlite_database :: SqliteConnectionInfo
- sqlite_database = mkSqliteConnectionInfo sqlite_database_file
- runConn :: MonadUnliftIO m => SqlPersistT (LoggingT m) t -> m ()
- runConn f = do
- let debugPrint = _debugOn
- let printDebug = if debugPrint then print . fromLogStr else void . return
- flip runLoggingT (\_ _ _ s -> printDebug s) $ do
- _ <- withSqlitePoolInfo sqlite_database 1 $ runSqlPool f
- return ()
- db :: SqlPersistT (LoggingT (ResourceT IO)) () -> IO ()
- db actions = do
- runResourceT $ runConn $ do
- runMigration testMigrate
- actions
- transactionUndo
- specs :: Spec
- specs = describe "persistent-qq" $ do
- it "sqlQQ/?-?" $ db $ do
- ret <- [sqlQQ| SELECT #{2 :: Int}+#{2 :: Int} |]
- liftIO $ ret @?= [Single (4::Int)]
- it "sqlQQ/?-?" $ db $ do
- ret <- [sqlQQ| SELECT #{5 :: Int}-#{3 :: Int} |]
- liftIO $ ret @?= [Single (2::Int)]
- it "sqlQQ/NULL" $ db $ do
- ret <- [sqlQQ| SELECT NULL |]
- liftIO $ ret @?= [Nothing :: Maybe (Single Int)]
- it "sqlQQ/entity" $ db $ do
- let insert'
- :: PersistStore backend
- => PersistEntity val
- => PersistEntityBackend val ~ BaseBackend backend
- => MonadIO m
- => val
- -> ReaderT backend m (Key val, val)
- insert' v = insert v >>= \k -> return (k, v)
- (p1k, p1) <- insert' $ Person "Mathias" 23 Nothing
- (p2k, p2) <- insert' $ Person "Norbert" 44 Nothing
- (p3k, _ ) <- insert' $ Person "Cassandra" 19 Nothing
- (_ , _ ) <- insert' $ Person "Thiago" 19 Nothing
- (a1k, a1) <- insert' $ Pet p1k "Rodolfo" Cat
- (a2k, a2) <- insert' $ Pet p1k "Zeno" Cat
- (a3k, a3) <- insert' $ Pet p2k "Lhama" Dog
- (_ , _ ) <- insert' $ Pet p3k "Abacate" Cat
- let runQuery
- :: (RawSql a, Functor m, MonadIO m)
- => Int
- -> ReaderT SqlBackend m [a]
- runQuery age =
- [sqlQQ|
- SELECT ??, ??
- FROM
- ^{Person},
- ^{Pet}
- WHERE ^{Person}.@{PersonAge} >= #{age}
- AND ^{Pet}.@{PetOwnerId} = ^{Person}.@{PersonId}
- ORDER BY ^{Person}.@{PersonName}
- |]
- ret <- runQuery 20
- liftIO $ ret @?= [ (Entity p1k p1, Entity a1k a1)
- , (Entity p1k p1, Entity a2k a2)
- , (Entity p2k p2, Entity a3k a3) ]
- ret2 <- runQuery 20
- liftIO $ ret2 @?= [ (Just (Entity p1k p1), Just (Entity a1k a1))
- , (Just (Entity p1k p1), Just (Entity a2k a2))
- , (Just (Entity p2k p2), Just (Entity a3k a3)) ]
- ret3 <- runQuery 20
- liftIO $ ret3 @?= [ Just (Entity p1k p1, Entity a1k a1)
- , Just (Entity p1k p1, Entity a2k a2)
- , Just (Entity p2k p2, Entity a3k a3) ]
- it "sqlQQ/order-proof" $ db $ do
- let p1 = Person "Zacarias" 93 Nothing
- p1k <- insert p1
- let runQuery
- :: (RawSql a, Functor m, MonadIO m)
- => ReaderT SqlBackend m [a]
- runQuery = [sqlQQ| SELECT ?? FROM ^{Person} |]
- ret1 <- runQuery
- ret2 <- runQuery :: (MonadIO m) => SqlPersistT m [Entity (ReverseFieldOrder Person)]
- liftIO $ ret1 @?= [Entity p1k p1]
- liftIO $ ret2 @?= [Entity (RFOKey $ unPersonKey p1k) (RFO p1)]
- it "sqlQQ/OUTER JOIN" $ db $ do
- let insert' :: (PersistStore backend, PersistEntity val, PersistEntityBackend val ~ BaseBackend backend, MonadIO m)
- => val -> ReaderT backend m (Key val, val)
- insert' v = insert v >>= \k -> return (k, v)
- (p1k, p1) <- insert' $ Person "Mathias" 23 Nothing
- (p2k, p2) <- insert' $ Person "Norbert" 44 Nothing
- (a1k, a1) <- insert' $ Pet p1k "Rodolfo" Cat
- (a2k, a2) <- insert' $ Pet p1k "Zeno" Cat
- ret <- [sqlQQ|
- SELECT ??, ??
- FROM ^{Person}
- LEFT OUTER JOIN ^{Pet}
- ON ^{Person}.@{PersonId} = ^{Pet}.@{PetOwnerId}
- ORDER BY ^{Person}.@{PersonName}
- |]
- liftIO $ ret @?= [ (Entity p1k p1, Just (Entity a1k a1))
- , (Entity p1k p1, Just (Entity a2k a2))
- , (Entity p2k p2, Nothing) ]
- it "sqlQQ/values syntax" $ db $ do
- let insert' :: (PersistStore backend, PersistEntity val, PersistEntityBackend val ~ BaseBackend backend, MonadIO m)
- => val -> ReaderT backend m (Key val, val)
- insert' v = insert v >>= \k -> return (k, v)
- (p1k, p1) <- insert' $ Person "Mathias" 23 (Just "red")
- (_ , _ ) <- insert' $ Person "Norbert" 44 (Just "green")
- (p3k, p3) <- insert' $ Person "Cassandra" 19 (Just "blue")
- (_ , _ ) <- insert' $ Person "Thiago" 19 (Just "yellow")
- let
- colors = Just "blue" :| Just "red" : [] :: NonEmpty (Maybe Text)
- ret <- [sqlQQ|
- SELECT ??
- FROM ^{Person}
- WHERE ^{Person}.@{PersonColor} IN %{colors}
- |]
- liftIO $ ret @?= [ (Entity p1k p1)
- , (Entity p3k p3) ]
|