如何在scotty和selda中使用monad堆栈?

问题描述 投票:0回答:1

我一直在努力使运行scotty的Web服务器可以使用selda与我的数据库进行通信。我认为使用monad变压器堆栈将是完成类似任务的方式。我一直在尝试解决问题,但是遇到了一些死胡同,这些类型似乎根本无法工作。

{-# LANGUAGE DeriveGeneric, OverloadedStrings, OverloadedLabels #-}

module Server where

import Web.Scotty
import Data.Monoid (mconcat)
import Data.Aeson (ToJSON)
import GHC.Generics
import Web.Scotty
import Database.Selda
import Database.Selda.SQLite
import Control.Monad.Trans.Class

import Models

type App = SeldaT SQLite ScottyM

-- withPersist:: (MonadIO m, MonadMask m) => SeldaT SQLite m a -> m a
server = scotty 4200 (withPersist router)

router :: App ()
router = do
  lift $ get "/book/:id" searchBook

searchBook:: ActionM ()
searchBook = do
  books <- query selectBookQuery
  json books
    where
      selectBookQuery = do
        book <- select goodreadsBooks
        restrict (book ! #goodreadsId .== "20")
        return book

我试图将其基于答案here,但我想包装路由器而不是单独的路线。我不希望我打开的连接数与我拥有的路由数成正比,如果可以避免的话,我也不希望每个路由都必须有一个withPersist调用。

所以我有一个App,它的类型为SeldaT Sqlite ScottyM,然后使用withPersist(== withSQLite "mydb.db"),我将SeldaT Sqlite ScottyM变成了ScottyM。虽然有很多问题,但我对这些问题的理解是:

  • [SeldaT m a(MonadIO m, MonadMask m)约束,并且ScottyM没有MonadIO的实例
  • Scotty.get返回一个ScottyM (),我觉得这是我要使用lift将其变成SeldaT Sqlite ScottyM的地方,但是我得到了一个错误,可能与ScottyM不是上方MonadIO的实例。
  • 由于searchBook仍然是ActionM,因此我无法在其中运行查询。不确定如何获取get来接受我的转换器堆栈,而不是ActionM

这里是错误:

/home/marcus/Documents/projects/nowwhatdoiread/nwdir-server/app/Server.hs:19:23: error:
    • No instance for (MonadIO ScottyM)
        arising from a use of ‘withPersist’
    • In the second argument of ‘scotty’, namely ‘(withPersist router)’
      In the expression: scotty 4200 (withPersist router)
      In an equation for ‘server’:
          server = scotty 4200 (withPersist router)
   |
19 | server = scotty 4200 (withPersist router)
   |                       ^^^^^^^^^^^^^^^^^^

/home/marcus/Documents/projects/nowwhatdoiread/nwdir-server/app/Server.hs:23:3: error:
    • No instance for (MonadTrans (SeldaT SQLite))
        arising from a use of ‘lift’
    • In a stmt of a 'do' block: lift $ get "/book/:id" searchBook
      In the expression: do lift $ get "/book/:id" searchBook
      In an equation for ‘router’:
          router = do lift $ get "/book/:id" searchBook
   |
23 |   lift $ get "/book/:id" searchBook
   |   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

/home/marcus/Documents/projects/nowwhatdoiread/nwdir-server/app/Server.hs:27:12: error:
    • No instance for (MonadSelda
                         (Web.Scotty.Internal.Types.ActionT
                            Data.Text.Internal.Lazy.Text IO))
        arising from a use of ‘query’
    • In a stmt of a 'do' block: books <- query selectBookQuery
      In the expression:
        do books <- query selectBookQuery
           json books
      In an equation for ‘searchBook’:
          searchBook
            = do books <- query selectBookQuery
                 json books
            where
                selectBookQuery
                  = do book <- select goodreadsBooks
                       ....
   |
27 |   books <- query selectBookQuery
   |            ^^^^^^^^^^^^^^^^^^^^^

更新:在看了更多类似的问题之后,我可能需要使用ScottyT。虽然不确定如何将SeldaT嵌套在ScottyT转换器中。

haskell monad-transformers scotty
1个回答
0
投票

我在看了很多其他答案并了解了有关monad变压器的更多信息后才发现,我得出的解决方案是:

{-# LANGUAGE DeriveGeneric, OverloadedStrings, OverloadedLabels #-}

module Server where

import Web.Scotty.Trans
import Database.Selda
import Database.Selda.SQLite
import Control.Monad.Trans.Class
import Control.Monad.Identity
import qualified Data.Text.Lazy as TL

import Models

server :: IO ()
server = scottyT 4200 withPersist router

router :: ScottyT TL.Text (SeldaT SQLite IO) ()
router = do
  get "/book/:id" searchBook

searchBook:: ActionT TL.Text (SeldaT SQLite IO) ()
searchBook = do
  books <- lift $ query selectBookQuery
  json books
    where
      selectBookQuery = do
        book <- select goodreadsBooks
        restrict (book ! #goodreadsId .== "20")
        return book

有几个键:

  • Scotty拥有自己的monad变压器ScottyT,它必须是最外面的变压器
  • Scott.Trans需要用于使变压器堆栈与scotty一起使用,因为类型更为通用
  • 需要使用ActionT转换器执行操作,因此他们也可以访问transformer堆栈
© www.soinside.com 2019 - 2024. All rights reserved.