Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yesod #13

Open
felipexpert opened this issue Feb 18, 2016 · 6 comments
Open

Yesod #13

felipexpert opened this issue Feb 18, 2016 · 6 comments

Comments

@felipexpert
Copy link

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)

@gbwey
Copy link
Owner

gbwey commented Feb 18, 2016

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

@felipexpert
Copy link
Author

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

@gbwey
Copy link
Owner

gbwey commented Feb 20, 2016

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>

    "
    blogsSrc $= CL.map ((E.Value blogid, E.Value title, E.Value name) ->
    toFlushBuilder $
    [hamlet|

  • <a href=@{BlogR blogid}>#{title} by #{name}
    |] render
    )
    sendChunkText "
"

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
}

@felipexpert
Copy link
Author

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

@gbwey
Copy link
Owner

gbwey commented Feb 20, 2016

Unfortunately I don't have mysql and am unable to debug this.
Best,
Grant

@felipexpert
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants