Hey,
i'm trying to understand how and when exactly eager loading happens. Let's imagine we have following User model:
final class User: Model, Content, Authenticatable {
static let schema = "users"
enum Keys {
static let id = "id"
static let name = "name"
static let surname = "surname"
static let email = "email"
static let passwordHash = "password_hash"
static let createdAt = "created_at"
static let updatedAt = "updated_at"
}
@ID(key: Keys.id)
var id: Int?
@Field(key: Keys.name)
var name: String
@Field(key: Keys.surname)
var surname: String?
@Field(key: Keys.email)
var email: String
@Field(key: Keys.passwordHash)
var passwordHash: String
@Timestamp(key: Keys.createdAt, on: .create)
var createdAt
@Timestamp(key: Keys.updatedAt, on: .update)
var updatedAt
@Children(for: \.$owner)
var wallets: [Wallet] // wallets that user owns
@Siblings(through: WalletGuest.self, from: \.$guest, to: \.$wallet)
var guestWallets: [Wallet] // wallets that user visits in
@Children(for: \.$author)
var ownedTransactions: [Transaction]
// with neccessary inits as well
}
extension User {
struct Public: Content { // so that I can share User object without passwordHash
var id: Int?
var name: String
var surname: String?
var email: String
var createdAt: Date?
var updatedAt: Date?
var wallets: [Wallet] // wallets that user owns
var guestWallets: [Wallet] // wallets that user visits in
var ownedTransactions: [Transaction]
}
func makePublic() -> Public {
Public(id: self.id, name: self.name, surname: self.surname, email: self.email, createdAt: self.createdAt, updatedAt: self.updatedAt, wallets: self.wallets, guestWallets: self.guestWallets, ownedTransactions: self.ownedTransactions)
}
}
And we have following route:
tokenProtected.get("me") { req -> EventLoopFuture<User.Public> in
let thisUser = try req.auth.require(User.self)
return thisUser
}
Now I have 2 questions:
-
this endpoint works fine, however I'm wondering if there's any way I could load missing relation data (from childrens or siblings) into User object like
wallets
without needing to do whole Query chaining like in second version ?
I did try:
print(thisUser.wallets)
but it crashes with information that I should use it through $ but then
print(thisUser.$wallets)
I'm not sure how could I use it, other than through query:
try thisUser.$wallets.query(on: req.db).all()
especially when I want to get access into all relation fields inside same object. -
Is there any way I could do "deeper" eager loads ?
Wallet looks like this:
final class Wallet: Model, Content {
static let schema = "wallets"
// other properties
@Siblings(through: WalletGuest.self, from: \.$wallet, to: \.$guest)
var guests: [User] // users that visit this wallet
}
and now I want to print User object with it's wallets and guests of these wallets so:
User.query(on: req.db)
.filter(\.$id == thisUser.id!)
.with(\.$wallets)
.with(\.$wallets.$guests) // something like that
could give me such response
{
"id": 1,
"name": "User Foo",
"wallets": [
{
"id": 1,
"guests": [
{
"id": "5",
"name": "User Joe",
}
]
}
]
}