2011-10-18 9 views
5

मैं एक डेटाबेस में बहुत सी पहुंच के साथ एक हैप्स्टैक एप्लिकेशन बनाना चाहता हूं। मुझे लगता है कि नीचे और शीर्ष पर एक डाटाबेस लिखें की तरह इकाई (बीच में लॉग लेखक के साथ) पर आईओ के साथ एक इकाई ढेर प्रत्येक एक्सेस, उदाहरण में एक स्पष्ट कार्यों के लिए काम करेंगे:हैप्स्टैक में डेटाबेस मोनाड स्टैक कैसे बनाएं?

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 

के साथ:

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

लेकिन मैं इकाई और इकाई ट्रांसफॉर्मर (मैं एक व्यायाम इसके बारे में जानने के लिए के रूप में इस सवाल देखें) का कम ज्ञान है, और मुझे कैसे डाटाबेस इकाई के निर्माण शुरू करने के लिए, कैसे लिफ्ट करने के लिए आईओ पता नहीं है खुशहाल से डाटाबेस स्टैक तक ... आदि। इस मामले में, मूल्य हम चाहते हैं कि हर कोई कम से प्राप्त करने के लिए डेटाबेस कनेक्शन है -

type MyMonad a = ReaderT DbHandle ServerPart a 

Reader इकाई ट्रांसफार्मर एकल मान ask समारोह का उपयोग कर सुलभ बना देता है:

+0

मैंने आईओओ करने के लिए 'unsafePerformIO' का उपयोग करने की कोशिश की। चूंकि हैप्स्टैक पूरी तरह से संयोजन का उपयोग करता है, शायद यह आईओ करने का आपका एकमात्र तरीका है। – Nybble

+0

@Wu Xingbo, लिफ्टियो के साथ खुशहाल पर आईओ करना संभव है, लेकिन मुझे नहीं पता कि कौन सा मोनैड स्टैक पास करना है। – Zhen

उत्तर

6

आप की संभावना 'ReaderT' का उपयोग करना चाहते ।

यहां, DbHandle आपके डेटाबेस से कुछ कनेक्शन है।

क्योंकि 'रीडर टी' पहले से ही सभी खुशहाल-सर्वर प्रकार-वर्गों का एक उदाहरण है, सभी सामान्य happstack-server फ़ंक्शन इस monad में काम करेंगे।

आप शायद भी डेटाबेस कनेक्शन खोलने के लिए और बंद करने के लिए सहायक के कुछ प्रकार हैं:

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 

(यह ब्रैकेट 'यहाँ की तरह एक समारोह का उपयोग करने के लिए बेहतर हो सकता है, लेकिन मैं नहीं जानता कि वहाँ सर्वरपार्ट मोनैड के लिए ऐसा एक ऑपरेशन है)

मुझे नहीं पता कि आप लॉगिंग कैसे करना चाहते हैं - आप अपनी लॉग-फ़ाइल से कैसे बातचीत करने की योजना बना रहे हैं?

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

और उसके बाद: की तरह कुछ

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

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

पर्याप्त हो सकता है। फिर आप उन उच्चतम कार्यों को बनाने के लिए उन प्राइमेटिव्स पर निर्माण कर सकते हैं। में जो भी हो, आपको runMyMonad को बदलने की आवश्यकता होगी।

एक बार जब आप दो से अधिक चीजें प्राप्त करते हैं तो आप इसे एक्सेस करना चाहते हैं, एक टुपल के बजाय उचित रिकॉर्ड प्रकार प्राप्त करने का भुगतान करता है।

+2

साइड विषय: कनेक्शन पूलिंग के लिए http://hackage.haskell.org/package/resource-pool और http://hackage.haskell.org/package/pool है। हालांकि, आपको इसकी आवश्यकता से अधिक हो सकता है। पूल टिप के लिए –

+0

धन्यवाद! – Zhen

6

यहां मेरे जैसे भ्रमित नए लोगों के लिए ऊपर स्निपेट से संकलित कुछ न्यूनतम काम कोड है।

आप AppConfig प्रकार में सामान डालते हैं और अपने प्रतिक्रिया निर्माताओं के अंदर ask के साथ इसे पकड़ते हैं।

{-# 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"]} 
संबंधित मुद्दे