Esqueletoの利用方法

Type-safeにSQLを扱うためのEDSLでバックエンドはPersistentを利用しているライブラリです。

テーブルのJOIN

from関数 の中で、 InnerJoinLeftOuterJoinRightOuterJoin などが利用可能です。

getUsers ::
    Param
    -> Handler ([(Entity UsrMember, Value Text, 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 = from $ \(usrMember `InnerJoin`
                             usrImage `InnerJoin`
                             usrAgeView) -> do
            on $ usrMember ^. UsrMemberUsrMemberId ==. usrAgeView ^. UsrAgeViewUid
            on $ usrMember ^. UsrMemberUsrMemberId ==. usrImage ^. UsrImageUsrId
            where_ $ do
               let reqQuery = usrMember ^. UsrMemberReqId ==. val reqId
                    ageQuery = usrAgeView ^. UsrAgeViewAge >=. val ageFrom
                                  &&. usrAgeView ^. UsrAgeViewAge <=. val ageTo
               usrMember ^. UsrMemberTypeId `in_` valList typeIds
                    &&. (if reqId > 0 then reqQuery else val True)
                    &&. (if ageFrom > 0 && ageTo > 0 then ageQuery else val True)
                    &&. usrImage ^. UsrImageImageDiv ==. val 2
            return
              (
                usrMember
              , usrImage ^. UsrImageFileName
              , usrAgeView ^. UsrAgeViewAge
              )
        baseQueryPage =
            do
                r <- baseQuery
                offset (pagePerLine * page)
                limit pagePerLine
                return r
    cnt <- Import.length <$> select baseQuery
    s <- select baseQueryPage
    return (s,  cnt)

サブクエリ

サブクエリの注意点は、サブクエリの結果が取得できる場合、 subSelect関数 を利用すること、条件によってはサブクエリ結果が取得できない場合は、 subSelectMaybe関数 を利用することです。

getList ::
    Key UsrMember
    -> Handler Int
getList (UsrMemberKey uid) = runDB $ do
    let pagePerLine = 10
        page = 0
    list <- select $ from $ \(um `InnerJoin` mdt) -> do
        let newRec = subSelect $ from $ \mdt -> do
                where_ $ mdt ^. MsgDetailRefUsrMemberId ==. um ^. UsrMemberUsrMemberId
                limit 1
                orderBy [desc (mdt ^. MsgDetailCreateTime)]
                return $ mdt ^. MsgDetailCreateTime
        on $
            um ^. UsrMemberUsrMemberId ==. mdt ^. MsgDetailRefUsrMemberId
        where_ $ do
            um ^. UsrMemberUsrMemberId ==. val uid
            &&.
            um ^. UsrMemberStatusFlag >=. val contractStatusFlag
        orderBy [ desc (um ^. UsrMemberCreateTime)]
        limit pagePerLine
        offset page
        return (newRec, um ^. UsrMemberNickname)
    return 0

補足説明

Value typ

select関数 で最後にreturnされる値は、 「um ^. UsrMemberNickname」で、

return (newRec, um ^. UsrMemberNickname)

モデルで定義されている、UsrMemberのnicknameのフィールドを意味しています、そしてnicknameフィールドが

UsrMember
...
    nickname Text sqltype=varchar(64)

のように宣言されている場合、(Value typ) でtypがText型 (Value Text) で取得できるようになります。

Entity

Entityはテーブル情報そのものを表現しています

return
  (
    usrMember
  , usrImage ^. UsrImageFileName
  , usrAgeView ^. UsrAgeViewAge
  )

usrMemberについては、テーブルすべての項目を取得している書き方で、モデルが

UsrMember
    usrMemberId Int sqltype=bigint default=nextval('usr_member_usr_member_id_seq')
...
    nickname Text sqltype=varchar(64)

のような場合、usrMemberIdは PrimaryAuto Increment とすると

data Entity record =
    Entity
        {
          entityKey :: Key record
        , entityVal :: record
        }

で定義されるように、Primary Keyrecord (実際のレコードデータ) の2つで取得できます。

キーの値を取る場合はパターンマッチで取得するパターンと

func :: Key UsrMember -> Handler ()
func UsrMemberKey pk = do
  ...

Keyを取ってInt64を返す関数として書くこともできます。

fromTblFreeKey :: Key TblFree -> Int64
fromTblFreeKey = unSqlBackendKey . unTblFreeKey

備忘録で書いておきます、気がつけば追加していきます。

githubサンプルコード はこちらに置いてあります。

Posted on 2021-01-15 18:06:05

はじめまして

お茶の国静岡で、焼酎のお茶割なんか罰当たりで飲んだことはありません、常に一番搾りを嗜む静岡極東のBBQerです、最近まわりのエンジニアの方々がお料理を上手にやっている姿を恨めしそうに横目に見ながら、軟骨ピリ辛チクワを食べています、みなさんよろしく。

Posted

Amazon

tags