Yesod
Opened this issue · 6 comments
How can I easily use it with yesod through stack? (By the way, thank you so much for this repo, it was the only way I've found to use Persistent+Mysql+Windows)
I just tried this and it looks like you would need to add at least these extra dependencies to stack.yaml and then run "stack build".
extra-deps:
- persistent-odbc-0.2.0.1
- HDBC-odbc-2.5.0.0
- concurrent-extra-0.7.0.10
Let me know if you need more info.
Best,
Grant
How can I implement YesodPersist in Yesod?
I tryed the following which doesn't compile:
-- How to run database actions.
instance YesodPersist App where
runDB = runResourceT . runNoLoggingT . withODBCConn Nothing "dsn=mysql_test" . runSqlConn
For instance, I've found the following code from the Yesod book:
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
import Control.Monad.Logger (runNoLoggingT)
import Data.Text (Text)
import Data.Time
import Database.Persist.Sqlite
import Yesod
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Link
title Text
url Text
added UTCTime
|]
data App = App ConnectionPool
mkYesod "App" [parseRoutes|
/ HomeR GET
/add-link AddLinkR POST
|]
instance Yesod App
instance RenderMessage App FormMessage where
renderMessage _ _ = defaultFormMessage
instance YesodPersist App where
type YesodPersistBackend App = SqlBackend
runDB db = do
App pool <- getYesod
runSqlPool db pool
getHomeR :: Handler Html
getHomeR = defaultLayout
[whamlet|
<form method=post action=@{AddLinkR}>
<p>
Add a new link to
<input type=url name=url value=http://>
titled
<input type=text name=title>
<input type=submit value="Add link">
<h2>Existing links
^{existingLinks}
|]
existingLinks :: Widget
existingLinks = do
links <- handlerToWidget $ runDB $ selectList [] [LimitTo 5, Desc LinkAdded]
[whamlet|
<ul>
$forall Entity _ link <- links
<li>
<a href=#{linkUrl link}>#{linkTitle link}
|]
postAddLinkR :: Handler ()
postAddLinkR = do
url <- runInputPost $ ireq urlField "url"
title <- runInputPost $ ireq textField "title"
now <- liftIO getCurrentTime
runDB $ insert $ Link title url now
setMessage "Link added"
redirect HomeR
main :: IO ()
main = runNoLoggingT $ withSqlitePool "links.db3" 10 $ \pool -> liftIO $ do
runSqlPersistMPool (runMigration migrateAll) pool
warp 3000 $ App pool
stack new abcd yesod-simple [ie create project with yesod-simple template just to setup all yesod dependencies]
then add these dependencies to the abcd.cabal file
, persistent-odbc
, esqueleto
add these extra dependencies to stack.yaml
extra-deps:
- persistent-odbc-0.2.0.1
- HDBC-odbc-2.5.0.0
- concurrent-extra-0.7.0.10
run: stack build
Create this file: I dont have MySql on my machine so I used sqlite3 instead but it is similar:
the key line is:
pool <- runStderrLoggingT $ createODBCPool (Just (Sqlite True)) "dsn=sqlitetest" 1
Just replace with MySql and you should be running fine
A minor thing, : but I noticed that you had:
let conf = OdbcConf "DNS=mysql_test;" 1 "MySQL" [should be DSN=]
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ViewPatterns #-}
import Control.Monad.Logger
import Data.Text (Text)
import qualified Database.Esqueleto as E
import Database.Esqueleto ((^.))
import Yesod
import qualified Data.Conduit.List as CL
import Data.Conduit (($=))
import Prelude
import Database.Persist.ODBC
import Database.Persist.ODBCTypes
import Database.Persist.MigrateSqlite
import System.IO.Unsafe
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Author
name Text
Blog
author AuthorId
title Text
content Html
|]
data App = App
{ persistConfig :: OdbcConf
, connPool :: ConnectionPool
}
instance Yesod App
instance YesodPersist App where
type YesodPersistBackend App = SqlBackend
runDB = defaultRunDB persistConfig connPool
instance YesodPersistRunner App where
getDBRunner = defaultGetDBRunner connPool
mkYesod "App" [parseRoutes|
/ HomeR GET
/blog/#BlogId BlogR GET
|]
getHomeR :: Handler TypedContent
getHomeR = do
let blogsSrc =
E.selectSource
$ E.from $ (blog E.InnerJoin
author) -> do
E.on $ blog ^. BlogAuthor E.==. author ^. AuthorId
return
( blog ^. BlogId
, blog ^. BlogTitle
, author ^. AuthorName
)
render <- getUrlRenderParams
respondSourceDB typeHtml $ do
sendChunkText "<title>Blog posts</title>
- "
<a href=@{BlogR blogid}>#{title} by #{name}
|] render
)
sendChunkText "
blogsSrc $= CL.map ((E.Value blogid, E.Value title, E.Value name) ->
toFlushBuilder $
[hamlet|
getBlogR :: BlogId -> Handler Html
getBlogR _ = error "Implementation left as exercise to reader"
main :: IO ()
main = do
-- Is this configuration right?
-- let conf = OdbcConf "DNS=mysql_test;" 1 "MySQL"
-- DRIVER=SQLite3 ODBC Driver;Database=c:\mydb.db;LongNames=0;Timeout=1000;NoTXN=0;SyncPragma=NORMAL;StepAPI=0;
-- let conf = OdbcConf "DRIVER=SQLite3 ODBC Driver;Database=mydb.db;LongNames=0;Timeout=1000;NoTXN=0;SyncPragma=NORMAL;StepAPI=0;" 1 "Sqlite {sqlite3619 = True}"
pool <- runStderrLoggingT $ createODBCPool (Just (Sqlite True)) "dsn=sqlitetest" 1
flip runSqlPersistMPool pool $ do
runMigration migrateAll
-- Fill in some testing data
alice <- insert $ Author "Alice"
bob <- insert $ Author "Bob"
insert_ $ Blog alice "Alice's first post" "Hello World!"
insert_ $ Blog bob "Bob's first post" "Hello World!!!"
insert_ $ Blog alice "Alice's second post" "Goodbye World!"
warp 3000 App
{ persistConfig = undefined
, connPool = pool
}
It is working!
There is just a issue, when I run the first time with the migrations, a error appears, but then (after commenting it) it works apparently properly: (the error is in the last line)
Run from outside a project, using implicit global project config
Using resolver: lts-4.1 from implicit global project's config file: /home/geppetto/.stack/global-project/stack.yaml
getColumns cs=[Right (Left (Column {cName = DBName {unDBName = "name"}, cNull = False, cSqlType = SqlString, cDefault = Nothing, cDefaultConstraintName = Nothing, cMaxLen = Nothing, cReference = Nothing}))]
us=[]
old=[Right (Left (Column {cName = DBName {unDBName = "name"}, cNull = False, cSqlType = SqlString, cDefault = Nothing, cDefaultConstraintName = Nothing, cMaxLen = Nothing, cReference = Nothing}))]
fdefs=[]
getColumns cs=[Right (Left (Column {cName = DBName {unDBName = "author"}, cNull = False, cSqlType = SqlInt64, cDefault = Nothing, cDefaultConstraintName = Nothing, cMaxLen = Nothing, cReference = Nothing})),Right (Left (Column {cName = DBName {unDBName = "title"}, cNull = False, cSqlType = SqlString, cDefault = Nothing, cDefaultConstraintName = Nothing, cMaxLen = Nothing, cReference = Nothing})),Right (Left (Column {cName = DBName {unDBName = "content"}, cNull = False, cSqlType = SqlString, cDefault = Nothing, cDefaultConstraintName = Nothing, cMaxLen = Nothing, cReference = Nothing}))]
us=[]
old=[Right (Left (Column {cName = DBName {unDBName = "author"}, cNull = False, cSqlType = SqlInt64, cDefault = Nothing, cDefaultConstraintName = Nothing, cMaxLen = Nothing, cReference = Nothing})),Right (Left (Column {cName = DBName {unDBName = "title"}, cNull = False, cSqlType = SqlString, cDefault = Nothing, cDefaultConstraintName = Nothing, cMaxLen = Nothing, cReference = Nothing})),Right (Left (Column {cName = DBName {unDBName = "content"}, cNull = False, cSqlType = SqlString, cDefault = Nothing, cDefaultConstraintName = Nothing, cMaxLen = Nothing, cReference = Nothing}))]
fdefs=[]
Migrating: ALTER TABLE blog
ADD CONSTRAINT blog_author_fkey
FOREIGN KEY(author
) REFERENCES author
(id
)
[Debug#SQL] ALTER TABLE blog
ADD CONSTRAINT blog_author_fkey
FOREIGN KEY(author
) REFERENCES author
(id
); []
File.hs: Prelude.chr: bad argument: 5832776
Unfortunately I don't have mysql and am unable to debug this.
Best,
Grant
Hello gbway, I am following another path. I am trying to integrate persistent-odbc with scotty, looking at this tutorial: http://adit.io/posts/2013-04-15-making-a-website-with-haskell.html
tutorial version using Postgrees:
import Database.Persist
import Database.Persist.Sqlite
runDb :: SqlPersist (ResourceT IO) a -> IO a
runDb query = runResourceT . withSqliteConn "dev.sqlite3" . runSqlConn $ query
but I am getting trouble in the following code:
import Prelude
import Database.Persist
import Database.Persist.ODBC
import Control.Monad.Logger (runNoLoggingT)
import Control.Monad.Trans.Resource (runResourceT, ResourceT)
runDb :: SqlPersist (ResourceT IO) a -> IO a
runDb = runResourceT . runNoLoggingT . (withODBCConn Nothing "dsn=newmyerp") . runSqlConn
But the signature doesn't match...