Presenting acronyms with the creator name

I have a use case where I need to present a list of records with a join value from each record. This is usually done with a JOIN in SQL.

To provide some context, I would use the TILApp. I have modified the code in Chapter 21 so that I could have an index webpage where the creator’s name for each acronym is displayed alongside the acronym. The code works, but I am unsure of the efficiency:

  func indexHandler(_ req: Request) throws -> Future<View> {
    return Acronym.query(on: req)
      .all()
      .flatMap(to: View.self) { acronyms in // required in order to get the related user for another query??
        return flatMap(
            to: View.self,
            req.future(acronyms), // wrap the acronyms back into a future in order to flatMap it with the future from user??
            acronyms.map { $0.user.get(on: req) }.flatten(on: req)) { acronyms, users in
                let acronymsData: [AcronymData]? = acronyms.isEmpty ? nil : acronyms.map { acronym in
                    let user = users.filter { $0.id == acronym.userID }.first
                    return AcronymData(short: acronym.short, long: acronym.long, creatorName: user?.name ?? "")
                }
                let userLoggedIn = try req.isAuthenticated(User.self)
                let showCookieMessage = req.http.cookies["cookies-accepted"] == nil
                let context = IndexContext(title: "Homepage",
                                           acronyms: acronymsData,
                                           userLoggedIn: userLoggedIn,
                                           showCookieMessage: showCookieMessage)
                return try req.view().render("index", context)
        }
    }
  }

struct AcronymData: Encodable { // View Model using primitives
    let short: String
    let long: String
    let creatorName: String
}

struct IndexContext: Encodable {
  let title: String
  let acronyms: [AcronymData]?
  let userLoggedIn: Bool
  let showCookieMessage: Bool
}

My question is:

Is there a more concise and elegant way to perform a join query which will fetch the user (perhaps even selected properties of user)?

@0xtim Can you please help with this when you get a chance? Thank you - much appreciated! :]

A join should actually work for this one. It will be more efficient (less database queries) but the code will be more complicated. What you’ll want to do is something like:

return Acronym.query(on: req).join(\User.id, to: \Acronym.userID).alsoDecode(User.self).all().map(to: View.self) { acronymUserPairs in

That will give you a tuple containing (acronym, user) which you can then use to construct the array of AcronymData. Hope that helps!

1 Like