Alright, so there are a few problems actually, I'll try to describe each of them in isolation of the other, but in a sense they are all related.
I want to insert a user id, which I want to get from the AuthManager
. Okay that's fair enough, we can just use currentUser
and then do some maybe
voodoo to get the actual unUid
. But then is when the problem starts. Okay, so we want to use execute
to exute a query:
execute "INSERT INTO events(title,recurring) VALUES(?,?);" (eventname,recurring)
boom. Okay, then when doing cabal install
, it fails saying that there is no instance of HasPostgres
available for the type I declared. Makes perfect sense since the type of my handler is ...-> ...-> Handler App (AuthManager App)
. This is the first problem: I don't know how to correctly make an instance so that the types are correct. As I tried, just copying the initial instance in Application.hs
doesn't help us at all.
That brings us to other problems that arise when trying to find an alternative solution. So the solutions I tried is by just substituting the execute
call with a with pg $ execute
call. This has the following result:
Couldn't match type `App' with `AuthManager App'
Expected type: Handler App (AuthManager App) GHC.Int.Int64
Actual type: Handler App App GHC.Int.Int64
So again, to no avail. The next thing I tried is removing (AuthManager App)
type, and just substituting it by App
, so then I could replace AuthManager
calls with with auth $ call
. Then I realised this isn't the solution either, because once you get AuthManager
out of there, you need to drop it from every function that calls it.
I need some help with how to fix this. Can I somehow lift the type to fix this? Or alternatively what is a good solution to this problem?
EDIT
Okay, so I've tried to remove AuthManager App
out of my type so I can use postgres after all. Now this doesn't go as smoothly either as one would expect. The next part comes from a regular application generated by Snap init
:
handleLoginSubmit :: Handler App App ()
handleLoginSubmit =
with auth $ loginUser "login" "password" Nothing
(\_ ->handleLogin err) (handleFoo)
where
err = Just "Unknown user or password"
Okay so both handleLogin
and handleFoo
now have types Handler App App ()
, but yet Haskell complains it expects the type Handler App (AuthManager App) ()
:
Couldn't match type `App' with `AuthManager App'
Expected type: Handler App (AuthManager App) ()
Actual type: Handler App App ()
--Definition of App:
data App = App
{ _heist :: Snaplet (Heist App)
, _sess :: Snaplet SessionManager
, _auth :: Snaplet (AuthManager App)
, _pg :: Snaplet Postgres
}
You want to use this type signature.
yourHandler :: Handler App App ()
with pg $ execute ...
with auth $ loginUser ...
The with
function lets you raise a Handler b v
function, which only has access to the v snaplet's data, into Handler b b
, which has access to everything. And the only thing it needs to do that is the lens from b to v.