Возвращая `Maybe (Entity a)` из Esqueleto `LeftOuterJoin`

Из надуманного config/models на сайте лесов:

Inventory
  name        Text
  description Text
Container
  name        Text
ContainerSlot
  container   ContainerId
  item        InventoryId Maybe

Теперь, используя Esqueleto, я хочу использовать LeftOuterJoin чтобы получить слоты в контейнере, с фактическим запасом, если он не был назначен.

selectContainerSlots containerKey = do
  stuff <- select $ from $ \(cs `LeftOuterJoin` i) -> do
    on $ cs ^. ContainerSlotItem ==. just (i ^. InventoryId)
    where_ $ cs ^. ContainerSlotContainer ==. val containerKey
    return (cs, i)
  return $ uncurry buildStuff <$> stuff

Я бы ожидал buildStuff нужна следующая подпись из-за "внешнего" характера объединения:

buildStuff :: Entity ContainerSlot -> Maybe (Entity Inventory) -> Result

но обнаружим, что для этого нужно следующее:

buildStuff :: Entity ContainerSlot -> Entity Inventory -> Result

Что вызывает сбои во время выполнения, когда (как и ожидалось) Inventory поля заполнены NULL ценности.

PersistMarshalError "field id: int64 Expected Integer, received: PersistNull"

Есть ли способ проецировать Entity Inventory как Maybe (Entity Inventory)?

1 ответ

Решение

Это, вероятно, может быть помечено как дубликат Внешних соединений с Esqueleto; однако разница в проекции.

При работе с любыми внешними объединениями все таблицы, которые могут возвращаться нулевыми, должны иметь все проекции, выполненные с ?. синтаксис. Это заставит сущности таблицы стать Maybe (Entity a) Таким образом, решение выше

selectContainerSlots containerKey = do
  stuff <- select $ from $ \(cs `LeftOuterJoin` i) -> do
    on $ cs ^. ContainerSlotItem ==. i ?. InventoryId
    where_ $ cs ^. ContainerSlotContainer ==. val containerKey
    return (cs, i)
  return $ uncurry buildStuff <$> stuff

Кроме того, если несколько таблиц связаны друг с другом; например

select $ from $ \(cs `LeftOuterJoin` (i `InnerJoin` is)) -> do

Тогда оба i а также is (таблица SKU инвентаризации) должен быть спроектирован с таким синтаксисом:

  on $ i ?. InventoryId ==. is ?. InventorySkuItem
  on $ cs ^. ContainerSlotItem ==. i ?. InventoryId
Другие вопросы по тегам