我一直在努力使运行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转换器中。
我在看了很多其他答案并了解了有关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
有几个键: