Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor builder types #2389

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ You can find and compare releases at the [GitHub release page](https://github.co

## Unreleased

### Changed

- Use common Builder interface https://github.com/nuwave/lighthouse/pull/2389
- Do not pass `ResolveInfo` to itself in `ResolveInfo::enhanceBuilder()` https://github.com/nuwave/lighthouse/pull/2389

## v6.9.1

### Fixed
Expand Down
30 changes: 30 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,36 @@ It will prevent the following type of HTTP requests:
- `GET` requests
- `POST` requests that can be created using HTML forms

### Type hinting query builders

Lighthouse now uses `Illuminate\Contracts\Database\Query\Builder` to type hint database query builders.
If you implement `ArgBuilderDirective` or `FieldBuilderDirective`, you will have to change the signature of the `handleFieldBuilder` method accordingly:

```diff
- use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
- use Illuminate\Database\Eloquent\Relations\Relation;
- use Illuminate\Database\Query\Builder as QueryBuilder;
+ use Illuminate\Contracts\Database\Query\Builder;

- public function handleFieldBuilder(QueryBuilder|EloquentBuilder|Relation $builder, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): QueryBuilder|EloquentBuilder|Relation;
+ public function handleFieldBuilder(Builder $builder, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): Builder;
spawnia marked this conversation as resolved.
Show resolved Hide resolved
```

### Do not pass `ResolveInfo` to itself in `ResolveInfo::enhanceBuilder()`

`ResolveInfo::enhanceBuilder()` no longer expects to be passed an instance of `ResolveInfo`,
as it can access it via `$this`.

```diff
use Nuwave\Lighthouse\Execution\ResolveInfo;
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;

// Some resolver function or directive middleware
function (mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo) {
- $resolveInfo->enhanceBuilder($builder, $scopes, $root, $args, $context, $resolveInfo, $directiveFilter);
+ $resolveInfo->enhanceBuilder($builder, $scopes, $root, $args, $context, $directiveFilter);
```

## v5 to v6

### `messages` on `@rules` and `@rulesForArray`
Expand Down
6 changes: 2 additions & 4 deletions docs/master/custom-directives/argument-directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,7 @@ where the `category` column is equal to the value of the `category` argument.
So let's take a look at a simplified version of the built-in [@eq](../api-reference/directives.md#eq) directive.

```php
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Contracts\Database\Query\Builder;
use Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective;

class EqDirective extends BaseDirective implements ArgBuilderDirective
Expand All @@ -171,7 +169,7 @@ GRAPHQL;
/**
* Apply a "WHERE = $value" clause.
*/
public function handleBuilder(QueryBuilder|EloquentBuilder|Relation $builder, $value): QueryBuilder|EloquentBuilder|Relation
public function handleBuilder(Builder $builder, $value): Builder
{
return $builder->where(
$this->directiveArgValue('key', $this->nodeName()),
Expand Down
2 changes: 0 additions & 2 deletions src/Auth/CanDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ protected function modelsToCheck(mixed $root, array $args, GraphQLContext $conte
$root,
$args,
$context,
$resolveInfo,
)
->get();
}
Expand Down Expand Up @@ -194,7 +193,6 @@ protected function modelsToCheck(mixed $root, array $args, GraphQLContext $conte
$root,
$args,
$context,
$resolveInfo,
Utils::instanceofMatcher(TrashedDirective::class),
);
assert($enhancedBuilder instanceof EloquentBuilder);
Expand Down
5 changes: 2 additions & 3 deletions src/Auth/WhereAuthDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
namespace Nuwave\Lighthouse\Auth;

use Illuminate\Contracts\Auth\Factory as AuthFactory;
use Illuminate\Contracts\Database\Query\Builder;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Nuwave\Lighthouse\Execution\ResolveInfo;
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
use Nuwave\Lighthouse\Support\Contracts\FieldBuilderDirective;
Expand Down Expand Up @@ -38,7 +37,7 @@ public static function definition(): string
GRAPHQL;
}

public function handleFieldBuilder(QueryBuilder|EloquentBuilder|Relation $builder, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): QueryBuilder|EloquentBuilder|Relation
public function handleFieldBuilder(Builder $builder, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): Builder
{
assert($builder instanceof EloquentBuilder);

Expand Down
41 changes: 16 additions & 25 deletions src/Execution/ResolveInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
namespace Nuwave\Lighthouse\Execution;

use GraphQL\Type\Definition\ResolveInfo as BaseResolveInfo;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Contracts\Database\Query\Builder;
use Illuminate\Support\Collection;
use Laravel\Scout\Builder as ScoutBuilder;
use Nuwave\Lighthouse\Execution\Arguments\ArgumentSet;
Expand Down Expand Up @@ -37,26 +35,21 @@ public function __construct(
/**
* Apply ArgBuilderDirectives and scopes to the builder.
*
* @template TModel of \Illuminate\Database\Eloquent\Model
*
* @param \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<TModel>|\Illuminate\Database\Eloquent\Relations\Relation<TModel>|\Laravel\Scout\Builder $builder
* @param array<string> $scopes
* @param array<string, mixed> $args
* @param (callable(\Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective): bool)|null $directiveFilter
*
* @return \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<TModel>|\Illuminate\Database\Eloquent\Relations\Relation<TModel>|\Laravel\Scout\Builder
* @api
*/
public function enhanceBuilder(QueryBuilder|EloquentBuilder|Relation|ScoutBuilder $builder, array $scopes, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo, callable $directiveFilter = null): QueryBuilder|EloquentBuilder|Relation|ScoutBuilder
public function enhanceBuilder(Builder|ScoutBuilder $builder, array $scopes, mixed $root, array $args, GraphQLContext $context, callable $directiveFilter = null): Builder|ScoutBuilder
{
$argumentSet = $resolveInfo->argumentSet;

$scoutEnhancer = new ScoutEnhancer($argumentSet, $builder);
$scoutEnhancer = new ScoutEnhancer($this->argumentSet, $builder);
if ($scoutEnhancer->canEnhanceBuilder()) {
return $scoutEnhancer->enhanceBuilder();
}

self::applyArgBuilderDirectives($argumentSet, $builder, $directiveFilter);
self::applyFieldBuilderDirectives($builder, $root, $args, $context, $resolveInfo);
self::applyArgBuilderDirectives($this->argumentSet, $builder, $directiveFilter);
self::applyFieldBuilderDirectives($builder, $root, $args, $context, $this);

foreach ($scopes as $scope) {
$builder->{$scope}($args);
Expand All @@ -72,24 +65,24 @@ public function enhanceBuilder(QueryBuilder|EloquentBuilder|Relation|ScoutBuilde
* @param array<string> $scopes
* @param array<string, mixed> $args
* @param (callable(\Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective): bool)|null $directiveFilter
*
* @api
*/
public function wouldEnhanceBuilder(QueryBuilder|EloquentBuilder|Relation|ScoutBuilder $builder, array $scopes, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo, callable $directiveFilter = null): bool
public function wouldEnhanceBuilder(Builder|ScoutBuilder $builder, array $scopes, mixed $root, array $args, GraphQLContext $context, callable $directiveFilter = null): bool
{
$argumentSet = $resolveInfo->argumentSet;

return (new ScoutEnhancer($argumentSet, $builder))->wouldEnhanceBuilder()
|| self::wouldApplyArgBuilderDirectives($argumentSet, $builder, $directiveFilter)
|| self::wouldApplyFieldBuilderDirectives($resolveInfo)
return (new ScoutEnhancer($this->argumentSet, $builder))->wouldEnhanceBuilder()
|| self::wouldApplyArgBuilderDirectives($this->argumentSet, $builder, $directiveFilter)
|| self::wouldApplyFieldBuilderDirectives($this)
|| $scopes !== [];
}

/**
* Recursively apply the ArgBuilderDirectives onto the builder.
*
* @param \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model>|\Illuminate\Database\Eloquent\Relations\Relation<\Illuminate\Database\Eloquent\Model> $builder
* @param \Illuminate\Contracts\Database\Query\Builder $builder
* @param (callable(\Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective): bool)|null $directiveFilter
*/
protected static function applyArgBuilderDirectives(ArgumentSet $argumentSet, QueryBuilder|EloquentBuilder|Relation &$builder, callable $directiveFilter = null): void
protected static function applyArgBuilderDirectives(ArgumentSet $argumentSet, Builder &$builder, callable $directiveFilter = null): void
{
foreach ($argumentSet->arguments as $argument) {
$value = $argument->toPlain();
Expand Down Expand Up @@ -122,10 +115,9 @@ static function ($value) use (&$builder, $directiveFilter): void {
/**
* Would there be any ArgBuilderDirectives to apply to the builder?
*
* @param \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model>|\Illuminate\Database\Eloquent\Relations\Relation<\Illuminate\Database\Eloquent\Model> $builder
* @param (callable(\Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective): bool)|null $directiveFilter
*/
protected static function wouldApplyArgBuilderDirectives(ArgumentSet $argumentSet, QueryBuilder|EloquentBuilder|Relation &$builder, callable $directiveFilter = null): bool
protected static function wouldApplyArgBuilderDirectives(ArgumentSet $argumentSet, Builder &$builder, callable $directiveFilter = null): bool
{
foreach ($argumentSet->arguments as $argument) {
$filteredDirectives = $argument
Expand Down Expand Up @@ -164,10 +156,9 @@ protected static function wouldApplyArgBuilderDirectives(ArgumentSet $argumentSe
/**
* Apply the FieldBuilderDirectives onto the builder.
*
* @param \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder<\Illuminate\Database\Eloquent\Model>|\Illuminate\Database\Eloquent\Relations\Relation<\Illuminate\Database\Eloquent\Model> $builder
* @param array<string, mixed> $args
*/
protected static function applyFieldBuilderDirectives(QueryBuilder|EloquentBuilder|Relation &$builder, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): void
protected static function applyFieldBuilderDirectives(Builder &$builder, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): void
{
foreach (self::fieldBuilderDirectives($resolveInfo) as $fieldBuilderDirective) {
$builder = $fieldBuilderDirective->handleFieldBuilder($builder, $root, $args, $context, $resolveInfo);
Expand Down
7 changes: 3 additions & 4 deletions src/OrderBy/OrderByDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
use GraphQL\Language\AST\InterfaceTypeDefinitionNode;
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
use GraphQL\Language\Parser;
use Illuminate\Contracts\Database\Query\Builder;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Nuwave\Lighthouse\Exceptions\DefinitionException;
Expand Down Expand Up @@ -112,7 +111,7 @@ enum OrderByDirection {
}

/** @param array<array<string, mixed>> $value */
public function handleBuilder(QueryBuilder|EloquentBuilder|Relation $builder, $value): QueryBuilder|EloquentBuilder|Relation
public function handleBuilder(Builder $builder, $value): Builder
{
foreach ($value as $orderByClause) {
$order = Arr::pull($orderByClause, 'order');
Expand Down Expand Up @@ -260,7 +259,7 @@ public function manipulateArgDefinition(
}
}

public function handleFieldBuilder(QueryBuilder|EloquentBuilder|Relation $builder, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): QueryBuilder|EloquentBuilder|Relation
public function handleFieldBuilder(Builder $builder, mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): Builder
{
return $builder->orderBy(
$this->directiveArgValue('column'),
Expand Down
23 changes: 4 additions & 19 deletions src/Pagination/PaginateDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,11 @@
use GraphQL\Language\AST\InterfaceTypeDefinitionNode;
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Laravel\Scout\Builder as ScoutBuilder;
use Nuwave\Lighthouse\Cache\CacheDirective;
use Nuwave\Lighthouse\Execution\ResolveInfo;
use Nuwave\Lighthouse\Schema\AST\DocumentAST;
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
use Nuwave\Lighthouse\Schema\Directives\Traits\HasBuilderArgument;
use Nuwave\Lighthouse\Schema\Values\FieldValue;
use Nuwave\Lighthouse\Support\Contracts\ComplexityResolverDirective;
use Nuwave\Lighthouse\Support\Contracts\Directive;
Expand All @@ -23,6 +20,8 @@

class PaginateDirective extends BaseDirective implements FieldResolver, FieldManipulator, ComplexityResolverDirective
{
use HasBuilderArgument;

public static function definition(): string
{
return /** @lang GraphQL */ <<<'GRAPHQL'
Expand Down Expand Up @@ -152,26 +151,12 @@ public function resolveField(FieldValue $fieldValue): callable
return $paginator;
}

if ($this->directiveHasArgument('builder')) {
$builderResolver = $this->getResolverFromArgument('builder');

$query = $builderResolver($root, $args, $context, $resolveInfo);

assert(
$query instanceof QueryBuilder || $query instanceof EloquentBuilder || $query instanceof ScoutBuilder || $query instanceof Relation,
"The method referenced by the builder argument of the @{$this->name()} directive on {$this->nodeName()} must return a Builder or Relation.",
);
} else {
$query = $this->getModelClass()::query();
}

$query = $resolveInfo->enhanceBuilder(
$query,
$this->makeBuilder($root, $args, $context, $resolveInfo),
$this->directiveArgValue('scopes', []),
$root,
$args,
$context,
$resolveInfo,
);

$paginationArgs = PaginationArgs::extractArgs($args, $this->paginationType(), $this->paginateMaxCount());
Expand Down
12 changes: 3 additions & 9 deletions src/Pagination/PaginationArgs.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
namespace Nuwave\Lighthouse\Pagination;

use GraphQL\Error\Error;
use Illuminate\Contracts\Database\Query\Builder;
use Illuminate\Contracts\Pagination\Paginator;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Support\Arr;
use Laravel\Scout\Builder as ScoutBuilder;

Expand Down Expand Up @@ -74,13 +72,9 @@ protected static function calculateCurrentPage(int $first, int $after, int $defa
/**
* Apply the args to a builder, constructing a paginator.
*
* @template TModel of \Illuminate\Database\Eloquent\Model
*
* @param \Illuminate\Database\Query\Builder|\Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder<TModel>|\Illuminate\Database\Eloquent\Relations\Relation<TModel> $builder
*
* @return \Illuminate\Contracts\Pagination\Paginator<TModel>
* @return \Illuminate\Contracts\Pagination\Paginator<\Illuminate\Database\Eloquent\Model>
*/
public function applyToBuilder(QueryBuilder|ScoutBuilder|EloquentBuilder|Relation $builder): Paginator
public function applyToBuilder(Builder|ScoutBuilder $builder): Paginator
{
$methodName = $this->type->isSimple()
? 'simplePaginate'
Expand Down
8 changes: 4 additions & 4 deletions src/Schema/Directives/AggregateDirective.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
use GraphQL\Language\AST\FieldDefinitionNode;
use GraphQL\Language\AST\InterfaceTypeDefinitionNode;
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Contracts\Database\Query\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Nuwave\Lighthouse\Exceptions\DefinitionException;
use Nuwave\Lighthouse\Execution\BatchLoader\BatchLoaderRegistry;
use Nuwave\Lighthouse\Execution\BatchLoader\RelationBatchLoader;
use Nuwave\Lighthouse\Execution\ModelsLoader\AggregateModelsLoader;
use Nuwave\Lighthouse\Execution\ResolveInfo;
use Nuwave\Lighthouse\Schema\AST\DocumentAST;
use Nuwave\Lighthouse\Schema\Directives\Traits\RelationDirectiveHelpers;
use Nuwave\Lighthouse\Schema\Values\FieldValue;
use Nuwave\Lighthouse\Support\Contracts\FieldManipulator;
use Nuwave\Lighthouse\Support\Contracts\FieldResolver;
Expand Down Expand Up @@ -144,8 +144,8 @@ public function resolveField(FieldValue $fieldValue): callable
$builder = $builderResolver($root, $args, $context, $resolveInfo);

assert(
$builder instanceof QueryBuilder || $builder instanceof EloquentBuilder,
"The method referenced by the builder argument of the @{$this->name()} directive on {$this->nodeName()} must return a Builder.",
$builder instanceof Builder,
"The method referenced by the builder argument of the @{$this->name()} directive on {$this->nodeName()} must return a Builder or Relation.",
);

$this->makeBuilderDecorator($root, $args, $context, $resolveInfo)($builder);
Expand Down
Loading