Внутреннее соединение в постоянном или я должен использовать esqueleto?

У меня есть этот фрагмент, описывающий Notification а также Notified лица:

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 ]

Это работает, но извлечение списка уведомлений в виде списка и последующее использование его для выбора элементов в другой таблице... ну, это не совсем верно. Очевидно, что мне нужно здесь присоединиться, и тогда я смогу все эффективно обновить.

Как это сделать в чистом виде persistent? Возможно ли и стоит ли в этом случае оставаться с persistent для такого рода задач? Должен ли я использовать esqueleto вместо? Похоже, мне нужно изучить различные DSL, чтобы работать с ним, поэтому я не уверен, переключаться или нет.

Как написать markAsRead правильно с persistent (если возможно)?

2 ответа

Решение

Как упоминал Грег, Эскелето - это путь. Вы можете попробовать прочитать документацию по основному модулю.

В настоящее время Esqueleto не поддерживает присоединения к UPDATEs. Тем не менее, вы можете использовать подзапросы для того же эффекта.

Непроверенный код для начала работы:

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

Да, Esqueleto, если вы хотите сделать присоединения. Persistent хорошо работает со встраиванием данных, если ваша БД и моделирование данных поддерживают это.

Другие вопросы по тегам