3

次のモデルがあるとします。

Person
    stackOverflowUser Bool
    age Int Maybe

Esqueleto (および Yesod) を使用して、Stack Overflow ユーザーの平均年齢を取得したいとします。型シグネチャを持つ関数を作成したい:

userAge :: Handler (Maybe Int)

これまでのところ、私は次のものを持っています:

userAge :: Handler [Value (Maybe Int)]
userAge = runDB $
    select $
    from $ \person -> do
    where_ (person ^. PersonStackOverflowUser ==. val True)
    return joinV $ avg_ (person ^. PersonAge)

[Value (Maybe Int)] になりますが、「Maybe Int」に戻る必要があります。やってみた

mapM_ unValue userAge

しかし、何らかの理由で、そうすると型エラーが発生し、[Maybe Int] ではなく [Maybe ()] が返されました... さらに、上記のコードの最後の行には次のようにすべきだと思います。

person ?. PersonAge

それよりも

person ^. PersonAge

PersonAge は NULL になる可能性があるため、変更すると型エラーが発生します。

avg_ :: (PersistField a, PersistField b) => expr (Value a) -> expr (Value (Maybe b))
(^.) :: (PersistEntity val, PersistField typ) => expr (Entity val) -> EntityField val typ -> expr (Value typ)
(?.) :: (PersistEntity val, PersistField typ) => expr (Maybe (Entity val)) -> EntityField val typ -> expr (Value (Maybe typ))

これはおそらく私が思っているよりも簡単ですが、Esqueleto で集計関数を使用するための例をオンラインで見つけることができません。

生のSQLでもいいと思いますが、できればEsqueletoでやってみたいです。

4

1 に答える 1

3

とった!最後に、型エラーに頭を悩ませて、これを思いつきました:

import Safe (headMay)
import Control.Monad (join)
import Database.Esqueleto
-- other misc Yesod imports

userAge :: Handler (Maybe Int)
userAge = do
    a <- runDB $ select $
                 from $ \person -> do
                 where_ (person ^. PersonStackOverflowUser ==. val True)
                 return $ joinV $ avg_ (person ^. PersonAge)
    return $ join (headMay (map unValue a))

"person ^.PersonAge" は問題を引き起こしているようには見えません。null値とnull以外の値でテストしました。「?」だと思います。operator は他の状況のた​​めに予約されています。

うまくいけば、これは他の誰かがそれを理解する時間を節約します!

于 2014-09-18T11:47:24.327 に答える