convert PersistValue to Text in Yesod - haskell

I want get the attribute value from Persist Entity; so i have the following code
userToText userId = do
user <- runDB $ get404 userId
userName user
This code doesn't compile, so I wrote those alternative version
userToText userId = do
user <- runDB $ get404 userId
listToJSON [user]
userToText userId = do
(_,_,_,_,_,name,_,_) <- runDB $ get404 userId
show name
All generate the same error
Handler/Report.hs:105:9:
Couldn't match expected type ‘HandlerT site IO b’
with actual type ‘Text’
Relevant bindings include
userToText :: Key PersistValue -> HandlerT site IO b
(bound at Handler/Report.hs:102:1)
In a stmt of a 'do' block: listToJSON [user]
In the expression:
do { user <- runDB $ get404 userId;
listToJSON [user] }
thanks for the help

Your code is in the Handler monad, so your function needs to return something of the type Handler Text rather than just Text:
userToText :: UserId -> Handler Text
userToText userId = do
user <- runDB $ get404 userId
return $ userName user -- Note the `return` here
(This is similar to how functions like getLine have type IO String rather than String).

Related

Couldn't match type `BaseBackend(YesodPersistBackend PersonalPage)' with `SqlBackend'

I have a problem using persistent and Yesod with postgresql. This is the function that brings problems:
postBlogR :: MyHandler Html
postBlogR = do
((res, widgetForm), enctype) <- runFormPost blogForm
case res of
FormSuccess blog -> do
blogId <- runDB $ insert blog
redirect $ HomeR
_ -> adminLayout [whamlet|<h1>Post Created!|]
The trace is:
* Couldn't match type `BaseBackend(YesodPersistBackend PersonalPage)'
with `SqlBackend'
arising from a use of `insert'
* In the second argument of `($)', namely `insert blog'
In a stmt of a 'do' block: blogId <- runDB $ insert blog
In the expression:
do { blogId <- runDB $ insert blog;
redirect $ HomeR }
You are missing the relevant YesodPerist instance. It will be something like this:
instance YesodPersist App where
type YesodPersistBackend App = SqlBackend
runDB action = do
master <- getYesod
runSqlPool action $ appConnPool master

Yesod - Error "couldn't match expected type" when extracting data from database

