mirror of
https://github.com/AnimeThemes/animethemes-server.git
synced 2026-07-11 17:44:51 +02:00
168 lines
5.3 KiB
PHP
168 lines
5.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\GraphQL\Directives;
|
|
|
|
use GraphQL\Deferred;
|
|
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
|
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\Directives\AggregateDirective;
|
|
use Nuwave\Lighthouse\Schema\Values\FieldValue;
|
|
use Nuwave\Lighthouse\Support\Contracts\FieldManipulator;
|
|
use Nuwave\Lighthouse\Support\Contracts\FieldResolver;
|
|
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
|
|
|
|
class AggregateCustomDirective extends AggregateDirective implements FieldManipulator, FieldResolver
|
|
{
|
|
public static function definition(): string
|
|
{
|
|
return /** @lang GraphQL */ <<<'GRAPHQL'
|
|
"""
|
|
Returns an aggregate of a column in a given relationship or model.
|
|
"""
|
|
directive @aggregateCustom(
|
|
"""
|
|
The column to aggregate.
|
|
"""
|
|
column: String!
|
|
|
|
"""
|
|
The aggregate function to compute.
|
|
"""
|
|
function: AggregateFunction!
|
|
|
|
"""
|
|
The relationship with the column to aggregate.
|
|
Mutually exclusive with `model` and `builder`.
|
|
"""
|
|
relation: String
|
|
|
|
"""
|
|
The model with the column to aggregate.
|
|
Mutually exclusive with `relation` and `builder`.
|
|
"""
|
|
model: String
|
|
|
|
"""
|
|
Point to a function that provides a Query Builder instance.
|
|
Consists of two parts: a class name and a method name, seperated by an `@` symbol.
|
|
If you pass only a class name, the method name defaults to `__invoke`.
|
|
Mutually exclusive with `relation` and `model`.
|
|
"""
|
|
builder: String
|
|
|
|
"""
|
|
Apply scopes to the underlying query.
|
|
"""
|
|
scopes: [String!]
|
|
) on FIELD_DEFINITION
|
|
|
|
"""
|
|
Options for the `function` argument of `@aggregate`.
|
|
"""
|
|
enum AggregateFunction {
|
|
"""
|
|
Return the average value.
|
|
"""
|
|
AVG
|
|
|
|
"""
|
|
Return the sum.
|
|
"""
|
|
SUM
|
|
|
|
"""
|
|
Return the minimum.
|
|
"""
|
|
MIN
|
|
|
|
"""
|
|
Return the maximum.
|
|
"""
|
|
MAX
|
|
|
|
"""
|
|
Return the boolean value of the relation existence.
|
|
"""
|
|
EXISTS
|
|
}
|
|
GRAPHQL;
|
|
}
|
|
|
|
public function resolveField(FieldValue $fieldValue): callable
|
|
{
|
|
$modelArg = $this->directiveArgValue('model');
|
|
if (is_string($modelArg)) {
|
|
return function (mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo) use ($modelArg) {
|
|
$builder = $this->namespaceModelClass($modelArg)::query();
|
|
|
|
$this->makeBuilderDecorator($root, $args, $context, $resolveInfo)($builder);
|
|
|
|
return $builder->{$this->function()}($this->column());
|
|
};
|
|
}
|
|
|
|
$relation = $this->directiveArgValue('relation');
|
|
if (is_string($relation)) {
|
|
return function (Model $parent, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): Deferred {
|
|
$relationBatchLoader = BatchLoaderRegistry::instance(
|
|
[...$this->qualifyPath($args, $resolveInfo), $this->function(), $this->column()],
|
|
fn (): RelationBatchLoader => new RelationBatchLoader(
|
|
new AggregateModelsLoader(
|
|
$this->relation(),
|
|
$this->column(),
|
|
$this->function(),
|
|
$this->makeBuilderDecorator($parent, $args, $context, $resolveInfo),
|
|
),
|
|
),
|
|
);
|
|
|
|
$deferred = $relationBatchLoader->load($parent);
|
|
|
|
return new Deferred(function () use ($deferred) {
|
|
$result = $deferred->result;
|
|
|
|
return $result ?? 0;
|
|
});
|
|
};
|
|
}
|
|
|
|
$modelArg = $this->directiveArgValue('model');
|
|
if (is_string($modelArg)) {
|
|
return function (mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo) use ($modelArg) {
|
|
$query = $this->namespaceModelClass($modelArg)::query();
|
|
|
|
$this->makeBuilderDecorator($root, $args, $context, $resolveInfo)($query);
|
|
|
|
return $query->{$this->function()}($this->column());
|
|
};
|
|
}
|
|
|
|
if ($this->directiveHasArgument('builder')) {
|
|
$builderResolver = $this->getResolverFromArgument('builder');
|
|
|
|
return function (mixed $root, array $args, GraphQLContext $context, ResolveInfo $resolveInfo) use ($builderResolver) {
|
|
$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.",
|
|
);
|
|
|
|
$this->makeBuilderDecorator($root, $args, $context, $resolveInfo)($builder);
|
|
|
|
return $builder->{$this->function()}($this->column());
|
|
};
|
|
}
|
|
|
|
throw new DefinitionException("One of the arguments `model`, `relation` or `builder` must be assigned to the '{$this->name()}' directive on '{$this->nodeName()}'.");
|
|
}
|
|
}
|