fluent-kit icon indicating copy to clipboard operation
fluent-kit copied to clipboard

Soft-deleted Parent relationship don't load even withDeleted

Open hartbit opened this issue 4 years ago • 7 comments

The following query:

Planet.query(on: req.db).with(\.$star).withDeleted().all().map { planets in
    for planet in planets {
        print(planet.star)
    }
}

will crash the process with:

Fatal error: Parent relation not eager loaded, use $ prefix to access: Parent<Planet, Star>(key: star_id)

if a referenced Star is soft-deleted, despite the withDeleted call.

hartbit avatar Aug 18 '20 21:08 hartbit

Here are some ideas for future discussion:

  • Should a withDeleted on a top-level query really trickle down to eager loads or do we only want a way to modify an eager load to return deleted objects? I would prefer the latter.
  • What would really make sense for me would be a way to configure at the relationship definition level if they should always load deleted objects or not:
@Parent(key: "star_id", withDeleted: true)

hartbit avatar Aug 18 '20 21:08 hartbit

Related to https://github.com/vapor/fluent-kit/issues/227

tanner0101 avatar Aug 20 '20 19:08 tanner0101

@tanner0101 I can't remember if you mentioned if there was a workaround meanwhile?

hartbit avatar Aug 20 '20 20:08 hartbit

Can you do:

Planet.query(on: req.db).with(\.$star) { star in
    star.withDeleted()
}.withDeleted().all().map { planets in
    for planet in planets {
        print(planet.star)
    }
}

0xTim avatar Aug 21 '20 09:08 0xTim

No, that doesn't compile:

error: Value of type 'NestedEagerLoadBuilder<QueryBuilder<Planet>, ParentProperty<Planet, Star>>' has no member 'withDeleted'

hartbit avatar Aug 21 '20 19:08 hartbit

Annoying but one option to add the API to

0xTim avatar Aug 22 '20 08:08 0xTim

It would be great if withDeleted() also applied to eager loaded relationships. In the meantime, here's the work-around that worked for me:

Child.query(on: request.db)
    .withDeleted()
    .all()
    .flatMap { children in
        request.eventLoop.makeSucceededFuture(children)
            .flatMapEach(on: request.eventLoop) { child in
                child.$parent
	            .query(on: request.db)
                    .withDeleted()
                    .first()
                    .map { parent in
                        child[keyPath: \.$parent].value = parent
                    }
            }
            .map {
                 children
            }
    }

avario avatar Oct 18 '20 08:10 avario