内部加入持久性还是我应该使用 esqueleto?

Inner join in persistent or should I use esqueleto?

我有这个描述 NotificationNotified 实体的片段:

Notification
  type          NotiType
  release       ReleaseId
  date          UTCTime
Notified
  aboutWhat     NotificationId
  unread        Bool
  user          UserId

现在我想写这个:

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

这行得通,但是将通知列表提取为 list,然后将其用于 select 另一个 table 中的内容……这并不完全正确。显然我需要在这里加入,然后我才能有效地更新所有内容。

persistent怎么做?在这种情况下,使用 persistent 完成此类任务是否可能并且是个好主意?我应该改用 esqueleto 吗?看来我需要学习不同的 DSL 才能使用它,所以我不确定是否要切换。

如何用 persistent 正确地写 markAsRead(如果可能的话)?

是的,如果您想加入 Esqueleto。如果您的数据库和数据建模支持 嵌入 数据,则持久性效果很好。

正如 Greg 所说,Esqueleto 是必经之路。您可以尝试阅读 its main module documentation.

目前 Esqueleto 不支持 UPDATE 上的联接。但是,您可以使用子查询来达到相同的效果。

未经测试的入门代码:

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