2011-10-18 22 views
5

Veritabanına çok sayıda erişime sahip bir Happstack uygulaması oluşturmak istiyorum.Happstack'ta bir veritabanı Monad Stack nasıl oluşturulur?

itemsRequest :: ServerConfig -> ServerPart Response 
itemsRequest cf = dir "items" $ do 
    methodM [GET,HEAD] 
    liftIO $ noticeM (scLogger cf) "sended job list" 

    items <- runDBMonad (scDBConnString cf) $ getItemLists 

    case items of 
    (Right xs) -> ok $ toResponse $ show xs 
    (Left err) -> internalServerError $ toResponse $ show err 

olarak: Ben alt ve (ortada günlük yazar ile) üstüne bir veritabanı Yaz benzeri monad de IO ile Monad Stack her erişim, örneğin açık bir işlevi vardır için çalışacağını düşünüyorum:

getItemList :: MyDBMonad (Error [Item]) 
getItemList = do 
    -- etc... 

Ama Monad ve Monad Transformers (Bu konuda bilgi edinmek için bir egzersiz olarak bu soruya bakın) çok az bilgiye sahip ve ben nasıl nasıl IO kaldırmaya, Veritabanı Monad oluşturulmasını başlamak için hiçbir fikrim yok happstack'tan Database Stack'a ... vb. Bu durumda, herkesin de almak istiyorum değer veritabanı bağlantısı -

type MyMonad a = ReaderT DbHandle ServerPart a 

Reader monad trafo ask işlevini kullanarak erişilebilir tek bir değeri yapar:

+0

İçinde IO yapmak için 'unsafePerformIO' kullanmayı denedim. Happstack tamamen bir kombinasyon kullandığından, belki de IO'yu yapmanın tek yoludur. – Nybble

+0

@Wu Xingbo, elevio'nun elevio'yu liftIO ile yapmak mümkün, ancak başka bir monad kümesine kimin geçeceğini bilmiyorum. – Zhen

cevap

6

Büyük olasılıkla 'ReaderT' kullanmak istiyorum .

Burada, DbHandle veritabanınıza bir bağlantıdır.

'ReaderT' zaten tüm happstack-sunucu tipi sınıflarının bir örneğidir, tüm normal happstack-sunucu işlevleri bu monad içinde çalışacaktır.

Muhtemelen de veritabanı bağlantısı açmak ve kapatmak için yardımcı çeşit istiyorum

:

runMyMonad :: String -> MyMonad a -> ServerPart a 
runMyMonad connectionString m = do 
    db <- liftIO $ connect_to_your_db connectionString 
    result <- runReaderT m db 
    liftIO $ close_your_db_connection db 

(Burada 'parantez' gibi bir işlevi kullanmak daha iyi olabilir, ama ben bilmiyorum orada ServerPart monad için böyle bir işlemdir)

Oturum açma işlemini nasıl yapmak istediğinizi bilmiyorum - günlük dosyanızla nasıl etkileşim kurmayı planlıyorsunuz? Sonra

type MyMonad a = ReaderT (DbHandle, LogHandle) ServerPart a 

ve: Böyle bir şey

askDb :: MyMonad DbHandle 
askDb = fst <$> ask 

askLogger :: MyMonad LogHandle 
askLogger = snd <$> ask 

yetebilir. Daha sonra üst düzey işlevler yapmak için bu ilkelleri inşa edebilirsiniz. Ayrıca, ne olursa olsun, numaralı telefondan geçirilmek üzere runMyMonad'u değiştirmeniz gerekecektir.

Erişim sağlamak istediğiniz iki şeyden fazlasını aldıktan sonra, bir tuple yerine uygun kayıt türüne sahip olmak için ödeme yapar.

+2

Yan konu: bağlantı havuzu için http://hackage.haskell.org/package/resource-pool ve http://hackage.haskell.org/package/pool. Gerçi, ihtiyacınız olandan daha fazlası olabilir. Havuz ipucu için –

+0

teşekkürler! – Zhen

6

İşte benim gibi şaşkın yeni başlayanlar için yukarıdaki parçacıklardan derlenen bazı en az çalışma kodu.

AppConfig türüne bir şeyler koyun ve yanıt vericilerinizde ask ile yakalayın.

{-# LANGUAGE OverloadedStrings #-} 
module Main where 

import Happstack.Server 
import Control.Monad.Reader 
import qualified Data.ByteString.Char8 as C 

myApp :: AppMonad Response 
myApp = do 
    -- access app config. look mom, no lift! 
    test <- ask 

    -- try some happstack funs. no lift either. 
    rq <- askRq 
    bs <- lookBS "lol" 

    -- test IO please ignore 
    liftIO . print $ test 
    liftIO . print $ rq 
    liftIO . print $ bs 

    -- bye 
    ok $ toResponse ("Oh, hi!" :: C.ByteString) 

-- Put your stuff here. 
data AppConfig = AppConfig { appSpam :: C.ByteString 
          , appEggs :: [C.ByteString] } deriving (Eq, Show) 
config = AppConfig "THIS. IS. SPAAAAAM!!1" [] 

type AppMonad = ReaderT AppConfig (ServerPartT IO) 

main = simpleHTTP (nullConf {port=8001}) $ runReaderT myApp config {appEggs=["red", "gold", "green"]} 
İlgili konular