nuwave / lighthouse

A framework for serving GraphQL from Laravel
https://lighthouse-php.com
MIT License
3.37k stars 437 forks source link

Ability to access the parent model in `@builder` directive #1736

Open hosmelq opened 3 years ago

hosmelq commented 3 years ago

What problem does this feature proposal attempt to solve?

I have the following schema

type Category {
  products: [Product!]!
    @builder(method: "App\\GraphQL\\Categories\\Builders\\OrderProducts")
    @belongsToMany(maxCount: 50, type: CONNECTION)
}

I would like to have access to the Category model within the builder because I have a field that specifies how the products are ordered within that Category.

At the moment I only have access to the builder.

Which possible solutions should be considered?

I don't know what would be the best solution for this.

spawnia commented 3 years ago

To enable this, we would have to pass the resolver arguments - in your case $root - to ArgumentSet::enhanceBuilder() and all functions below it. Such a change would be a lot of work and can not be implemented without significant breakage.

I do not plan to add support for this any time soon, but if you really want it you can give it a shot.

hosmelq commented 3 years ago

I was checking the implementation of ArgumentSet::enhanceBuilder() and found that there are some directives that do not need the $root argument.

Maybe I can create a new interface to implement something like FieldBuilderDirectiveWithRoot with a method like handleFieldBuilder(object $builder, Model $root).

The $root model can be passed as a third parameter to the resolver to avoid breaking changes.

spawnia commented 3 years ago

If we were to change this, we should also pass along the other resolver arguments, not just $root. That way we won't have to extend this even further if other use cases pop up.

I thought of one special case to consider, where passing $root is somewhat ambiguous: builders for batched resolvers. For example, in a scenario like this:

type Post {
  comments(popular: Boolean @eq): [Comment!]! @hasMany
}

{
  posts {
    comments(popular: true) { ... }
  }
}

Assuming there are multiple posts, there are multiple instances of $root when resolving comments. However, Lighthouse optimizes the query through batch loading, which means there will only be a single query for comments and thus a single call to the EqDirective. There is no clear answer which of the parent posts should be the $root for that call.