I have this fragment describing Notification
and Notified
entities:
Notification
type NotiType
release ReleaseId
date UTCTime
Notified
aboutWhat NotificationId
unread Bool
user UserId
Now I want to write this:
-- | Mark specified notification as already seen by specific user. Note that
-- we use 'ReleaseId' to select notification, so this may result in several
-- notifications marked as “read” if they happen to be about the same
-- release. This is generally what you want.
markAsRead
:: ReleaseId -- ^ Release in question
-> UserId -- ^ User who has seen mentioned release
-> SqlPersistM ()
markAsRead release user = do
ns <- selectKeysList [ NotificationRelease ==. release ] []
updateWhere [ NotifiedAboutWhat <-. ns
, NotifiedUnread ==. True
, NotifiedUser ==. user ]
[ NotifiedUnread =. False ]
This works, but extracting list of notifications as list and then using it to select things in another table… well that's not exactly right. Obviously I need a join here and then I will be able to update everything efficiently.
How to do it in pure persistent
? Is it possible and is it a good idea in this case to stay with persistent
for this sort of task? Should I use esqueleto
instead? It looks like I'll need to learn different DSL to work with it, so I'm not sure whether to switch or not.
How to write markAsRead
properly with persistent
(if possible)?
As Greg mentioned, Esqueleto is the way to go. You can try reading its main module documentation.
Currently Esqueleto doesn't support joins on UPDATE
s. However, you can use subqueries to the same effect.
Untested code to get you started:
-- | Mark specified notification as already seen by specific user. Note that
-- we use 'ReleaseId' to select notification, so this may result in several
-- notifications marked as “read” if they happen to be about the same
-- release. This is generally what you want.
markAsRead
:: ReleaseId -- ^ Release in question
-> UserId -- ^ User who has seen mentioned release
-> SqlPersistM ()
markAsRead release user =
update $ \n -> do
set n [ NotifiedUnread =. val False ]
where_ $
n ^. NotifiedUnread ==. val True &&.
n ^. NotifiedUser ==. val user &&.
n ^. NotifiedAboutWhat `in_`
(subList_select $
from $ \t -> do
where_ $ t ^. NotificationRelease ==. val release
return $ t ^. NotificationId)