Search code examples
haskellyesodhaskell-persistent

How to get referenced model information in Yesod?


I have 3 Models

Address json
    number Text
    street Text
    pincode Text
    deriving Show
Person json
    email Text
    name Text
    telephone Text
    deriving Show
House json
    rent Int
    ownerId PersonId
    addressId AddressId
    deriving Show

I want to access all houses. Which I can get by doing

getHouseR :: Handler Value
getHouseR = do
 houses <- runDB $ selectList [] [Asc HouseRent]
 return $ toJSON houses

But I get only reference to the other entities like person & address.

[{"rent":8000,"addressId":4,"ownerId":1,"id":3},{"rent":10000,"addressId":2,"ownerId":1,"id":1}]

I would like to get complete information of house, That means, resolve that ownerId & addressId and get that data sent which might look like,

[{"rent":8000,"address":{"number": "23", "street": "12/B", "pincode": "111111"},"owner":{"email": "hey@email.com", "name": "Moto", "telephone": "xxxxxxxxxx"},"id":3}]

Is there any way to add an information like getForiegnData to the query and that would fetch me all this ? Or any other solution ?


Solution

  • I couldn't find any direct way (similar to annotations) to fetch referenced model information. But there are 2 ways we can get this done.

    1. Incase, if your database is SQL. You can use esqueleto https://github.com/bitemyapp/esqueleto/blob/master/README.md.
    2. Write some boilerplate code and get information.

    Create the HouseResp type, which will represent your response body including person and address information.

    data HouseResp = HouseResp
      { rent :: Int
      , owner :: Person
      , address :: Address
      }
    

    Then, modify getHouseR to fetch complete information for every house by using available reference id.

    getHouseR :: Handler Value
    getHouseR = do
      housesWithReference <- runDB $ selectList [] [Asc HouseRent]
      houses <- sequence (Import.map getCompleteHouse housesWithReference)
      return $ toJSON houses
    
    
    getCompleteHouse :: Entity House -> Handler HouseResp
    getCompleteHouse house = runDB $ do
      let rent' = houseRent (entityVal house)
      person <- getJust (houseOwnerId (entityVal house))
      address' <- getJust (houseAddressId (entityVal house))
      return (HouseResp rent' person address')