I'm new to GRDB and trying to understand how to make a fairly simple left join work. I'm loading data from a source I have no control over, so I'm trying to keep things simple by avoiding nullable fields in my model types.
I'm having problems with .belongsTo
not creating the related object.
Imagine a Book
with a foreign key category_id
:
struct Book: Codable, Sendable, FetchableRecord, PersistableRecord, Equatable {
public let bookId: String
public let categoryId: String
// I'd like GRDB to map this to a valid category object after loading
public var category: Category?
enum CodingKeys: String, CodingKey {
case bookId = "book_id"
case categoryId = "category_id"
}
static let categoryColumn = Column(CodingKeys.categoryId.rawValue)
static let categoryForeignKey = ForeignKey([categoryColumn])
static let category = belongsTo(Category.self, using: categoryForeignKey).forKey("category")
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
self.bookId = container.decodeString(forKey: .bookId)
self.categoryId = container.decodeString(forKey: .categoryId)
}
}
struct Category: Codable, Sendable, FetchableRecord, PersistableRecord, Equatable {
public let name: String
public let categoryId: String
public var category: Category?
enum CodingKeys: String, CodingKey {
case categoryId = "category_id"
case name
}
}
When querying, I use this, which appears to be loading all the data:
let all = try Book.all()
.including(optional: Book.category)
.asRequest(of: Book.self) // Not sure if this is even needed
.fetchAll(database)
I would expect category
to be loaded if there's a valid item with a matching category id. Instead, it's always null. I don't see any obvious errors in the logs, and I confirmed the SQL query is including the left outer join.
Interestingly, this works, but I'd rather not have to deal with yet another type.
struct BookWithCategory: : FetchableRecord, Decodable {
let book: Book
let category: Category?
}
let all = try Book.all()
.including(optional: Book.category)
.asRequest(of: BookWithCategory.self)
.fetchAll(database)