mirror of
https://github.com/AnimeThemes/animethemes-server.git
synced 2026-09-27 14:56:17 +02:00
95 lines
3.2 KiB
PHP
95 lines
3.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\GraphQL\Directives;
|
|
|
|
use App\Enums\GraphQL\SortType;
|
|
use App\Exceptions\GraphQL\ClientValidationException;
|
|
use App\GraphQL\Support\Sort\RandomSort;
|
|
use App\GraphQL\Support\Sort\Sort;
|
|
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 InvalidArgumentException;
|
|
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
|
|
use Nuwave\Lighthouse\Support\Contracts\ArgBuilderDirective;
|
|
|
|
class SortCustomDirective extends BaseDirective implements ArgBuilderDirective
|
|
{
|
|
final public const INPUT_COLUMN = 'column';
|
|
final public const INPUT_VALUE = 'value';
|
|
final public const INPUT_SORT_TYPE = 'sortType';
|
|
final public const INPUT_RELATION = 'relation';
|
|
|
|
public static function definition(): string
|
|
{
|
|
return /** @lang GraphQL */ <<<'GRAPHQL'
|
|
"""
|
|
Sort a result by the given argument.
|
|
"""
|
|
directive @sortCustom(columns: [SortByColumnInput!]) on ARGUMENT_DEFINITION
|
|
|
|
"""
|
|
This input is used to coordinate the code to get the client argument and matches with the column sortable.
|
|
"""
|
|
input SortByColumnInput {
|
|
column: String
|
|
value: String!
|
|
sortType: Int! = 1
|
|
relation: String
|
|
}
|
|
GRAPHQL;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, string> $enumCases
|
|
*
|
|
* @throws ClientValidationException
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function handleBuilder(QueryBuilder|EloquentBuilder|Relation $builder, $enumCases): QueryBuilder|EloquentBuilder|Relation
|
|
{
|
|
$sortByColumnInputArray = json_decode($this->directiveArgValue('columns'), true);
|
|
|
|
foreach ($enumCases as $enumCase) {
|
|
if ($enumCase === RandomSort::CASE) {
|
|
$builder->inRandomOrder();
|
|
continue;
|
|
}
|
|
|
|
$direction = Sort::resolveFromEnumCase($enumCase);
|
|
|
|
$sortByColumnValue = Str::remove('_DESC', $enumCase);
|
|
|
|
$sortByColumnInput = Arr::first($sortByColumnInputArray, fn ($sortByColumn) => $sortByColumn[self::INPUT_VALUE] === $sortByColumnValue);
|
|
|
|
$column = Arr::get($sortByColumnInput, self::INPUT_COLUMN);
|
|
$sortType = SortType::from(Arr::get($sortByColumnInput, self::INPUT_SORT_TYPE));
|
|
|
|
if ($sortType === SortType::ROOT) {
|
|
$builder->orderBy($column, $direction);
|
|
}
|
|
|
|
if ($sortType === SortType::AGGREGATE) {
|
|
$relation = Arr::get($sortByColumnInput, self::INPUT_RELATION);
|
|
if ($relation === null) {
|
|
throw new InvalidArgumentException("The 'relation' argument is required for the @{$this->name()} directive with aggregate sort type.");
|
|
}
|
|
|
|
$builder->withAggregate([
|
|
"$relation as {$relation}_value" => function ($query) use ($direction) {
|
|
$query->orderBy('value', $direction);
|
|
},
|
|
], 'value');
|
|
|
|
$builder->orderBy("{$relation}_value", $direction);
|
|
}
|
|
}
|
|
|
|
return $builder;
|
|
}
|
|
}
|