Skip to content

Eager loading of sibling relation causes fatal error #641

@karola-gr

Description

@karola-gr

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions