12

「ベース」クエリと対応する結果セットを定義した後、追加の内部結合と where 式を追加して結果セットを制限できるように、モジュール方式でDatabase.Esqueletoクエリを構成するにはどうすればよいですか。

また、エンティティ (またはフィールド タプル) のリストを返す基本クエリを結果セットをカウントするクエリに変換するにはどうすればよいですか。基本クエリはそのままでは実行されず、LIMIT と OFFSET を使用して修正されたバージョンであるためです。

Yesod Bookから採用された次の誤った Haskell コード スニペットは、私が何を目指しているかを明確にすることを願っています。

{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies, OverloadedStrings #-}
{-# LANGUAGE GADTs, FlexibleContexts #-}
import qualified Database.Persist as P
import qualified Database.Persist.Sqlite as PS
import Database.Persist.TH
import Control.Monad.IO.Class (liftIO)
import Data.Conduit
import Control.Monad.Logger
import Database.Esqueleto
import Control.Applicative

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Person
    name String
    age Int Maybe
    deriving Show
BlogPost
    title String
    authorId PersonId
    deriving Show
Comment
    comment String
    blogPostId BlogPostId
|]

main :: IO ()
main = runStdoutLoggingT $ runResourceT $ PS.withSqliteConn ":memory:" $ PS.runSqlConn $ do
    runMigration migrateAll

    johnId <- P.insert $ Person "John Doe" $ Just 35
    janeId <- P.insert $ Person "Jane Doe" Nothing

    jackId <- P.insert $ Person "Jack Black" $ Just 45
    jillId <- P.insert $ Person "Jill Black" Nothing

    blogPostId <- P.insert $ BlogPost "My fr1st p0st" johnId
    P.insert $ BlogPost "One more for good measure" johnId
    P.insert $ BlogPost "Jane's" janeId

    P.insert $ Comment "great!" blogPostId

    let baseQuery = select $ from $ \(p `InnerJoin` b) -> do 
        on (p ^. PersonId ==. b ^. BlogPostAuthorId)
        where_ (p ^. PersonName `like` (val "J%"))
        return (p,b)

    -- Does not compile
    let baseQueryLimited = (,) <$> baseQuery <*> (limit 2)

    -- Does not compile
    let countingQuery = (,) <$> baseQuery <*> (return countRows)

    -- Results in invalid SQL 
    let commentsQuery = (,) <$> baseQuery
                <*> (select $ from $ \(b `InnerJoin` c) -> do
                        on (b ^. BlogPostId ==. c ^. CommentBlogPostId)
                        return ())

    somePosts <- baseQueryLimited
    count <- countingQuery
    withComments <- commentsQuery
    liftIO $ print somePosts
    liftIO $ print ((head count) :: Value Int)
    liftIO $ print withComments
    return ()
4

2 に答える 2

9

ドキュメントとのタイプを見るselect

select :: (...) => SqlQuery a -> SqlPersistT m [r]

を呼び出すとselect、純粋な構成可能なクエリの世界 ( ) を離れ、SqlQuery a副作用の世界 ( ) に入ることが明らかですSqlPersistT m [r]。そのため、 の前に構成する必要がありselectます。

let baseQuery = from $ \(p `InnerJoin` b) -> do 
      on (p ^. PersonId ==. b ^. BlogPostAuthorId)
      where_ (p ^. PersonName `like` (val "J%"))
      return (p,b)

let baseQueryLimited = do r <- baseQuery; limit 2; return r
let countingQuery    = do baseQuery; return countRows

somePosts <- select baseQueryLimited
count     <- select countingQuery

これは、制限とカウントに機能します。結合のためにそれを行う方法はまだわかりませんが、可能であるように見えます。

于 2013-05-16T22:09:19.247 に答える