Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scotty Using MongoDB

I'm relatively new to Haskell, and this is my first time working with monad transformers. I'd really appreciate some help.

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  
            ...

I'm trying to query a mongodb database under the scotty web framework, but I'm getting an error about MonadBaseControl. Do I really have to make an instance of this to connect to a database with scotty, and how would I go about doing it?

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))
like image 566
Craig Avatar asked Mar 20 '23 16:03

Craig


1 Answers

mongoDB is generic enough to work in any monad that is instance of MonadBaseControl IO and MonadIO.

For example, you can choose IO monad. In this case you need liftIO . runQuery inside scotty's action:

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

After @Sebastian Philipp added MonadBaseControl instance for Scotty.ActionT, there is no need to lift anything. You can transparently work with mongoDB form scotty. Just change type signature and drop liftIOs:

runQuery :: Pipe -> Query -> ActionM [Document]
...
    get "/" $ do
      res <- runQuery pipe (select [] "stock_foods")
      text $ T.pack $ show res
like image 186
max taldykin Avatar answered Mar 28 '23 14:03

max taldykin