{-# LANGUAGE CPP #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -Wno-unused-top-binds #-} {-# OPTIONS_GHC -Wno-missing-methods #-} module Example ( TestApp , runTestApp , runTestAppWith -- * Person , Person(..) , person , getPeople , getPeopleNames , getName , nameAndAge -- * Post , Post(..) , post , getPosts , getPostTitles -- * Persistent , EntityField(..) , Unique(..) , migration ) where import Control.Arrow ((&&&)) import Control.Monad.IO.Class (MonadIO(..)) import Control.Monad.Trans.Resource (MonadResource, ResourceT, runResourceT) import Database.Persist.Sql (Entity(..), EntityField, Key, SelectOpt(..), Unique, toSqlKey) import Database.Persist.TH (mkMigrate, mkPersist, persistLowerCase, share, sqlSettings) #if !MIN_VERSION_persistent(2,13,0) import qualified Database.Persist.TH #endif import UnliftIO (MonadUnliftIO(..), wrappedWithRunInIO) import Control.Monad.IO.Rerunnable (MonadRerunnableIO) import Database.Persist.Monad import TestUtils.DB (BackendType(..), withTestDB) share [ mkPersist sqlSettings #if !MIN_VERSION_persistent(2,13,0) , Database.Persist.TH.mkDeleteCascade sqlSettings #endif , mkMigrate "migration" ] [persistLowerCase| Person name String age Int removedColumn String SafeToRemove UniqueName name deriving Show Eq Post title String #if MIN_VERSION_persistent(2,13,0) author PersonId editor PersonId Maybe #else author PersonId OnDeleteCascade editor PersonId Maybe OnDeleteCascade #endif deriving Show Eq |] deriving instance Eq (Unique Person) #if !MIN_VERSION_persistent_template(2,6,0) || MIN_VERSION_persistent_template(2,9,0) deriving instance Show (Unique Person) #endif -- Let tests use a literal number for keys instance Num (Key Person) where fromInteger = toSqlKey . fromInteger instance Num (Key Post) where fromInteger = toSqlKey . fromInteger newtype TestApp a = TestApp { unTestApp :: SqlQueryT (ResourceT IO) a } deriving ( Functor , Applicative , Monad , MonadIO , MonadRerunnableIO , MonadSqlQuery , MonadResource ) instance MonadUnliftIO TestApp where withRunInIO = wrappedWithRunInIO TestApp unTestApp runTestApp :: BackendType -> TestApp a -> IO a runTestApp backendType m = withTestDB backendType $ \pool -> runResourceT . runSqlQueryT pool . unTestApp $ do _ <- runMigrationSilent migration m runTestAppWith :: BackendType -> (SqlQueryEnv -> SqlQueryEnv) -> TestApp a -> IO a runTestAppWith backendType f m = withTestDB backendType $ \pool -> do let env = mkSqlQueryEnv pool f runResourceT . runSqlQueryTWith env . unTestApp $ do _ <- runMigrationSilent migration m {- Person functions -} person :: String -> Person person name = Person name 0 getName :: Entity Person -> String getName = personName . entityVal getPeople :: MonadSqlQuery m => m [Person] getPeople = map entityVal <$> selectList [] [Asc PersonId] getPeopleNames :: MonadSqlQuery m => m [String] getPeopleNames = map personName <$> getPeople nameAndAge :: Person -> (String, Int) nameAndAge = personName &&& personAge {- Post functions -} post :: String -> Key Person -> Post post title author = Post title author Nothing getPosts :: MonadSqlQuery m => m [Post] getPosts = map entityVal <$> selectList [] [] getPostTitles :: MonadSqlQuery m => m [String] getPostTitles = map postTitle <$> getPosts