haskellyesodhaskell-persistent

How to create a list of a single column with yesod-persistent?


Given a user, I am trying to select a list of events that are affiliated with organizations that the user is in. The UserOrg table describes which OrgIds correspond to a given UserId.

I have these tables:

User
    email Text
    name Text
    UniqueUser email
    deriving Typeable
Event
    name Text
    description Text
    dateTime UTCTime
    userId UserId
    orgId OrgId
    deriving Show
Org
    name Text
    description Text
    deriving Show
UserOrg
    userId UserId
    orgId OrgId

Currently I am trying this:

getEventR :: Handler Html
getEventsR = do
    muser <- maybeAuth
    eventList <- runDB $ 
        case muser of
            Nothing -> []
            (Just euser) -> selectList [ EventOrgId <-. (userOrgIds $ entityKey euser) ] []
    defaultLayout $ do
        setTitle "Events"
        $(widgetFile "events")

userOrgIds :: UserId -> [OrgId]
userOrgIds userid = do
    rows <- liftHandler $ runDB $ selectList [ UserOrgUserId ==. userid ] []
    return $ [ userOrgOrgId $ entityVal $ erow | erow <- rows ]

But I get a type error saying that the return of userOrgIds returns a [[OrgId]] rather than [OrgId], and concat doesn't work here

Am I going about this wrong? Should I just use rawQuery in this case?


Solution

  • It's a good start, but I see a number of things wrong with this.

    getEventR :: Handler Html
    getEventsR = do
    

    These function names don't match.

        muser <- maybeAuth
        eventList <- runDB $ 
            case muser of
                Nothing -> []
                (Just euser) -> selectList [ EventOrgId <-. (userOrgIds $ entityKey euser) ] []
    

    I'm not sure this will work; you probably want your Nothing branch to provide pure [].

        defaultLayout $ do
            setTitle "Events"
            $(widgetFile "events")
    

    This looks fine.

    userOrgIds :: UserId -> [OrgId]
    userOrgIds userid = do
        rows <- liftHandler $ runDB $ selectList [ UserOrgUserId ==. userid ] []
        return $ [ userOrgOrgId $ entityVal $ erow | erow <- rows ]
    

    This definitely won't work. In your type signature, you've said that it's a pure function; it takes a UserId (which is a synonym for Key User), and returns a list of OrgId (again, synonymous with Key Org) values. However in your implementation, you're using liftHandler, runDB, and selectList. These are all effectful things!

    Here's how I would write your Handler.

    getEventsR :: Handler Html
    getEventsR = do
      mUser <- maybeAuth
      eventList <- case mUser of
        Nothing -> pure []
        Just user -> runDB $ do
          orgs <- selectList [ UserOrgUserId ==. entityKey user ] []
          selectList [ EventOrgId <-. map entityKey orgs ] []
      defaultLayout $ do
        setTitle "Events"
        $(widgetFile "events")
    

    I'm writing that without a compiler, but it should be correct.