I have a realy simple data in my config/model
Author
name Text
and I want to select author by name and not by id
I tried this ( the information comes from a form) :
FormSuccess book -> do
result <- runDB $ selectSource [ AuthorName ==. title book]
And book is a data
data FormBook = FormBook {
isbn :: Text
, author :: Text
, title :: Text
, description :: Maybe Text
}
But I got this error
Couldn't match type `[SelectOpt Author]' with `HandlerT App IO'
Expected type: YesodPersistBackend
App
(HandlerT App IO)
(Data.Conduit.Internal.Source m0 (Entity Author))
Actual type: [SelectOpt Author]
-> Data.Conduit.Internal.Source m0 (Entity Author)
In the return type of a call of `selectSource'
Probable cause: `selectSource' is applied to too few arguments
In the second argument of `($)', namely
`selectSource [AuthorName ==. (author book)]'
In a stmt of a 'do' block:
authorresult <- runDB $ selectSource [AuthorName ==. (author book)]
I tried th put before Author PersistenceEntity and PersistenceField but they are not in scope.
I do not have any other idea, except raw query.
Related
(This was asked before but it has no answers).
I have a list of countries in a database:
share [mkPersist sqlSettings] [persistLowerCase|
Country
name Text
UniqueCountryName name
deriving Show
|]
And I can show a form to select one of them:
countries = do
rows <- runDB $ selectList [] [Asc CountryName]
optionsPairs $ map (\ r -> (countryName $ entityVal r, entityKey r)) rows
surveyForm :: Html -> MForm Handler (FormResult SurveyAnswerSet, Widget)
surveyForm extra = do
(countryR, countryV) <- mreq (selectField countries) "" Nothing
I know that I should replace the Nothing in the last line with the desired default value but I still don't get how to do it. Looking at the mreq and the optionsPairs signatures my thought was that in this case I should provide a Maybe Option with the default country but my attempts have raised so many type errors that probably I am quite far from the right answer.
The Yesod book has an example using seems more simple than what I tried to achieve so I am not sure how to extrapolate it.
By the way I am getting the default country from the database so I don't need to hardcode its internal id:
defaultCountry = do
row <- runDB $ getBy $ UniqueCountryName $ countryName "United States"
(countryName $ entityVal row, entityKey row)
When I pass it as an argument to mreq I get the following errors:
Couldn't match type ‘(,) Text’ with ‘HandlerFor site’
Expected type: HandlerFor site (Key record)
Actual type: (Text, Key record)
That's on the last line of the of the defaultContry function ((countryName $ entityVal row, entityKey row)). I understand that I should take the Key record from the pair and return it in a HandlerFor site but at the same time I also get:
Couldn't match expected type ‘Maybe (Key Country)’
with actual type ‘HandlerFor site0 (Key record0)’
In the (countryR, countryV) <- mreq (selectField countries) "" defaultCountry line. I interprete this as "you are passing me a HandlerFor site0 (Key record0) but I only accept Maybe (Key Country) which seems in conflict with the first error...
In the (countryName $ entityVal row, entityKey row) line I also see:
Couldn't match expected type ‘Entity Country’
with actual type ‘Maybe (Entity Country)’
in the row argument. I understand that I should extract the Entity Country from the Maybe but if I pattern match and pass just the Entity Country (i. e.: Just (Entity countryId country) -> (countryName $ entityVal (Entity countryId country), entityKey (Entity countryId country)) I still get the first error.
Thanks in advance.
Alright, this looks like a few type errors. The first
Couldn't match type ‘(,) Text’ with ‘HandlerFor site’ Expected type: HandlerFor site (Key record) Actual type: (Text, Key record)
comes from not using return in your do notation to lift the value to the monad:
defaultCountry :: HandlerFor site (Text, Key record)
defaultCountry = do
row <- runDB $ getBy $ UniqueCountryName $ countryName "United States"
return (countryName $ entityVal row, entityKey row)
The error on row
Couldn't match expected type ‘Entity Country’ with actual type ‘Maybe (Entity Country)’
is because it's a Maybe, so let's correct that
defaultCountry :: HandlerFor site (Text, Key record)
defaultCountry = do
Just row <- runDB $ getBy $ UniqueCountryName $ countryName "United States"
return (countryName $ entityVal row, entityKey row)
Now that defaultCountry is a good monad, you should be able to use it in your other code. But be careful of that third error
Couldn't match expected type ‘Maybe (Key Country)’ with actual type ‘HandlerFor site0 (Key record0)’
You need to unwrap the value from the HandlerFor monad, and rewrap it in a Maybe
surveyForm :: Html -> MForm Handler (FormResult SurveyAnswerSet, Widget)
surveyForm extra = do
(defaultName, defaultKey) <- defaultCountry -- (defaultName, defaultKey) :: (Text, Key record)
(countryR, countryV) <- mreq (selectField countries) "" (Just defaultKey)
In my yesod test I want to be able to modify a record in the db in the middle of the test.
Here is the code I came up with
yit "post is created by authorized user" $ do
request $ do
addPostParam "ident" "dummy"
setMethod "POST"
setUrl ("http://localhost:3000/auth/page/dummy" :: Text)
update 0 [UserAuthorized =. True]
postBody PostR (encode $ object [
"body" .= ("test post" :: Text),
"title" .= ("test post" :: Text),
"coverImage" .= ("test post" :: Text),
"author" .= (0 :: Int)
])
statusIs 200
This fails with the error
• Couldn't match expected type ‘IO a0’
with actual type ‘ReaderT backend0 m0 ()’
• In the second argument of ‘($)’, namely
‘update 0 [UserAuthorized =. True]’
In a stmt of a 'do' block:
runIO $ update 0 [UserAuthorized =. True]
In the expression:
do { settings <- runIO
$ loadYamlSettings
["config/test-settings.yml", "config/settings.yml"] [] useEnv;
foundation <- runIO $ makeFoundation settings;
yesodSpec foundation $ do { ydescribe "Auth" $ do { ... } };
runIO $ update 0 [UserAuthorized =. True];
.... }
I can tell this is because update returns m () instead of YesodExample site () like request, postBody and statusIs do.
How would I be able to do a db update inside of this test?
You need to use runDB function. i.e:
runDB $ update 0 [UserAuthorized =. True]
There were 2 problems in this, the first one as Sibi pointed out is I needed runDB the second one is you can't just look up a record with an integer.
To get this working I used the following code
runDB $ do
(first :: Maybe (Entity User)) <- selectFirst [] []
case first of
Nothing -> pure () -- handle the case when the table is empty
Just (Entity k _) -> update k [UserAuthorized =. True]
This find's the record in the DB and then updates it. Modify (first :: Maybe (Entity User)) <- selectFirst [] [] to select the record you want to update.
I'm working on a project that builds on the simple yesod template. I am new to functional programming, haskell and Yesod so it's probably something obvious to anyone with Yesod experience. At the moment I am trying to make github API calls using this library. I am getting some type issues and I'm not even sure how to start approaching solving them.
You can find my handler here.
Handler/Home.hs:43:19:
Couldn't match expected type ‘HandlerT
App IO (Either a0 GitHub.User)’
with actual type ‘GitHub.Request k0 GitHub.User’
In a stmt of a 'do' block:
possibleUser <- GitHub.userInfoForR "mike-burns"
In the expression:
do { maid <- maybeAuthId;
possibleUser <- GitHub.userInfoForR "mike-burns";
result <- either (("Error: " <>) . tshow) formatUser possibleUser;
defaultLayout
(do { (asWidgetT GHC.Base.. toWidget)
((blaze-markup-0.7.1.1:Text.Blaze.Internal.preEscapedText
GHC.Base.. Data.Text.pack)
"<p>Your current auth ID: ");
(asWidgetT GHC.Base.. toWidget) (toHtml (show maid));
(asWidgetT GHC.Base.. toWidget)
((blaze-markup-0.7.1.1:Text.Blaze.Internal.preEscapedText
GHC.Base.. Data.Text.pack)
"</p>\n");
.... }) }
Handler/Home.hs:44:38:
Couldn't match type ‘Text’ with ‘HandlerT App IO a1’
Expected type: a0 -> HandlerT App IO a1
Actual type: a0 -> Text
In the second argument of ‘(.)’, namely ‘tshow’
In the first argument of ‘either’, namely
‘(("Error: " <>) . tshow)’
Handler/Home.hs:44:45:
Couldn't match type ‘Text’ with ‘HandlerT App IO a1’
Expected type: GitHub.User -> HandlerT App IO a1
Actual type: GitHub.User -> Text
In the second argument of ‘either’, namely ‘formatUser’
In a stmt of a 'do' block:
result <- either (("Error: " <>) . tshow) formatUser possibleUser
The GitHub library seems to be about building requests, and running them. The userInfoForR does such a thing :
userInfoForR :: Name User -> Request k User
Once you have a request, you can run it with one of the following functions, depending if you need to authenticate or not:
executeRequest :: Auth -> Request k a -> IO (Either Error a)
executeRequest' :: Request RO a -> IO (Either Error a)
I don't know about this specific case, but let's say you don't need authentication. So, the following expression would do the trick:
executeRequest' (userInfoForR "mike-burns") :: IO (Either Error User)
Now, in order to use it in a Handler, you'll need to learn about the fact that Handler is an instance of MonadIO, and you can thus do:
euser <- liftIO (executeRequest' (userInfoForR "mike-burns"))
case euser of
Left rr -> ...
Right user -> ...
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.
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.