-
-
Notifications
You must be signed in to change notification settings - Fork 120
Description
Description
Eager loading of sibling relation causes fatal error.
Fatal error: Cannot access field before it is initialized or fetched
The data in the database seems to be correctly created. The relations exist and are filled. However, I cannot access them in a query. The problem only occurs with some sibling relations, but only when querying a sibling that is held by an optional parent, or with a sibling that may be empty. Not with all of them.
Details
Case 1:
Sibling relation of optional parent
Example EntityOne with sibling relation to EntityTwo
final class EntityOne: Model, Content {
static let schema = "entity_one"
@Siblings(
through: EntityOneAttachedEntityTwo.self,
from: \.$entityOne,
to: \.$entityTwo
) var attachedEntityTwo: [EntityTwo]
init() {}
EntityThree with optional parent relation to EntityOne
final class EntityThree: Model, Content {
static let schema = "entity_three"
@ID var id: UUID?
...Fields..
@OptionalParent(key: "entity_one_id") var entityOne: EntityOne?
init() {}
}
--> Query
let entity = try await EntityThree
.query(on: req.db)
.with(\.$entityThree) { entityThree in
entityThree
.with(\.$field) // Fields, Parents, etc. work fine
.with(\.$attachedEntityTwo) // Causes fatal error in all()
}
.all()
}
BUT: entity.entityThree.load(on: db) works fine
Case 2:
Same behaviour as Case 1, but without optional parent relation
Example EntityOne with sibling relation to EntityTwo
final class EntityOne: Model, Content {
...
@Siblings(
through: EntityOneAllowedEntityTwo.self,
from: \.$entityOne,
to: \.$entityTwo
) var allowedEntityTwo: [EntityTwo]
....
}
RelationTable (same for case 1)
final class EntityOneAllowedEntityTwo: Model {
...
@ID(key: .id) var id: UUID?
@Parent(key: "entity_one_id") var entityOne: EntityOne
@Parent(key: "entity_two_id") var entityTwo: EntityTwo
init() {}
init(id: UUID? = nil,
entityOne: EntityOne,
entityTwo: EntityTwo
) throws {
self.id = id
self.$entityOne = try entityOne.requireID()
self.$entityTwo = try entityTwo.requireID()
}
}
Eager loading in query failes, but loading afterwards works fine.
let entityOne = try await EntityOne
.query(on: db)
.with(\.$field) // Everything works fine
// .with(\.$allowedEntityTwo) // Causes fatal error
.first()
.unwrap(or: Abort(.notFound))
.get()
But: try await entityOne.$allowedEntityTwo.loadIfNeeded(on: db) also works fine.
Migration for relation table
struct CreateEntityOneAllowedEntityTwoPivot: Migration {
func prepare(on database: Database) -> EventLoopFuture<Void> {
database.schema(EntityOneAllowedEntityTwo.schema)
.id()
.field("entity_one_id",
.uuid,
.references(EntityOne.schema, "id", onDelete: .cascade),
.required)
.field("entity_two_id",
.uuid,
.references(EntityTwo.schema, "id", onDelete: .cascade),
.required)
.unique(on: "entity_one_id", "entit_two_id")
.create()
}
func revert(on database: Database) -> EventLoopFuture<Void> {
database.schema(EntityOneAllowedEntityTwo.schema)
.delete()
}
}
Expected behavior
Sibling relations should be eager loaded / accessed in query
Environment
Vapor 4.77
MacOS: 13.5