Having the following database models, I am trying to get the city name (a certain field from city - a related entity) of an event :
City json
name Text
countryId CountryId
UniqueCity name
deriving Eq
deriving Show
Event
title Text
description Text
date UTCTime
cityId CityId
extractCityName :: EventId -> Text
extractCityName eventId = do
event <- runDB $ get404 eventId
city <- runDB $ get404 (eventCityId event)
x <- cityName city
return cityName
And I am having this error even if the function is not called yet(at compile time):
Couldn't match expected type `HandlerT site0 IO t0' with actual type `Text'
In a stmt of a 'do' block: x <- cityName city
In the expression:
do { event <- runDB $ get404 eventId;
city <- runDB $ get404 (eventCityId event);
x <- cityName city;
return cityName }
Can you please help me figure out what is wrong with my code?
That's because the type signature of runDB is YesodDB site a -> HandlerT site IO a. Unless you want to run database related actions in yesod handers, you won't be needing runDB. The code for extracting city name would be like this:
extractCityName :: EventId -> ReaderT SqlBackend IO (Maybe Text)
extractCityName eventId = do
event <- selectFirst [EventId ==. eventId] [LimitTo 1]
case event of
Nothing -> return Nothing
Just event' -> do
city <- getJust (eventCityId $ entityVal event')
return $ Just $ cityName city
Now you can use the above function in the Yesod handlers when you actually need it. You can do the pattern matching in the result and send a 404 page if the result is Nothing.

Use of `get` and `toSqlKey` in persistent

I'm trying to use persistent-postgresql with servant.
I have a User model.
I want to have an endpoint that takes an id and returns the user with that id.
According to other answers I can use toSqlKey to turn an Int64 into a Key to feed to get.
My function looks like:
oneUser :: Int64 -> App (Entity User)
oneUser userId = do
maybeUser <- runDb $ get $ toSqlKey userId
case maybeUser of
Nothing ->
throwError err404
Just user ->
return user
When I try to compile I get the error Couldn't match expected type ‘PersistEntityBackend (Entity User)’ with actual type ‘SqlBackend’
Use of selectList works fine.
allUsers :: App [Entity User]
allUsers = runDb $ selectList [] []
Please tell me what I'm doing wrong and where I should look in the future for stuff like this. I couldn't find get on hackage/the right version of the library on stackage etc.
runDb looks like:
runDb :: (MonadReader Config m, MonadIO m) => SqlPersistT IO b -> m b
runDb query = do
pool <- asks getPool
liftIO $ runSqlPool query pool
taken from this github project.
The difference is that get ... returns a plain User not an Entity User, so this will work:
altSingleUser :: Int64 -> App User
altSingleUser userid = do
let foo = get (toSqlKey userid) :: SqlPersistT IO (Maybe User)
maybeUser <- runDb $ foo
case maybeUser of
Nothing ->
throwError err404
Just person ->
return person
If you want to return an Entity User, just change the last return statement to:
return $ Entity { entityKey = toSqlKey userid, entityVal = person }

Resulting Ambiguous Type Variable in Persistent's `get` call

I'm having the following error while trying to retrieve a list of Entities from a list of foreign attributes.
Handler/ContactList.hs:21:57:
Couldn't match type `PersistMonadBackend m0'
with `persistent-1.3.0.6:Database.Persist.Sql.Types.SqlBackend'
The type variable `m0' is ambiguous
Possible fix: add a type sig`enter code here`nature that fixes these type variable(s)
Expected type: PersistEntityBackend User
Actual type: PersistMonadBackend m0
In the expression: `enter code here`get
In the expression: (get $ ((contactContact val) :: UserId))
In the first argument of `map', namely
`(\ (Entity key val) -> (get $ ((contactContact val) :: UserId)))'
The code below gets a List entity which has a one-to-many relationship with contact. In the Contact Model, there is an attribute called contact to represent the foreign key constraint to User (The type for conctact is UserId).
I'm Trying to retrieve the list of contacts (list of userIds) and perform a map get to retrieve the list of user entities.
For my understanding, there is a problem of type generalization while using get on a Contact Entity with UserId type, but I can't figure out what is the proper type it can work with.
getContactsR :: Handler Html
getContactsR = do
muser <- maybeAuth
case muser of
Just (Entity userId user) -> do
(list, contacts) <- runDB $ do
maybeList <- getBy (UniqueList userId)
case maybeList of
Just (Entity listId list) -> do
contacts' <- selectList [ContactList ==. listId] []
let contacts = map (\(Entity key val) -> (get $ ((contactContact val) :: UserId) )) contacts'
return (list, contacts')
Nothing -> error "Could not retrieve contact list"
defaultLayout $(widgetFile "contacts")
Nothing -> do
setMessage $ toHtml ("Error getting contact list" :: Text)
redirect HomeR
Thanks in advance
I think you need to replace:
let contacts = map (\(Entity key val) -> (get $ ((contactContact val) :: UserId) )) contacts'
with:
contacts <- mapM (\(Entity key val) -> (get $ ((contactContact val) :: UserId) )) contacts'
(Yes, the Persistent error messages here are terrible, we're working on that for Persistent 2.0.) I think the UserId type annotation may not even be necessary.

Extracting database field values inside a Handler

I would like to extract a database field (Text) and pass it as an argument to another function from a Handler. However, I run into Type errors. Completely made up example so may feel a bit contrived but should illustrate the issue I am having.
Person
name Text
Car
personId PersonId
name Text
type Text
I would like to get a Car entity and then find the corresponding Person. Get his name and then pass it as an argument. Something like:
data MyD = MyD { input1 :: Int}
entryForm :: Text -> Form MyD -- Update: Removed the incorrect extra parameter
entryForm n1 = renderDivs $ MyD
<$> areq intField n1 Nothing
My get handler looks like:
getInputR :: CarId -> Handler Html
getInputR carId = do
car <- runDB $ get404 carId
pid <- carPersonId car
name <- getPName pid
(widget, enctype) <- generateFormPost $ entryForm name
defaultLayout $ do
$(widgetFile "my_template")
where
getPName pid = do
person <- runDB $ get404 pid
personName person
I get an error saying:
Couldn't match expected type `HandlerT App IO t0'
with actual type `KeyBackend
persistent-1.2.1:Database.Persist.Sql.Types.SqlBackend Person'
In the return type of a call of `carPersonId'
In a stmt of a 'do' block: pid <- carPersonId car
What am I doing wrong?
Thanks!
Try changing
pid <- carPersonId car
name <- getPName pid
to
name <- getPName $ carPersonId car
The value returned from your runDB call is not inside the handler monad so you don't need to use the arrow syntax to access it.
For the second error, the issue is similar: The getPName function's return type is in the Handler monad since it uses runDB, so you need to use return to put the value into the monad:
getPName pid = do
person <- runDB $ get404 pid
return $ personName person

Resources