2019年4月23日火曜日

esqueletoでjoinとかイケてないcountとか

ちょっと癖が強いesqueletoですが、やはりhaskellの型安全なところでできるのがいい感じになる、まぁそんな個人的な感想はどうでもいいよっていつも言われるが...

こんな構成のデータベースにある3テーブルの各レコードをusr_member_idでjoinしてとるSQLを書いてみた



でコード、yesodのHandlerモナドの中から呼んでいるのでHandler Appになっているのは許してもらうとしてこんな感じ

getUsers :: Param -> HandlerFor App ([(E.Entity UsrMember, E.Value Text, E.Value Int)], Int)
getUsers p = runDB $ do
    let pagePerLine = fromIntegral $ unPagePerLine p
        page = fromIntegral $ unPageNum p
        reqId = fromIntegral $ unReqId p
        typeIds = [1, 2]
        (ageFrom, ageTo) = (unAgeFrom p, unAgeTo p)
        baseQuery = E.from $ \(usrMember `E.InnerJoin` usrImage `E.InnerJoin` usrAgeView) -> do
            E.on $ usrMember E.^. UsrMemberUsrMemberId E.==. usrAgeView E.^. UsrAgeViewUid
            E.on $ usrMember E.^. UsrMemberUsrMemberId E.==. usrImage E.^. UsrImageUsrId
            E.where_ $ do
                let reqQuery = usrMember E.^. UsrMemberReqId E.==. E.val reqId
                    ageQuery = usrAgeView E.^. UsrAgeViewAge E.>=. E.val ageFrom 
                             E.&&. usrAgeView E.^. UsrAgeViewAge E.<=. E.val ageTo
                usrMember E.^. UsrMemberTypeId `E.in_` E.valList typeIds
                    E.&&. (if reqId > 0 then reqQuery else E.val True)
                    E.&&. (if ageFrom > 0 && ageTo > 0 then ageQuery else E.val True)
                    E.&&. usrImage E.^. UsrImageImageDiv E.==. E.val 2
            return (usrMember, usrImage E.^. UsrImageFileName, usrAgeView E.^. UsrAgeViewAge)
        baseQueryPage = do r <- baseQuery; E.offset (pagePerLine * page); E.limit pagePerLine; return r
    cnt <- Import.length <$> E.select baseQuery
    s <- E.select baseQueryPage
    return (s,  cnt)


where句に条件で追加する方法、haskellのifは型を合わせる必要があるので、then、elseの
ところをexpr(Value a)にする必要があって、「E.val True」にするのは気がつかなかった、あとはoffsetだのlimitだのを後で追加する方法とかも参考になった。
 
ただ、カウントの取得方法がわからず、上のコードだと無駄なとり方になっているのはごめんなさい、どうしてもjoinした場合のcountRowsやその他の集計関数がうまく組み込めなかった。
どなたか教えては頂けないでしょうか?...

コードはこちらに置いておきます、「えすきゅーぅうれっちゅ」ネタでした。


0 件のコメント:

コメントを投稿