2017-04-02 2 views
1

D'un config/models artificiel dans un site échafaudée:De retour `Peut-être (entité a)` `de Esqueleto LeftOuterJoin`

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

Maintenant, en utilisant Esqueleto, je veux utiliser LeftOuterJoin pour obtenir les créneaux horaires dans un récipient, avec l'inventaire réel vide s'il n'a pas été affecté.

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 

Je me attends buildStuff avoir besoin de la signature suivante en raison de la nature "extérieure" de la jointure:

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

mais trouve qu'il a besoin de ce qui suit:

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

qui provoque des échecs d'exécution lorsque (de façon prévisible) les champs Inventory sont remplis avec NULL valeurs.

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

est-il un moyen de projeter le Entity Inventory comme Maybe (Entity Inventory)?

Répondre

1

Cela pourrait probablement être marqué comme un doublon de Outer Joins with Esqueleto; Cependant, la différence est dans la projection.

Lorsque vous traitez des jointures externes, toutes les tables qui peuvent revenir à zéro doivent avoir toutes les projections effectuées avec la syntaxe ?.. Cela forcera les entités de la table pour devenir Maybe (Entity a) Donc, la solution à ce qui précède est

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 

De plus, si plus d'une table est enchaînée; par exemple.

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

Puis les deuxi et is (inventaire tableau SKU) doit être projeté avec cette syntaxe:

on $ i ?. InventoryId ==. is ?. InventorySkuItem 
    on $ cs ^. ContainerSlotItem ==. i ?. InventoryId