如何在Yesod / Persistent中正确使用runDB

时间:2014-01-02 20:10:39

标签: haskell yesod persistent

我有以下持久模型:

User
    ident Text
    password Text Maybe
     UniqueUser ident
    deriving Typeable

Payment
    timestamp UTCTime
    from UserId
    to UserId
    amount Int

我正在尝试构建一个页面,显示数据库中所有付款的列表,每个付款链接指向付款/收到付款的用户。目前我的代码是:

getPaymentsR :: Handler Html
getPaymentsR = do
    let payments = map addFromTo $ runDB $ selectList [] [Desc PaymentTimestamp]
    defaultLayout
        [whamlet|
            <h3> Payments
            <ul>
                $forall (key, value, from, to) <- payments
                    <li>
                        <a href=@{UserR $ paymentFrom value}> #{from} </a> paid #{paymentAmount value} to <a href=@{UserR $ paymentTo value}> #{to} </a> on #{printDay $ paymentTimestamp value}
            $if null payments
                <ul>
                    <li> No payments
        |]
    where 
        addFromTo :: Entity Payment -> (Key Payment, Payment, Text, Text)
        addFromTo (Entity key val) = do
            let from = runDB $ get404 $ paymentFrom val
            let to = runDB $ get404 $ paymentTo val
            (key, val, userIdent from, userIdent to)

但是我收到以下错误:

Handler/Payment.hs:9:36:
    Couldn't match expected type `[Entity Payment]'
                with actual type `HandlerT site0 IO [Entity Payment]'
    In the second argument of `($)', namely
      `runDB $ selectList [] [Desc PaymentTimestamp]'
    In the expression:
      map addFromTo $ runDB $ selectList [] [Desc PaymentTimestamp]
    In an equation for `payments':
        payments
          = map addFromTo $ runDB $ selectList [] [Desc PaymentTimestamp]

Handler/Payment.hs:26:34:
    Couldn't match expected type `User'
                with actual type `HandlerT site0 IO User'
    In the first argument of `userIdent', namely `from'
    In the expression: userIdent from
    In a stmt of a 'do' block: (key, val, userIdent from, userIdent to)

Handler/Payment.hs:26:50:
    Couldn't match expected type `User'
                with actual type `HandlerT site1 IO User'
    In the first argument of `userIdent', namely `to'
    In the expression: userIdent to
    In a stmt of a 'do' block: (key, val, userIdent from, userIdent to)

有人知道我做错了什么,或者如何解决这些错误? 我认为它与Extracting database field values inside a Handler有很大关系。 但是我仍无法解决上述链接中的信息问题。

更新

使用Michael Snoyman的答案编辑我的代码后,我的新addFromTo函数仍然会出现类型错误:

addFromTo :: Entity Payment -> (Key Payment, Payment, Text, Text)
addFromTo (Entity key val) = do
    from' <- runDB $ get404 $ paymentFrom val
    to' <- runDB $ get404 $ paymentTo val
    let from = userIdent from'
    let to = userIdent to'
    (key, val, from, to)

1 个答案:

答案 0 :(得分:3)

这里的问题是你将monadic动作视为纯粹的价值。解决这个问题的更简单方法是使用do-notation和slurp运算符:

payments' <- runDB $ selectList [] [Desc PaymentTimestamp]
let payments = map addFromTo payments'

或者如果你想获得更好的(不一定推荐):

payments <- fmap (map addFromTo) $ runDB $ selectList [] [Desc PaymentTimestamp]