haskellyesodesqueleto

YesodDB, how to put types correctly


I have created a function for loading some Entities but I am having some trouble to understand how I should put its type declaration, so I took this Yesod book chapter about Yesod monads, to understand it better, and I came to this snippet:

-- type Distance = Int
worksByNhood :: AdrNhoodId -> Int64 -> Int64 -> YesodDB App [(Entity Work, Int, [Entity WImage])] 
worksByNhood nId offset' limit' = do
  works <- select $ from $ \(w `InnerJoin` d) -> do
    on $ d ^. AdrDistanceNhood2 ==. w ^. WorkNhood
    where_ (d ^. AdrDistanceNhood1 ==. val nId)
    orderBy [asc (d ^. AdrDistanceDistance)]
    offset offset'
    limit limit'
    return (w, d ^. AdrDistanceDistance)
  works' <- forM works $ \(w@(Entity wId _), d) -> do
    images <- select $ from $ \wi -> do
      where_ (wi ^. WImageWork ==. val wId)
      return wi
    return (w, d, images);
  return works'

I think this Int in the type declaration needs to be converted someway, to be more specific, I am getting this error:

Select.hs:20:12:
    Couldn't match type ‘Database.Esqueleto.Value Distance’ with ‘Int’
    Expected type: (Entity Work, Distance, [Entity WImage])
      Actual type: (Entity Work,
                    Database.Esqueleto.Value Distance,
                    [Entity WImage])
    In the first argument of ‘return’, namely ‘(w, d, images)’
    In a stmt of a 'do' block: return (w, d, images)
    In the expression:
      do { images <- select $ from $ \ wi -> do { ... };
           return (w, d, images) }

Solution

  • I remembered there is a chapter about joins in the great Yesod book, so I read it again and found the solution, maybe my code may help others, so here it goes:

    module Select where
    
    import Import hiding((==.), on, Value)
    import Database.Persist.Sql (toSqlKey) -- Useful when I want to explicitly use primary keys
    import Database.Esqueleto
    
    -- type Distance = Int
    worksByNhood :: AdrNhoodId -> Int64 -> Int64 -> YesodDB App [(Entity Work, Value Distance, [Entity WImage])] 
    worksByNhood nId offset' limit' = do
      works <- select $ from $ \(w `InnerJoin` d) -> do
        on $ d ^. AdrDistanceNhood2 ==. w ^. WorkNhood
        where_ (d ^. AdrDistanceNhood1 ==. val nId)
        orderBy [asc (d ^. AdrDistanceDistance)]
        offset offset'
        limit limit'
        return (w, d ^. AdrDistanceDistance)
      forM works $ \(w@(Entity wId _), d) -> do
        images <- select $ from $ \wi -> do
          where_ (wi ^. WImageWork ==. val wId)
          return wi
        return (w, d, images)
    

    Value Distance at the type declaration is the answer