Скотти использует MongoDB

Я относительно новичок в Haskell, и я впервые работаю с преобразователями монад. Я был бы очень признателен за помощь.

runQuery :: Pipe -> Query -> ActionM (Either Failure [Document])
runQuery pipe query = access pipe master "nutrition" (find query >>= rest) 

main = do
pipe <- runIOE $ connect $ host "127.0.0.1"  

scotty 3000 $ do
post "/" $ do
        b <-  body
        let user :: Either String User = eitherDecode b
        case user of 
            Left err -> text . pack $ "Could not decode the user:" ++ err ++ ":\n" ++ (show b)
            Right u -> do 
            let query::Query = (select ["i_name" =: ["$in" =: map (unpack . name) (foods u)]] "stock_foods")
            results <- runQuery pipe query  
            ...

Я пытаюсь запросить базу данных mongodb в рамках веб-фреймворка scotty, но получаю сообщение об ошибке MonadBaseControl. Мне действительно нужно создать экземпляр этого, чтобы подключиться к базе данных с помощью scotty, и как мне это сделать?

No instance for (MonadBaseControl
                   IO (scotty-0.7.2:Web.Scotty.Types.ActionT Text IO))
  arising from a use of `find'
Possible fix:
  add an instance declaration for
  (MonadBaseControl
     IO (scotty-0.7.2:Web.Scotty.Types.ActionT Text IO))

person Craig    schedule 08.05.2014    source источник
comment
Вы должны включить в свой вопрос достаточно кода (включая все импорты и имена пакетов, которые вы используете из Hackage), чтобы мы могли попытаться скомпилировать его самостоятельно. Это упрощает отладку и тестирование различных решений. Я предполагаю, что вы можете исправить это с помощью простого lift в своем runQuery, но не можете это проверить.   -  person shang    schedule 08.05.2014
comment
Я правда ценю это. Оказывается, мне нужно было lift выполнить функцию runQuery и изменить ее тип возвращаемого значения с ActionM (Either ...) на IO (Either ...). Я думаю, что теперь я смогу добиться большего прогресса с трансформерами монад!   -  person Craig    schedule 08.05.2014
comment
Если это поможет, я прохожу что-то очень похожее: использую Скотти с Persistent и пытаюсь понять, как использовать преобразователи. Здесь есть код, который, кажется, работает: github. com/stu-smith/Brandy/blob/master/src/Api/Users.hs   -  person stusmith    schedule 08.05.2014
comment
(Забыл сказать: мне, вероятно, следует использовать liftIO вместо нескольких lift... там еще много уборки для меня, поэтому, пожалуйста, не думайте, что код, который я разместил, разумен: я просто публикую его для интереса ).   -  person stusmith    schedule 08.05.2014
comment
Спасибо, всегда приятно увидеть примеры!   -  person Craig    schedule 08.05.2014
comment
github.com/scotty-web/scotty/pull/82 Это тянет запрос на добавление экземпляра MonadBaseControl для ActionT.   -  person Sebastian Wagner    schedule 08.05.2014
comment
Спасибо за это. Оказывается, это необходимо для функции find: hackage.haskell.org/package/mongoDB-1.4.4/docs/   -  person Craig    schedule 09.05.2014


Ответы (1)


mongoDB достаточно универсален, чтобы работать в любой монаде, являющейся экземпляром MonadBaseControl IO и MonadIO.

Например, вы можете выбрать монаду IO. В этом случае вам нужно liftIO . runQuery внутри действия Скотти:

import Web.Scotty
import Database.MongoDB
import qualified Data.Text.Lazy as T
import Control.Monad.IO.Class

runQuery :: Pipe -> Query -> IO [Document]
runQuery pipe query = access pipe master "nutrition" (find query >>= rest) 

main = do
  pipe <- connect $ host "127.0.0.1"
  scotty 3000 $ do
    get "/" $ do
      res <- liftIO $ runQuery pipe (select [] "stock_foods")
      text $ T.pack $ show res

После @Sebastian Philipp добавлен MonadBaseControl экземпляр для Scotty.ActionT, поднимать ничего не нужно. Вы можете прозрачно работать с формой Скотти mongoDB. Просто измените подпись типа и отбросьте liftIOs:

runQuery :: Pipe -> Query -> ActionM [Document]
...
    get "/" $ do
      res <- runQuery pipe (select [] "stock_foods")
      text $ T.pack $ show res
person max taldykin    schedule 13.10.2014