diff --git a/app/Actions/GraphQL/IndexAction.php b/app/Actions/GraphQL/IndexAction.php index 945ded131..6072b7e30 100644 --- a/app/Actions/GraphQL/IndexAction.php +++ b/app/Actions/GraphQL/IndexAction.php @@ -8,10 +8,9 @@ use App\Concerns\Actions\GraphQL\ConstrainsEagerLoads; use App\Concerns\Actions\GraphQL\FieldSelection; use App\Concerns\Actions\GraphQL\PaginatesModels; use App\Concerns\Actions\GraphQL\SortsModels; +use App\Contracts\GraphQL\EnumSort; use App\GraphQL\Argument\SortArgument; use App\GraphQL\Criteria\Sort\RelationSortCriteria; -use App\GraphQL\Criteria\Sort\SortCriteria; -use App\GraphQL\Schema\Enums\SortableColumns; use App\GraphQL\Schema\Types\BaseType; use App\Rules\GraphQL\Argument\FirstArgumentRule; use App\Scout\Criteria; @@ -21,6 +20,7 @@ use Illuminate\Contracts\Pagination\Paginator; use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Validator; +use UnitEnum; class IndexAction { @@ -35,7 +35,7 @@ class IndexAction $this->filter($builder, $args, $type); - $this->sort($builder, $args, $type); + $this->sort($builder, $args); $this->constrainEagerLoads($builder, $resolveInfo, $type); @@ -53,7 +53,7 @@ class IndexAction $this->filter($builder, $args, $type); - $this->sort($builder, $args, $type); + $this->sort($builder, $args); $this->constrainEagerLoads($builder, $resolveInfo, $type); }; @@ -66,15 +66,14 @@ class IndexAction 'first' => ['required', 'integer', 'min:1', new FirstArgumentRule()], ])->validate(); + /** @var array $sorts */ $sorts = Arr::get($args, SortArgument::ARGUMENT, []); - $criteria = Arr::get(new SortableColumns($type)->getAttributes(), 'criteria'); $sortsRaw = []; foreach ($sorts as $sort) { - /** @var SortCriteria $criterion */ - $criterion = Arr::get($criteria, $sort); + $criterion = $sort->getSortCriteria(); - $column = $criterion->getSort()->getColumn(); + $column = $criterion->getColumn(); $direction = $criterion->getDirection(); $isString = $criterion->isStringField(); diff --git a/app/Concerns/Actions/GraphQL/ConstrainsEagerLoads.php b/app/Concerns/Actions/GraphQL/ConstrainsEagerLoads.php index fa0018b54..c2a2ef409 100644 --- a/app/Concerns/Actions/GraphQL/ConstrainsEagerLoads.php +++ b/app/Concerns/Actions/GraphQL/ConstrainsEagerLoads.php @@ -119,7 +119,7 @@ trait ConstrainsEagerLoads $this->filter($builder, $args, $type); - $this->sort($builder, $args, $type, $relation, $graphqlRelation); + $this->sort($builder, $args); $fields = Arr::get($selection, 'selectionSet.data.data.selectionSet') ?? Arr::get($selection, 'selectionSet.edges.edges.selectionSet.node.node.selectionSet') diff --git a/app/Concerns/Actions/GraphQL/SortsModels.php b/app/Concerns/Actions/GraphQL/SortsModels.php index 36d8fced1..a766b175c 100644 --- a/app/Concerns/Actions/GraphQL/SortsModels.php +++ b/app/Concerns/Actions/GraphQL/SortsModels.php @@ -4,38 +4,20 @@ declare(strict_types=1); namespace App\Concerns\Actions\GraphQL; +use App\Contracts\GraphQL\EnumSort; use App\GraphQL\Argument\SortArgument; -use App\GraphQL\Criteria\Sort\SortCriteria; -use App\GraphQL\Schema\Enums\SortableColumns; -use App\GraphQL\Schema\Fields\Relations\Relation as GraphQLRelation; -use App\GraphQL\Schema\Types\BaseType; -use App\GraphQL\Schema\Unions\BaseUnion; use Illuminate\Database\Eloquent\Builder; -use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Support\Arr; trait SortsModels { - public function sort(Builder $builder, array $args, BaseType|BaseUnion $type, ?Relation $relation = null, ?GraphQLRelation $graphqlRelation = null): Builder + public function sort(Builder $builder, array $args): Builder { - $sorts = Arr::get($args, SortArgument::ARGUMENT); - - if (blank($sorts)) { - return $builder; - } - - $relation = $relation instanceof BelongsToMany - ? $relation - : null; - - $criteria = Arr::get(new SortableColumns($type, $graphqlRelation?->getPivotType(), $relation)->getAttributes(), 'criteria'); + /** @var EnumSort[] $sorts */ + $sorts = Arr::get($args, SortArgument::ARGUMENT, []); foreach ($sorts as $sort) { - /** @var SortCriteria $criterion */ - $criterion = Arr::get($criteria, $sort); - - $criterion->sort($builder); + $sort->getSortCriteria()->sort($builder); } return $builder; diff --git a/app/Contracts/GraphQL/EnumSort.php b/app/Contracts/GraphQL/EnumSort.php new file mode 100644 index 000000000..51928065f --- /dev/null +++ b/app/Contracts/GraphQL/EnumSort.php @@ -0,0 +1,14 @@ + new FieldSortCriteria($this, Announcement::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, Announcement::ATTRIBUTE_ID, SortDirection::DESC), + self::CREATED_AT => new FieldSortCriteria($this, Announcement::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, Announcement::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, Announcement::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, Announcement::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return true; + } +} diff --git a/app/Enums/GraphQL/Sort/Admin/DumpSort.php b/app/Enums/GraphQL/Sort/Admin/DumpSort.php new file mode 100644 index 000000000..21e9eb0ae --- /dev/null +++ b/app/Enums/GraphQL/Sort/Admin/DumpSort.php @@ -0,0 +1,41 @@ + new FieldSortCriteria($this, Dump::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, Dump::ATTRIBUTE_ID, SortDirection::DESC), + self::CREATED_AT => new FieldSortCriteria($this, Dump::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, Dump::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, Dump::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, Dump::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return true; + } +} diff --git a/app/Enums/GraphQL/Sort/Document/PageSort.php b/app/Enums/GraphQL/Sort/Document/PageSort.php new file mode 100644 index 000000000..0c4f08621 --- /dev/null +++ b/app/Enums/GraphQL/Sort/Document/PageSort.php @@ -0,0 +1,49 @@ + new FieldSortCriteria($this, Page::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, Page::ATTRIBUTE_ID, SortDirection::DESC), + self::NAME => new FieldSortCriteria($this, Page::ATTRIBUTE_NAME, isStringField: true), + self::NAME_DESC => new FieldSortCriteria($this, Page::ATTRIBUTE_NAME, SortDirection::DESC, isStringField: true), + self::SLUG => new FieldSortCriteria($this, Page::ATTRIBUTE_SLUG, isStringField: true), + self::SLUG_DESC => new FieldSortCriteria($this, Page::ATTRIBUTE_SLUG, SortDirection::DESC, isStringField: true), + self::CREATED_AT => new FieldSortCriteria($this, Page::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, Page::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, Page::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, Page::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return true; + } +} diff --git a/app/Enums/GraphQL/Sort/List/Playlist/PlaylistTrackSort.php b/app/Enums/GraphQL/Sort/List/Playlist/PlaylistTrackSort.php new file mode 100644 index 000000000..c35623263 --- /dev/null +++ b/app/Enums/GraphQL/Sort/List/Playlist/PlaylistTrackSort.php @@ -0,0 +1,45 @@ + new FieldSortCriteria($this, PlaylistTrack::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, PlaylistTrack::ATTRIBUTE_ID, SortDirection::DESC), + self::POSITION => new FieldSortCriteria($this, PlaylistTrack::ATTRIBUTE_POSITION), + self::POSITION_DESC => new FieldSortCriteria($this, PlaylistTrack::ATTRIBUTE_POSITION, SortDirection::DESC), + self::CREATED_AT => new FieldSortCriteria($this, PlaylistTrack::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, PlaylistTrack::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, PlaylistTrack::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, PlaylistTrack::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return true; + } +} diff --git a/app/Enums/GraphQL/Sort/List/PlaylistSort.php b/app/Enums/GraphQL/Sort/List/PlaylistSort.php new file mode 100644 index 000000000..80d4efb91 --- /dev/null +++ b/app/Enums/GraphQL/Sort/List/PlaylistSort.php @@ -0,0 +1,59 @@ + new FieldSortCriteria($this, Playlist::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, Playlist::ATTRIBUTE_ID, SortDirection::DESC), + self::NAME => new FieldSortCriteria($this, Playlist::ATTRIBUTE_NAME, isStringField: true), + self::NAME_DESC => new FieldSortCriteria($this, Playlist::ATTRIBUTE_NAME, SortDirection::DESC, isStringField: true), + self::LIKES_COUNT => new FieldSortCriteria($this, 'like_aggregate_sum_value'), + self::LIKES_COUNT_DESC => new FieldSortCriteria($this, 'like_aggregate_sum_value', SortDirection::DESC), + self::TRACKS_COUNT => new FieldSortCriteria($this, 'tracksCount'), + self::TRACKS_COUNT_DESC => new FieldSortCriteria($this, 'tracksCount', SortDirection::DESC), + self::CREATED_AT => new FieldSortCriteria($this, Playlist::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, Playlist::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, Playlist::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, Playlist::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return match ($this) { + self::LIKES_COUNT, + self::LIKES_COUNT_DESC, + self::TRACKS_COUNT, + self::TRACKS_COUNT_DESC => false, + default => true, + }; + } +} diff --git a/app/Enums/GraphQL/Sort/Pivot/ArtistMemberSort.php b/app/Enums/GraphQL/Sort/Pivot/ArtistMemberSort.php new file mode 100644 index 000000000..a696fb395 --- /dev/null +++ b/app/Enums/GraphQL/Sort/Pivot/ArtistMemberSort.php @@ -0,0 +1,59 @@ + new FieldSortCriteria($this, Artist::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, Artist::ATTRIBUTE_ID, SortDirection::DESC), + self::NAME => new FieldSortCriteria($this, Artist::ATTRIBUTE_NAME, isStringField: true), + self::NAME_DESC => new FieldSortCriteria($this, Artist::ATTRIBUTE_NAME, SortDirection::DESC, isStringField: true), + self::MEMBER_ALIAS => new PivotSortCriteria($this, ArtistMember::ATTRIBUTE_ALIAS, isStringField: true), + self::MEMBER_ALIAS_DESC => new PivotSortCriteria($this, ArtistMember::ATTRIBUTE_ALIAS, SortDirection::DESC, isStringField: true), + self::MEMBER_AS => new PivotSortCriteria($this, ArtistMember::ATTRIBUTE_AS, isStringField: true), + self::MEMBER_AS_DESC => new PivotSortCriteria($this, ArtistMember::ATTRIBUTE_AS, SortDirection::DESC, isStringField: true), + self::MEMBER_RELEVANCE => new PivotSortCriteria($this, ArtistMember::ATTRIBUTE_RELEVANCE), + self::MEMBER_RELEVANCE_DESC => new PivotSortCriteria($this, ArtistMember::ATTRIBUTE_RELEVANCE, SortDirection::DESC), + self::CREATED_AT => new FieldSortCriteria($this, Artist::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, Artist::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, Artist::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, Artist::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return true; + } +} diff --git a/app/Enums/GraphQL/Sort/Pivot/ImageableSort.php b/app/Enums/GraphQL/Sort/Pivot/ImageableSort.php new file mode 100644 index 000000000..ddc7ab3f9 --- /dev/null +++ b/app/Enums/GraphQL/Sort/Pivot/ImageableSort.php @@ -0,0 +1,47 @@ + new FieldSortCriteria($this, Image::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, Image::ATTRIBUTE_ID, SortDirection::DESC), + self::DEPTH => new PivotSortCriteria($this, Imageable::ATTRIBUTE_DEPTH), + self::DEPTH_DESC => new PivotSortCriteria($this, Imageable::ATTRIBUTE_DEPTH, SortDirection::DESC), + self::CREATED_AT => new FieldSortCriteria($this, Image::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, Image::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, Image::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, Image::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return true; + } +} diff --git a/app/Enums/GraphQL/Sort/Wiki/Anime/AnimeTheme/AnimeThemeEntrySort.php b/app/Enums/GraphQL/Sort/Wiki/Anime/AnimeTheme/AnimeThemeEntrySort.php new file mode 100644 index 000000000..bbeb9bd40 --- /dev/null +++ b/app/Enums/GraphQL/Sort/Wiki/Anime/AnimeTheme/AnimeThemeEntrySort.php @@ -0,0 +1,63 @@ + new FieldSortCriteria($this, AnimeThemeEntry::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, AnimeThemeEntry::ATTRIBUTE_ID, SortDirection::DESC), + self::EPISODES => new FieldSortCriteria($this, AnimeThemeEntry::ATTRIBUTE_EPISODES), + self::EPISODES_DESC => new FieldSortCriteria($this, AnimeThemeEntry::ATTRIBUTE_EPISODES, SortDirection::DESC), + self::VERSION => new FieldSortCriteria($this, AnimeThemeEntry::ATTRIBUTE_VERSION), + self::VERSION_DESC => new FieldSortCriteria($this, AnimeThemeEntry::ATTRIBUTE_VERSION, SortDirection::DESC), + self::LIKES_COUNT => new FieldSortCriteria($this, 'like_aggregate_sum_value'), + self::LIKES_COUNT_DESC => new FieldSortCriteria($this, 'like_aggregate_sum_value', SortDirection::DESC), + self::TRACKS_COUNT => new FieldSortCriteria($this, 'tracks_count'), + self::TRACKS_COUNT_DESC => new FieldSortCriteria($this, 'tracks_count', SortDirection::DESC), + self::CREATED_AT => new FieldSortCriteria($this, AnimeThemeEntry::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, AnimeThemeEntry::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, AnimeThemeEntry::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, AnimeThemeEntry::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return match ($this) { + self::LIKES_COUNT, + self::LIKES_COUNT_DESC, + self::TRACKS_COUNT, + self::TRACKS_COUNT_DESC => false, + default => true, + }; + } +} diff --git a/app/Enums/GraphQL/Sort/Wiki/Anime/AnimeThemeSort.php b/app/Enums/GraphQL/Sort/Wiki/Anime/AnimeThemeSort.php new file mode 100644 index 000000000..32b14e057 --- /dev/null +++ b/app/Enums/GraphQL/Sort/Wiki/Anime/AnimeThemeSort.php @@ -0,0 +1,55 @@ + new FieldSortCriteria($this, AnimeTheme::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, AnimeTheme::ATTRIBUTE_ID, SortDirection::DESC), + self::SEQUENCE => new FieldSortCriteria($this, AnimeTheme::ATTRIBUTE_SEQUENCE), + self::SEQUENCE_DESC => new FieldSortCriteria($this, AnimeTheme::ATTRIBUTE_SEQUENCE, SortDirection::DESC), + self::CREATED_AT => new FieldSortCriteria($this, AnimeTheme::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, AnimeTheme::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, AnimeTheme::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, AnimeTheme::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::SONG_TITLE => new RelationSortCriteria($this, Song::ATTRIBUTE_TITLE, AnimeTheme::RELATION_SONG, isStringField: true), + self::SONG_TITLE_DESC => new RelationSortCriteria($this, Song::ATTRIBUTE_TITLE, AnimeTheme::RELATION_SONG, SortDirection::DESC, isStringField: true), + self::SONG_TITLE_NATIVE => new RelationSortCriteria($this, Song::ATTRIBUTE_TITLE_NATIVE, AnimeTheme::RELATION_SONG, isStringField: true), + self::SONG_TITLE_NATIVE_DESC => new RelationSortCriteria($this, Song::ATTRIBUTE_TITLE_NATIVE, AnimeTheme::RELATION_SONG, SortDirection::DESC, isStringField: true), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return true; + } +} diff --git a/app/Enums/GraphQL/Sort/Wiki/AnimeSort.php b/app/Enums/GraphQL/Sort/Wiki/AnimeSort.php new file mode 100644 index 000000000..2e7014cab --- /dev/null +++ b/app/Enums/GraphQL/Sort/Wiki/AnimeSort.php @@ -0,0 +1,49 @@ + new FieldSortCriteria($this, Anime::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, Anime::ATTRIBUTE_ID, SortDirection::DESC), + self::NAME => new FieldSortCriteria($this, Anime::ATTRIBUTE_NAME, isStringField: true), + self::NAME_DESC => new FieldSortCriteria($this, Anime::ATTRIBUTE_NAME, SortDirection::DESC, isStringField: true), + self::YEAR => new FieldSortCriteria($this, Anime::ATTRIBUTE_YEAR), + self::YEAR_DESC => new FieldSortCriteria($this, Anime::ATTRIBUTE_YEAR, SortDirection::DESC), + self::CREATED_AT => new FieldSortCriteria($this, Anime::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, Anime::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, Anime::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, Anime::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return true; + } +} diff --git a/app/Enums/GraphQL/Sort/Wiki/ArtistSort.php b/app/Enums/GraphQL/Sort/Wiki/ArtistSort.php new file mode 100644 index 000000000..1de7b4f6e --- /dev/null +++ b/app/Enums/GraphQL/Sort/Wiki/ArtistSort.php @@ -0,0 +1,45 @@ + new FieldSortCriteria($this, Artist::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, Artist::ATTRIBUTE_ID, SortDirection::DESC), + self::NAME => new FieldSortCriteria($this, Artist::ATTRIBUTE_NAME, isStringField: true), + self::NAME_DESC => new FieldSortCriteria($this, Artist::ATTRIBUTE_NAME, SortDirection::DESC, isStringField: true), + self::CREATED_AT => new FieldSortCriteria($this, Artist::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, Artist::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, Artist::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, Artist::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return true; + } +} diff --git a/app/Enums/GraphQL/Sort/Wiki/AudioSort.php b/app/Enums/GraphQL/Sort/Wiki/AudioSort.php new file mode 100644 index 000000000..730b48fbd --- /dev/null +++ b/app/Enums/GraphQL/Sort/Wiki/AudioSort.php @@ -0,0 +1,53 @@ + new FieldSortCriteria($this, Audio::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, Audio::ATTRIBUTE_ID, SortDirection::DESC), + self::BASENAME => new FieldSortCriteria($this, Audio::ATTRIBUTE_BASENAME, isStringField: true), + self::BASENAME_DESC => new FieldSortCriteria($this, Audio::ATTRIBUTE_BASENAME, SortDirection::DESC, isStringField: true), + self::FILENAME => new FieldSortCriteria($this, Audio::ATTRIBUTE_FILENAME, isStringField: true), + self::FILENAME_DESC => new FieldSortCriteria($this, Audio::ATTRIBUTE_FILENAME, SortDirection::DESC, isStringField: true), + self::SIZE => new FieldSortCriteria($this, Audio::ATTRIBUTE_SIZE), + self::SIZE_DESC => new FieldSortCriteria($this, Audio::ATTRIBUTE_SIZE, SortDirection::DESC), + self::CREATED_AT => new FieldSortCriteria($this, Audio::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, Audio::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, Audio::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, Audio::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return true; + } +} diff --git a/app/Enums/GraphQL/Sort/Wiki/ImageSort.php b/app/Enums/GraphQL/Sort/Wiki/ImageSort.php new file mode 100644 index 000000000..bfca7d637 --- /dev/null +++ b/app/Enums/GraphQL/Sort/Wiki/ImageSort.php @@ -0,0 +1,41 @@ + new FieldSortCriteria($this, Image::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, Image::ATTRIBUTE_ID, SortDirection::DESC), + self::CREATED_AT => new FieldSortCriteria($this, Image::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, Image::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, Image::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, Image::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return true; + } +} diff --git a/app/Enums/GraphQL/Sort/Wiki/SeriesSort.php b/app/Enums/GraphQL/Sort/Wiki/SeriesSort.php new file mode 100644 index 000000000..3b3359862 --- /dev/null +++ b/app/Enums/GraphQL/Sort/Wiki/SeriesSort.php @@ -0,0 +1,45 @@ + new FieldSortCriteria($this, Series::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, Series::ATTRIBUTE_ID, SortDirection::DESC), + self::NAME => new FieldSortCriteria($this, Series::ATTRIBUTE_NAME, isStringField: true), + self::NAME_DESC => new FieldSortCriteria($this, Series::ATTRIBUTE_NAME, SortDirection::DESC, isStringField: true), + self::CREATED_AT => new FieldSortCriteria($this, Series::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, Series::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, Series::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, Series::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return true; + } +} diff --git a/app/Enums/GraphQL/Sort/Wiki/Song/PerformanceSort.php b/app/Enums/GraphQL/Sort/Wiki/Song/PerformanceSort.php new file mode 100644 index 000000000..13f9f067c --- /dev/null +++ b/app/Enums/GraphQL/Sort/Wiki/Song/PerformanceSort.php @@ -0,0 +1,61 @@ + new FieldSortCriteria($this, Performance::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, Performance::ATTRIBUTE_ID, SortDirection::DESC), + self::ALIAS => new FieldSortCriteria($this, Performance::ATTRIBUTE_ALIAS, isStringField: true), + self::ALIAS_DESC => new FieldSortCriteria($this, Performance::ATTRIBUTE_ALIAS, SortDirection::DESC, isStringField: true), + self::AS => new FieldSortCriteria($this, Performance::ATTRIBUTE_AS, isStringField: true), + self::AS_DESC => new FieldSortCriteria($this, Performance::ATTRIBUTE_AS, SortDirection::DESC, isStringField: true), + self::MEMBER_ALIAS => new FieldSortCriteria($this, Performance::ATTRIBUTE_MEMBER_ALIAS, isStringField: true), + self::MEMBER_ALIAS_DESC => new FieldSortCriteria($this, Performance::ATTRIBUTE_MEMBER_ALIAS, SortDirection::DESC, isStringField: true), + self::MEMBER_AS => new FieldSortCriteria($this, Performance::ATTRIBUTE_MEMBER_AS, isStringField: true), + self::MEMBER_AS_DESC => new FieldSortCriteria($this, Performance::ATTRIBUTE_MEMBER_AS, SortDirection::DESC, isStringField: true), + self::RELEVANCE => new FieldSortCriteria($this, Performance::ATTRIBUTE_RELEVANCE), + self::RELEVANCE_DESC => new FieldSortCriteria($this, Performance::ATTRIBUTE_RELEVANCE, SortDirection::DESC), + self::CREATED_AT => new FieldSortCriteria($this, Performance::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, Performance::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, Performance::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, Performance::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return true; + } +} diff --git a/app/Enums/GraphQL/Sort/Wiki/SongSort.php b/app/Enums/GraphQL/Sort/Wiki/SongSort.php new file mode 100644 index 000000000..093125a34 --- /dev/null +++ b/app/Enums/GraphQL/Sort/Wiki/SongSort.php @@ -0,0 +1,49 @@ + new FieldSortCriteria($this, Song::ATTRIBUTE_ID, SortDirection::ASC), + self::ID_DESC => new FieldSortCriteria($this, Song::ATTRIBUTE_ID, SortDirection::DESC), + self::TITLE => new FieldSortCriteria($this, Song::ATTRIBUTE_TITLE, isStringField: true), + self::TITLE_DESC => new FieldSortCriteria($this, Song::ATTRIBUTE_TITLE, SortDirection::DESC, isStringField: true), + self::TITLE_NATIVE => new FieldSortCriteria($this, Song::ATTRIBUTE_TITLE_NATIVE, isStringField: true), + self::TITLE_NATIVE_DESC => new FieldSortCriteria($this, Song::ATTRIBUTE_TITLE_NATIVE, SortDirection::DESC, isStringField: true), + self::CREATED_AT => new FieldSortCriteria($this, Song::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, Song::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, Song::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, Song::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return true; + } +} diff --git a/app/Enums/GraphQL/Sort/Wiki/StudioSort.php b/app/Enums/GraphQL/Sort/Wiki/StudioSort.php new file mode 100644 index 000000000..3a530aa00 --- /dev/null +++ b/app/Enums/GraphQL/Sort/Wiki/StudioSort.php @@ -0,0 +1,45 @@ + new FieldSortCriteria($this, Studio::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, Studio::ATTRIBUTE_ID, SortDirection::DESC), + self::NAME => new FieldSortCriteria($this, Studio::ATTRIBUTE_NAME, isStringField: true), + self::NAME_DESC => new FieldSortCriteria($this, Studio::ATTRIBUTE_NAME, SortDirection::DESC, isStringField: true), + self::CREATED_AT => new FieldSortCriteria($this, Studio::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, Studio::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, Studio::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, Studio::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return true; + } +} diff --git a/app/Enums/GraphQL/Sort/Wiki/SynonymSort.php b/app/Enums/GraphQL/Sort/Wiki/SynonymSort.php new file mode 100644 index 000000000..625cad9d8 --- /dev/null +++ b/app/Enums/GraphQL/Sort/Wiki/SynonymSort.php @@ -0,0 +1,45 @@ + new FieldSortCriteria($this, Synonym::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, Synonym::ATTRIBUTE_ID, SortDirection::DESC), + self::TEXT => new FieldSortCriteria($this, Synonym::ATTRIBUTE_TEXT, isStringField: true), + self::TEXT_DESC => new FieldSortCriteria($this, Synonym::ATTRIBUTE_TEXT, SortDirection::DESC, isStringField: true), + self::CREATED_AT => new FieldSortCriteria($this, Synonym::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, Synonym::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, Synonym::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, Synonym::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return true; + } +} diff --git a/app/Enums/GraphQL/Sort/Wiki/VideoSort.php b/app/Enums/GraphQL/Sort/Wiki/VideoSort.php new file mode 100644 index 000000000..961c8e38b --- /dev/null +++ b/app/Enums/GraphQL/Sort/Wiki/VideoSort.php @@ -0,0 +1,57 @@ + new FieldSortCriteria($this, Video::ATTRIBUTE_ID), + self::ID_DESC => new FieldSortCriteria($this, Video::ATTRIBUTE_ID, SortDirection::DESC), + self::BASENAME => new FieldSortCriteria($this, Video::ATTRIBUTE_BASENAME, isStringField: true), + self::BASENAME_DESC => new FieldSortCriteria($this, Video::ATTRIBUTE_BASENAME, SortDirection::DESC, isStringField: true), + self::FILENAME => new FieldSortCriteria($this, Video::ATTRIBUTE_FILENAME, isStringField: true), + self::FILENAME_DESC => new FieldSortCriteria($this, Video::ATTRIBUTE_FILENAME, SortDirection::DESC, isStringField: true), + self::RESOLUTION => new FieldSortCriteria($this, Video::ATTRIBUTE_RESOLUTION), + self::RESOLUTION_DESC => new FieldSortCriteria($this, Video::ATTRIBUTE_RESOLUTION, SortDirection::DESC), + self::SIZE => new FieldSortCriteria($this, Video::ATTRIBUTE_SIZE), + self::SIZE_DESC => new FieldSortCriteria($this, Video::ATTRIBUTE_SIZE, SortDirection::DESC), + self::CREATED_AT => new FieldSortCriteria($this, Video::ATTRIBUTE_CREATED_AT), + self::CREATED_AT_DESC => new FieldSortCriteria($this, Video::ATTRIBUTE_CREATED_AT, SortDirection::DESC), + self::UPDATED_AT => new FieldSortCriteria($this, Video::ATTRIBUTE_UPDATED_AT), + self::UPDATED_AT_DESC => new FieldSortCriteria($this, Video::ATTRIBUTE_UPDATED_AT, SortDirection::DESC), + self::RANDOM => new RandomSortCriteria($this, ''), + }; + } + + public function shouldQualifyColumn(): bool + { + return true; + } +} diff --git a/app/Enums/GraphQL/Sort/SortDirection.php b/app/Enums/GraphQL/SortDirection.php similarity index 76% rename from app/Enums/GraphQL/Sort/SortDirection.php rename to app/Enums/GraphQL/SortDirection.php index 6605a720a..83a508dc1 100644 --- a/app/Enums/GraphQL/Sort/SortDirection.php +++ b/app/Enums/GraphQL/SortDirection.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace App\Enums\GraphQL\Sort; +namespace App\Enums\GraphQL; enum SortDirection: string { diff --git a/app/GraphQL/Argument/SortArgument.php b/app/GraphQL/Argument/SortArgument.php index a1aa4b591..eae2b46f5 100644 --- a/app/GraphQL/Argument/SortArgument.php +++ b/app/GraphQL/Argument/SortArgument.php @@ -4,25 +4,23 @@ declare(strict_types=1); namespace App\GraphQL\Argument; -use App\GraphQL\Schema\Enums\SortableColumns; +use App\Contracts\GraphQL\EnumSort; use App\GraphQL\Schema\Types\BaseType; -use App\GraphQL\Schema\Types\Pivot\PivotType; use GraphQL\Type\Definition\Type; -use Illuminate\Support\Arr; use Rebing\GraphQL\Support\Facades\GraphQL; +use UnitEnum; class SortArgument extends Argument { final public const string ARGUMENT = 'sort'; - public function __construct(protected BaseType $type, ?PivotType $pivotType = null) + /** + * @param class-string $sortEnum + */ + public function __construct(protected BaseType $type, ?string $sortEnum = null) { - $sortableColumns = new SortableColumns($type, $pivotType); + $enum = $sortEnum ?? $type->getEnumSortClass(); - GraphQL::addType($sortableColumns); - - $name = Arr::get($sortableColumns->getAttributes(), 'name'); - - parent::__construct(self::ARGUMENT, Type::listOf(Type::nonNull(GraphQL::type($name)))); + parent::__construct(self::ARGUMENT, Type::listOf(Type::nonNull(GraphQL::type(class_basename($enum))))); } } diff --git a/app/GraphQL/Criteria/Sort/FieldSortCriteria.php b/app/GraphQL/Criteria/Sort/FieldSortCriteria.php index 6445ffeb3..5d85e3335 100644 --- a/app/GraphQL/Criteria/Sort/FieldSortCriteria.php +++ b/app/GraphQL/Criteria/Sort/FieldSortCriteria.php @@ -13,11 +13,9 @@ class FieldSortCriteria extends SortCriteria */ public function sort(Builder $builder): Builder { - $sort = $this->getSort(); - - $column = $sort->shouldQualifyColumn() - ? $builder->qualifyColumn($sort->getColumn()) - : $sort->getColumn(); + $column = $this->sortCase->shouldQualifyColumn() + ? $builder->qualifyColumn($this->column) + : $this->column; return $builder->orderBy($column, $this->direction->value); } diff --git a/app/GraphQL/Criteria/Sort/PivotSortCriteria.php b/app/GraphQL/Criteria/Sort/PivotSortCriteria.php index fe6c1b468..c4ddb585a 100644 --- a/app/GraphQL/Criteria/Sort/PivotSortCriteria.php +++ b/app/GraphQL/Criteria/Sort/PivotSortCriteria.php @@ -4,51 +4,19 @@ declare(strict_types=1); namespace App\GraphQL\Criteria\Sort; -use App\Enums\GraphQL\Sort\SortDirection; -use App\GraphQL\Sort\Sort; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Relations\BelongsToMany; -use Illuminate\Support\Str; class PivotSortCriteria extends SortCriteria { - public function __construct( - protected Sort $sort, - protected SortDirection $direction = SortDirection::ASC, - protected ?BelongsToMany $relation = null, - protected bool $isStringField = false, - ) { - parent::__construct($sort, $direction, $isStringField); - } - - /** - * Build the enum case for a direction. - * Template: PIVOT_{FIELD_NAME}. - * Template: PIVOT_{FIELD_NAME}_DESC. - */ - public function __toString(): string - { - $name = Str::of($this->getSort()->getName()) - ->snake() - ->upper() - ->prepend('PIVOT_'); - - return (string) match ($this->getDirection()) { - SortDirection::ASC => $name, - SortDirection::DESC => $name->append('_DESC'), - }; - } - /** * Apply the ordering to the current Eloquent builder. */ - public function sort(Builder $builder): Builder + public function sort(Builder $builder, ?BelongsToMany $relation = null): Builder { - $sort = $this->getSort(); - - $column = $sort->shouldQualifyColumn() - ? $this->relation?->qualifyPivotColumn($sort->getColumn()) - : $sort->getColumn(); + $column = $this->sortCase->shouldQualifyColumn() + ? $relation?->qualifyPivotColumn($this->column) + : $this->column; return $builder->orderBy($column, $this->getDirection()->value); } diff --git a/app/GraphQL/Criteria/Sort/RandomSortCriteria.php b/app/GraphQL/Criteria/Sort/RandomSortCriteria.php index b5534a14d..a8df68d6d 100644 --- a/app/GraphQL/Criteria/Sort/RandomSortCriteria.php +++ b/app/GraphQL/Criteria/Sort/RandomSortCriteria.php @@ -4,17 +4,10 @@ declare(strict_types=1); namespace App\GraphQL\Criteria\Sort; -use App\GraphQL\Sort\Sort; use Illuminate\Database\Eloquent\Builder; class RandomSortCriteria extends SortCriteria { - public function __construct() - { - // Random Sort doesn't need a field so we fake it. - parent::__construct(new Sort('')); - } - /** * Build the enum case. */ diff --git a/app/GraphQL/Criteria/Sort/RelationSortCriteria.php b/app/GraphQL/Criteria/Sort/RelationSortCriteria.php index 397acf47a..6e32cd5f5 100644 --- a/app/GraphQL/Criteria/Sort/RelationSortCriteria.php +++ b/app/GraphQL/Criteria/Sort/RelationSortCriteria.php @@ -4,54 +4,34 @@ declare(strict_types=1); namespace App\GraphQL\Criteria\Sort; -use App\Enums\GraphQL\Sort\SortDirection; -use App\GraphQL\Sort\Sort; +use App\Contracts\GraphQL\EnumSort; +use App\Enums\GraphQL\SortDirection; use Illuminate\Database\Eloquent\Builder; -use Illuminate\Support\Str; +use UnitEnum; class RelationSortCriteria extends SortCriteria { public function __construct( - protected Sort $sort, + protected UnitEnum&EnumSort $sortCase, + protected string $column, protected string $relation, protected SortDirection $direction = SortDirection::ASC, protected bool $isStringField = false, - ) { - parent::__construct($sort, $direction, $isStringField); - } + ) {} public function getRelation(): string { return $this->relation; } - /** - * Build the enum case for a direction. - * Template: {RELATION}_{FIELD_NAME}. - * Template: {RELATION}_{FIELD_NAME}_DESC. - */ - public function __toString(): string - { - $name = Str::of($this->getRelation()) - ->append('_') - ->append($this->getSort()->getName()) - ->snake() - ->upper(); - - return (string) match ($this->direction) { - SortDirection::ASC => $name, - SortDirection::DESC => $name->append('_DESC'), - }; - } - /** * Apply the ordering to the current Eloquent builder. */ public function sort(Builder $builder): Builder { - $relation = $builder->getRelation($this->getRelation()); + $relation = $builder->getRelation($this->relation); - $orderBySubQuery = $relation->getRelationExistenceQuery($relation->getQuery(), $builder, [$this->getSort()->getColumn()]); + $orderBySubQuery = $relation->getRelationExistenceQuery($relation->getQuery(), $builder, [$this->column]); return $builder->orderBy($orderBySubQuery->toBase(), $this->direction->value); } diff --git a/app/GraphQL/Criteria/Sort/SortCriteria.php b/app/GraphQL/Criteria/Sort/SortCriteria.php index e04afb138..c70308b9d 100644 --- a/app/GraphQL/Criteria/Sort/SortCriteria.php +++ b/app/GraphQL/Criteria/Sort/SortCriteria.php @@ -4,23 +4,24 @@ declare(strict_types=1); namespace App\GraphQL\Criteria\Sort; -use App\Enums\GraphQL\Sort\SortDirection; -use App\GraphQL\Sort\Sort; +use App\Contracts\GraphQL\EnumSort; +use App\Enums\GraphQL\SortDirection; use Illuminate\Database\Eloquent\Builder; -use Illuminate\Support\Str; use Stringable; +use UnitEnum; abstract class SortCriteria implements Stringable { public function __construct( - protected Sort $sort, + protected UnitEnum&EnumSort $sortCase, + protected string $column, protected SortDirection $direction = SortDirection::ASC, protected bool $isStringField = false, ) {} - public function getSort(): Sort + public function getColumn(): string { - return $this->sort; + return $this->column; } public function getDirection(): SortDirection @@ -40,14 +41,7 @@ abstract class SortCriteria implements Stringable */ public function __toString(): string { - $name = Str::of($this->getSort()->getName()) - ->snake() - ->upper(); - - return (string) match ($this->direction) { - SortDirection::ASC => $name, - SortDirection::DESC => $name->append('_DESC'), - }; + return $this->sortCase->name; } /** diff --git a/app/GraphQL/Schema/Enums/SortableColumns.php b/app/GraphQL/Schema/Enums/SortableColumns.php deleted file mode 100644 index d55d43761..000000000 --- a/app/GraphQL/Schema/Enums/SortableColumns.php +++ /dev/null @@ -1,114 +0,0 @@ - - */ - public function attributes(): array - { - $typeName = $this->type->name(); - - $name = $this->pivotType instanceof PivotType - ? $typeName.$this->pivotType->name() - : $typeName; - - return [ - 'name' => $name.self::SUFFIX, - 'values' => $this->getCriteria()->mapWithKeys(fn (SortCriteria $criterion): array => [$criterion->__toString() => $criterion->__toString()])->all(), - 'criteria' => $this->getCriteria()->mapWithKeys(fn (SortCriteria $criterion): array => [$criterion->__toString() => $criterion])->all(), - ]; - } - - /** - * @return Collection - */ - private function getSortableFields(): Collection - { - return collect($this->type->fieldClasses()) - ->filter(fn (Field $field): bool => $field instanceof SortableField); - } - - private function getCriteria(): Collection - { - return $this->getFieldSortCriteria() - ->merge($this->getPivotSortCriteria()) - ->merge($this->getRelationSortCriteria()) - ->push(new RandomSortCriteria()); - } - - private function getFieldSortCriteria(): Collection - { - return $this->getSortableFields() - ->map(fn (Field&SortableField $field): array => [ - new FieldSortCriteria($field->getSort(), SortDirection::ASC, $field instanceof StringField), - new FieldSortCriteria($field->getSort(), SortDirection::DESC, $field instanceof StringField), - ]) - ->flatten(); - } - - private function getPivotSortCriteria(): Collection - { - return collect($this->pivotType?->fieldClasses() ?? []) - ->filter(fn (Field $field): bool => $field instanceof SortableField) - ->map(fn (Field&SortableField $field): array => [ - new PivotSortCriteria($field->getSort(), SortDirection::ASC, $this->relation, $field instanceof StringField), - new PivotSortCriteria($field->getSort(), SortDirection::DESC, $this->relation, $field instanceof StringField), - ]) - ->flatten(); - } - - private function getRelationSortCriteria(): Collection - { - return $this->getRelations($this->type) - ->flatMap(fn (Collection $fields, $relation) => $fields->map(fn (Field&SortableField $field): array => [ - new RelationSortCriteria($field->getSort(), $relation, SortDirection::ASC, $field instanceof StringField), - new RelationSortCriteria($field->getSort(), $relation, SortDirection::DESC, $field instanceof StringField), - ])) - ->flatten(); - } - - private function getRelations(BaseType $type): Collection - { - return collect($type->relations()) - ->filter(fn (Relation $relation): bool => $relation instanceof BelongsToRelation && $relation->baseType() instanceof BaseType) - ->mapWithKeys( - fn (Relation $relation): array => [ - $relation->name() => collect($relation->baseType()->fieldClasses()) - ->filter(fn (Field $field): bool => $field instanceof SortableField), - ], - ); - } -} diff --git a/app/GraphQL/Schema/Fields/Base/Aggregate/AggregateField.php b/app/GraphQL/Schema/Fields/Base/Aggregate/AggregateField.php index 7c28c42eb..198f6707a 100644 --- a/app/GraphQL/Schema/Fields/Base/Aggregate/AggregateField.php +++ b/app/GraphQL/Schema/Fields/Base/Aggregate/AggregateField.php @@ -4,18 +4,14 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Fields\Base\Aggregate; +use App\Contracts\GraphQL\EnumSort; use App\Contracts\GraphQL\Fields\FilterableField; -use App\Contracts\GraphQL\Fields\SortableField; use App\Enums\GraphQL\Field\AggregateFunction; -use App\Enums\GraphQL\QualifyColumn; use App\GraphQL\Criteria\Filter\FilterCriteria; use App\GraphQL\Criteria\Filter\WhereConditionsFilterCriteria; -use App\GraphQL\Criteria\Sort\SortCriteria; use App\GraphQL\Schema\Enums\FilterableColumns; -use App\GraphQL\Schema\Enums\SortableColumns; use App\GraphQL\Schema\Fields\Field; use App\GraphQL\Schema\Types\BaseType; -use App\GraphQL\Sort\Sort; use GraphQL\Type\Definition\ResolveInfo; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; @@ -23,8 +19,9 @@ use Illuminate\Support\Arr; use Illuminate\Support\Collection; use Illuminate\Support\Str; use Illuminate\Support\Stringable; +use UnitEnum; -abstract class AggregateField extends Field implements FilterableField, SortableField +abstract class AggregateField extends Field implements FilterableField { private Collection $filterableFields; @@ -38,11 +35,6 @@ abstract class AggregateField extends Field implements FilterableField, Sortable parent::__construct($this->alias(), $fieldName, $nullable); } - public function getSort(): Sort - { - return new Sort($this->fieldName, $this->alias(), qualifyColumn: QualifyColumn::NO); - } - /** * Eager load the aggregate value for the query builder. */ @@ -54,11 +46,10 @@ abstract class AggregateField extends Field implements FilterableField, Sortable } // If the sorting is requesting an aggregate function. - /** @var SortCriteria[] $sortCriteria */ - $sortCriteria = Arr::get(new SortableColumns($type)->getAttributes(), 'criteria'); + /** @var array $sorts */ $sorts = Arr::get($args, 'sort', []); - foreach ($sortCriteria as $sortCriterion) { - if (in_array($sortCriterion->__toString(), $sorts) && $sortCriterion->getSort()->getName() === $this->name()) { + foreach ($sorts as $sort) { + if ($sort->getSortCriteria()->getColumn() === $this->alias()) { return true; } } diff --git a/app/GraphQL/Schema/Fields/Base/Aggregate/CountAggregateField.php b/app/GraphQL/Schema/Fields/Base/Aggregate/CountAggregateField.php index 309767a15..6c4a8ee38 100644 --- a/app/GraphQL/Schema/Fields/Base/Aggregate/CountAggregateField.php +++ b/app/GraphQL/Schema/Fields/Base/Aggregate/CountAggregateField.php @@ -5,14 +5,13 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Fields\Base\Aggregate; use App\Contracts\GraphQL\Fields\DisplayableField; -use App\Contracts\GraphQL\Fields\SortableField; use App\Enums\GraphQL\Field\AggregateFunction; use App\Enums\GraphQL\Filter\Clause; use App\GraphQL\Filter\IntFilter; use GraphQL\Type\Definition\ResolveInfo; use GraphQL\Type\Definition\Type; -class CountAggregateField extends AggregateField implements DisplayableField, SortableField +class CountAggregateField extends AggregateField implements DisplayableField { public function __construct( public string $aggregateRelation, diff --git a/app/GraphQL/Schema/Fields/Base/Aggregate/CountField.php b/app/GraphQL/Schema/Fields/Base/Aggregate/CountField.php index 8bdf7989e..62b5c1bc6 100644 --- a/app/GraphQL/Schema/Fields/Base/Aggregate/CountField.php +++ b/app/GraphQL/Schema/Fields/Base/Aggregate/CountField.php @@ -6,13 +6,12 @@ namespace App\GraphQL\Schema\Fields\Base\Aggregate; use App\Contracts\GraphQL\Fields\DisplayableField; use App\Contracts\GraphQL\Fields\FilterableField; -use App\Contracts\GraphQL\Fields\SortableField; use App\Enums\GraphQL\Field\AggregateFunction; use App\Enums\GraphQL\Filter\Clause; use App\GraphQL\Filter\IntFilter; use GraphQL\Type\Definition\Type; -class CountField extends AggregateField implements DisplayableField, FilterableField, SortableField +class CountField extends AggregateField implements DisplayableField, FilterableField { public function __construct( protected string $aggregateRelation, diff --git a/app/GraphQL/Schema/Fields/BooleanField.php b/app/GraphQL/Schema/Fields/BooleanField.php index 2ce98b014..0e5c4ad28 100644 --- a/app/GraphQL/Schema/Fields/BooleanField.php +++ b/app/GraphQL/Schema/Fields/BooleanField.php @@ -6,12 +6,10 @@ namespace App\GraphQL\Schema\Fields; use App\Contracts\GraphQL\Fields\DisplayableField; use App\Contracts\GraphQL\Fields\FilterableField; -use App\Contracts\GraphQL\Fields\SortableField; use App\GraphQL\Filter\BooleanFilter; -use App\GraphQL\Sort\Sort; use GraphQL\Type\Definition\Type; -abstract class BooleanField extends Field implements DisplayableField, FilterableField, SortableField +abstract class BooleanField extends Field implements DisplayableField, FilterableField { public function baseType(): Type { @@ -28,9 +26,4 @@ abstract class BooleanField extends Field implements DisplayableField, Filterabl return new BooleanFilter($this->name(), $this->getColumn()) ->useEq(); } - - public function getSort(): Sort - { - return new Sort($this->name(), $this->getColumn()); - } } diff --git a/app/GraphQL/Schema/Fields/EnumField.php b/app/GraphQL/Schema/Fields/EnumField.php index 1516a1a57..746bd77ad 100644 --- a/app/GraphQL/Schema/Fields/EnumField.php +++ b/app/GraphQL/Schema/Fields/EnumField.php @@ -6,16 +6,14 @@ namespace App\GraphQL\Schema\Fields; use App\Contracts\GraphQL\Fields\DisplayableField; use App\Contracts\GraphQL\Fields\FilterableField; -use App\Contracts\GraphQL\Fields\SortableField; use App\GraphQL\Filter\EnumFilter; -use App\GraphQL\Sort\Sort; use GraphQL\Type\Definition\ResolveInfo; use GraphQL\Type\Definition\Type; use Illuminate\Support\Arr; use Rebing\GraphQL\Support\Facades\GraphQL; use UnitEnum; -abstract class EnumField extends Field implements DisplayableField, FilterableField, SortableField +abstract class EnumField extends Field implements DisplayableField, FilterableField { /** * @param class-string $enum @@ -51,9 +49,4 @@ abstract class EnumField extends Field implements DisplayableField, FilterableFi ->useIn() ->useNotIn(); } - - public function getSort(): Sort - { - return new Sort($this->name(), $this->getColumn()); - } } diff --git a/app/GraphQL/Schema/Fields/FloatField.php b/app/GraphQL/Schema/Fields/FloatField.php index af113efcb..487f3c7ce 100644 --- a/app/GraphQL/Schema/Fields/FloatField.php +++ b/app/GraphQL/Schema/Fields/FloatField.php @@ -6,12 +6,10 @@ namespace App\GraphQL\Schema\Fields; use App\Contracts\GraphQL\Fields\DisplayableField; use App\Contracts\GraphQL\Fields\FilterableField; -use App\Contracts\GraphQL\Fields\SortableField; use App\GraphQL\Filter\FloatFilter; -use App\GraphQL\Sort\Sort; use GraphQL\Type\Definition\Type; -abstract class FloatField extends Field implements DisplayableField, FilterableField, SortableField +abstract class FloatField extends Field implements DisplayableField, FilterableField { public function baseType(): Type { @@ -30,9 +28,4 @@ abstract class FloatField extends Field implements DisplayableField, FilterableF ->useLt() ->useGt(); } - - public function getSort(): Sort - { - return new Sort($this->name(), $this->getColumn()); - } } diff --git a/app/GraphQL/Schema/Fields/IntField.php b/app/GraphQL/Schema/Fields/IntField.php index 067834deb..13fd1d301 100644 --- a/app/GraphQL/Schema/Fields/IntField.php +++ b/app/GraphQL/Schema/Fields/IntField.php @@ -6,12 +6,10 @@ namespace App\GraphQL\Schema\Fields; use App\Contracts\GraphQL\Fields\DisplayableField; use App\Contracts\GraphQL\Fields\FilterableField; -use App\Contracts\GraphQL\Fields\SortableField; use App\GraphQL\Filter\IntFilter; -use App\GraphQL\Sort\Sort; use GraphQL\Type\Definition\Type; -abstract class IntField extends Field implements DisplayableField, FilterableField, SortableField +abstract class IntField extends Field implements DisplayableField, FilterableField { public function baseType(): Type { @@ -32,9 +30,4 @@ abstract class IntField extends Field implements DisplayableField, FilterableFie ->useIn() ->useNotIn(); } - - public function getSort(): Sort - { - return new Sort($this->name(), $this->getColumn()); - } } diff --git a/app/GraphQL/Schema/Fields/Relations/BelongsToManyRelation.php b/app/GraphQL/Schema/Fields/Relations/BelongsToManyRelation.php index 09bb78b17..5c76311ad 100644 --- a/app/GraphQL/Schema/Fields/Relations/BelongsToManyRelation.php +++ b/app/GraphQL/Schema/Fields/Relations/BelongsToManyRelation.php @@ -46,7 +46,11 @@ class BelongsToManyRelation extends Relation return [ ...parent::arguments(), - new SortArgument($this->baseType(), $pivotType), + ...( + $this->baseType()->getEnumSortClass() !== null || $this->sortEnum + ? [new SortArgument($this->baseType(), $this->sortEnum)] + : [] + ), ]; } diff --git a/app/GraphQL/Schema/Fields/Relations/Relation.php b/app/GraphQL/Schema/Fields/Relations/Relation.php index e5a61f2ed..d749946c8 100644 --- a/app/GraphQL/Schema/Fields/Relations/Relation.php +++ b/app/GraphQL/Schema/Fields/Relations/Relation.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Fields\Relations; use App\Concerns\Actions\GraphQL\FiltersModels; +use App\Contracts\GraphQL\EnumSort; use App\Enums\GraphQL\PaginationType; use App\GraphQL\Argument\Argument; use App\GraphQL\Argument\FirstArgument; @@ -21,6 +22,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\Arr; use Illuminate\Support\Collection; +use UnitEnum; abstract class Relation extends Field { @@ -28,6 +30,9 @@ abstract class Relation extends Field protected bool $asPivot = false; + /** @var class-string|null */ + protected ?string $sortEnum = null; + public function __construct( protected BaseType|BaseUnion $relatedType, protected string $relationName, @@ -65,6 +70,16 @@ abstract class Relation extends Field return $this; } + /** + * @param class-string $enum + */ + public function setSortEnum(string $enum): static + { + $this->sortEnum = $enum; + + return $this; + } + /** * Get the relation name in the model. */ @@ -99,7 +114,7 @@ abstract class Relation extends Field $arguments[] = new FirstArgument(true); $arguments[] = new PageArgument(); - if ($type instanceof BaseType && $type->hasSortableColumns()) { + if ($type instanceof BaseType && $type->getEnumSortClass() !== null) { $arguments[] = new SortArgument($type); } } diff --git a/app/GraphQL/Schema/Fields/StringField.php b/app/GraphQL/Schema/Fields/StringField.php index 6880a9749..285706b64 100644 --- a/app/GraphQL/Schema/Fields/StringField.php +++ b/app/GraphQL/Schema/Fields/StringField.php @@ -6,13 +6,11 @@ namespace App\GraphQL\Schema\Fields; use App\Contracts\GraphQL\Fields\DisplayableField; use App\Contracts\GraphQL\Fields\FilterableField; -use App\Contracts\GraphQL\Fields\SortableField; use App\GraphQL\Filter\Filter; use App\GraphQL\Filter\StringFilter; -use App\GraphQL\Sort\Sort; use GraphQL\Type\Definition\Type; -abstract class StringField extends Field implements DisplayableField, FilterableField, SortableField +abstract class StringField extends Field implements DisplayableField, FilterableField { public function baseType(): Type { @@ -30,9 +28,4 @@ abstract class StringField extends Field implements DisplayableField, Filterable ->useEq() ->useLike(); } - - public function getSort(): Sort - { - return new Sort($this->name(), $this->getColumn()); - } } diff --git a/app/GraphQL/Schema/Queries/BaseQuery.php b/app/GraphQL/Schema/Queries/BaseQuery.php index e996cf502..610564f81 100644 --- a/app/GraphQL/Schema/Queries/BaseQuery.php +++ b/app/GraphQL/Schema/Queries/BaseQuery.php @@ -69,7 +69,7 @@ abstract class BaseQuery extends Query $arguments[] = FilterCriteria::getFilters($baseType)->map(fn (Filter $filter): array => $filter->getArguments())->flatten(); } - if ($baseType->hasSortableColumns()) { + if ($baseType->getEnumSortClass() !== null) { $arguments[] = new SortArgument($baseType); } diff --git a/app/GraphQL/Schema/Types/Admin/AnnouncementType.php b/app/GraphQL/Schema/Types/Admin/AnnouncementType.php index a0387d004..d34ce716d 100644 --- a/app/GraphQL/Schema/Types/Admin/AnnouncementType.php +++ b/app/GraphQL/Schema/Types/Admin/AnnouncementType.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types\Admin; +use App\Enums\GraphQL\Sort\Admin\AnnouncementSort; use App\GraphQL\Schema\Fields\Admin\Announcement\AnnouncementContentField; use App\GraphQL\Schema\Fields\Base\CreatedAtField; use App\GraphQL\Schema\Fields\Base\IdField; @@ -19,6 +20,14 @@ class AnnouncementType extends EloquentType return 'Represents a site-wide message to be broadcasted on the homepage.'; } + /** + * @return class-string + */ + public function getEnumSortClass(): string + { + return AnnouncementSort::class; + } + /** * The fields of the type. * diff --git a/app/GraphQL/Schema/Types/Admin/DumpType.php b/app/GraphQL/Schema/Types/Admin/DumpType.php index 92fc6757f..7e3bad928 100644 --- a/app/GraphQL/Schema/Types/Admin/DumpType.php +++ b/app/GraphQL/Schema/Types/Admin/DumpType.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types\Admin; +use App\Enums\GraphQL\Sort\Admin\DumpSort; use App\GraphQL\Schema\Fields\Admin\Dump\DumpLinkField; use App\GraphQL\Schema\Fields\Admin\Dump\DumpPathField; use App\GraphQL\Schema\Fields\Base\CreatedAtField; @@ -20,6 +21,14 @@ class DumpType extends EloquentType return "Represents a database dump of selected tables at a given point in time.\n\nFor example, the animethemes-db-dump-wiki-1663559663946.sql dump represents the database dump of wiki tables performed at 2022-09-19."; } + /** + * @return class-string + */ + public function getEnumSortClass(): string + { + return DumpSort::class; + } + /** * The fields of the type. * diff --git a/app/GraphQL/Schema/Types/BaseType.php b/app/GraphQL/Schema/Types/BaseType.php index f95d033f0..01652bf08 100644 --- a/app/GraphQL/Schema/Types/BaseType.php +++ b/app/GraphQL/Schema/Types/BaseType.php @@ -4,14 +4,15 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types; +use App\Contracts\GraphQL\EnumSort; use App\Contracts\GraphQL\Fields\DeprecatedField; use App\Contracts\GraphQL\Fields\DisplayableField; use App\Contracts\GraphQL\Fields\FilterableField; -use App\Contracts\GraphQL\Fields\SortableField; use App\GraphQL\Schema\Fields\Field; use App\GraphQL\Schema\Fields\Relations\Relation; use Illuminate\Support\Str; use Rebing\GraphQL\Support\Type as RebingType; +use UnitEnum; abstract class BaseType extends RebingType { @@ -100,9 +101,12 @@ abstract class BaseType extends RebingType return $fields->merge($relations)->all(); } - public function hasSortableColumns(): bool + /** + * @return class-string|null + */ + public function getEnumSortClass(): ?string { - return array_any($this->fieldClasses(), fn (Field $field): bool => $field instanceof SortableField); + return null; } public function hasFilterableColumns(): bool diff --git a/app/GraphQL/Schema/Types/Document/PageType.php b/app/GraphQL/Schema/Types/Document/PageType.php index 833d67ae0..7378dfc6b 100644 --- a/app/GraphQL/Schema/Types/Document/PageType.php +++ b/app/GraphQL/Schema/Types/Document/PageType.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types\Document; +use App\Enums\GraphQL\Sort\Document\PageSort; use App\GraphQL\Schema\Fields\Base\CreatedAtField; use App\GraphQL\Schema\Fields\Base\DeletedAtField; use App\GraphQL\Schema\Fields\Base\IdUnbindableField; @@ -23,6 +24,14 @@ class PageType extends EloquentType return "Represents a static markdown page used for guides and other documentation.\n\nFor example, the 'encoding/audio_normalization' page represents the documentation for audio normalization."; } + /** + * @return class-string + */ + public function getEnumSortClass(): string + { + return PageSort::class; + } + /** * The fields of the type. * diff --git a/app/GraphQL/Schema/Types/List/Playlist/PlaylistTrackType.php b/app/GraphQL/Schema/Types/List/Playlist/PlaylistTrackType.php index 73d137c88..a0995be1d 100644 --- a/app/GraphQL/Schema/Types/List/Playlist/PlaylistTrackType.php +++ b/app/GraphQL/Schema/Types/List/Playlist/PlaylistTrackType.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types\List\Playlist; +use App\Enums\GraphQL\Sort\List\Playlist\PlaylistTrackSort; use App\GraphQL\Schema\Fields\Base\CreatedAtField; use App\GraphQL\Schema\Fields\Base\UpdatedAtField; use App\GraphQL\Schema\Fields\Field; @@ -28,6 +29,14 @@ class PlaylistTrackType extends EloquentType return "Represents an entry in a playlist.\n\nFor example, a \"/r/anime's Best OPs and EDs of 2022\" playlist may contain a track for the ParipiKoumei-OP1.webm video."; } + /** + * @return class-string + */ + public function getEnumSortClass(): string + { + return PlaylistTrackSort::class; + } + /** * The fields of the type. * diff --git a/app/GraphQL/Schema/Types/List/PlaylistType.php b/app/GraphQL/Schema/Types/List/PlaylistType.php index e0a61847d..dd6347ada 100644 --- a/app/GraphQL/Schema/Types/List/PlaylistType.php +++ b/app/GraphQL/Schema/Types/List/PlaylistType.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types\List; +use App\Enums\GraphQL\Sort\List\PlaylistSort; +use App\Enums\GraphQL\Sort\Pivot\ImageableSort; use App\GraphQL\Schema\Fields\Base\Aggregate\LikesCountField; use App\GraphQL\Schema\Fields\Base\CreatedAtField; use App\GraphQL\Schema\Fields\Base\UpdatedAtField; @@ -32,6 +34,14 @@ class PlaylistType extends EloquentType return "Represents a list of ordered tracks intended for continuous playback.\n\nFor example, a \"/r/anime's Best OPs and EDs of 2022\" playlist may contain a collection of tracks allowing the continuous playback of Best OP and ED nominations for the /r/anime Awards."; } + /** + * @return class-string + */ + public function getEnumSortClass(): string + { + return PlaylistSort::class; + } + /** * The fields of the type. * @@ -56,7 +66,8 @@ class PlaylistType extends EloquentType new BelongsToRelation(new UserType(), Playlist::RELATION_USER) ->nonNullable(), new HasManyRelation(new PlaylistTrackType(), Playlist::RELATION_TRACKS), - new MorphToManyRelation($this, new ImageType(), Playlist::RELATION_IMAGES, new ImageableType()), + new MorphToManyRelation($this, new ImageType(), Playlist::RELATION_IMAGES, new ImageableType()) + ->setSortEnum(ImageableSort::class), ]; } } diff --git a/app/GraphQL/Schema/Types/Wiki/Anime/AnimeThemeType.php b/app/GraphQL/Schema/Types/Wiki/Anime/AnimeThemeType.php index 13076fc07..f233979f5 100644 --- a/app/GraphQL/Schema/Types/Wiki/Anime/AnimeThemeType.php +++ b/app/GraphQL/Schema/Types/Wiki/Anime/AnimeThemeType.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types\Wiki\Anime; +use App\Enums\GraphQL\Sort\Wiki\Anime\AnimeThemeSort; use App\GraphQL\Schema\Fields\Base\CreatedAtField; use App\GraphQL\Schema\Fields\Base\DeletedAtField; use App\GraphQL\Schema\Fields\Base\IdField; @@ -30,6 +31,14 @@ class AnimeThemeType extends EloquentType return "Represents an OP or ED sequence for an anime.\n\nFor example, the anime Bakemonogatari has five OP anime themes and one ED anime theme."; } + /** + * @return class-string + */ + public function getEnumSortClass(): string + { + return AnimeThemeSort::class; + } + /** * The relations of the type. * diff --git a/app/GraphQL/Schema/Types/Wiki/Anime/Theme/AnimeThemeEntryType.php b/app/GraphQL/Schema/Types/Wiki/Anime/Theme/AnimeThemeEntryType.php index be03577dc..9339727a4 100644 --- a/app/GraphQL/Schema/Types/Wiki/Anime/Theme/AnimeThemeEntryType.php +++ b/app/GraphQL/Schema/Types/Wiki/Anime/Theme/AnimeThemeEntryType.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types\Wiki\Anime\Theme; +use App\Enums\GraphQL\Sort\Wiki\Anime\AnimeTheme\AnimeThemeEntrySort; use App\GraphQL\Schema\Fields\Base\Aggregate\LikesCountField; use App\GraphQL\Schema\Fields\Base\CreatedAtField; use App\GraphQL\Schema\Fields\Base\DeletedAtField; @@ -34,6 +35,14 @@ class AnimeThemeEntryType extends EloquentType return "Represents a version of an anime theme.\n\nFor example, the ED theme of the Bakemonogatari anime has three anime theme entries to represent three versions."; } + /** + * @return class-string + */ + public function getEnumSortClass(): string + { + return AnimeThemeEntrySort::class; + } + /** * The fields of the type. * diff --git a/app/GraphQL/Schema/Types/Wiki/AnimeType.php b/app/GraphQL/Schema/Types/Wiki/AnimeType.php index 1cfdfcc13..3a2ece899 100644 --- a/app/GraphQL/Schema/Types/Wiki/AnimeType.php +++ b/app/GraphQL/Schema/Types/Wiki/AnimeType.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types\Wiki; +use App\Enums\GraphQL\Sort\Pivot\ImageableSort; +use App\Enums\GraphQL\Sort\Wiki\AnimeSort; use App\GraphQL\Schema\Fields\Base\CreatedAtField; use App\GraphQL\Schema\Fields\Base\DeletedAtField; use App\GraphQL\Schema\Fields\Base\IdUnbindableField; @@ -37,6 +39,14 @@ class AnimeType extends EloquentType return "Represents a production with at least one opening or ending sequence.\n\nFor example, Bakemonogatari is an anime production with five opening sequences and one ending sequence."; } + /** + * @return class-string + */ + public function getEnumSortClass(): string + { + return AnimeSort::class; + } + /** * The fields of the type. * @@ -66,7 +76,8 @@ class AnimeType extends EloquentType new MorphManyRelation(new SynonymType(), Anime::RELATION_SYNONYMS), new HasManyRelation(new AnimeThemeType(), Anime::RELATION_THEMES), new MorphToManyRelation($this, new ExternalResourceType(), Anime::RELATION_RESOURCES, new ResourceableType()), - new MorphToManyRelation($this, new ImageType(), Anime::RELATION_IMAGES, new ImageableType()), + new MorphToManyRelation($this, new ImageType(), Anime::RELATION_IMAGES, new ImageableType()) + ->setSortEnum(ImageableSort::class), new BelongsToManyRelation($this, new SeriesType(), Anime::RELATION_SERIES, new AnimeSeriesType()), new BelongsToManyRelation($this, new StudioType(), Anime::RELATION_STUDIOS, new AnimeStudioType()), ]; diff --git a/app/GraphQL/Schema/Types/Wiki/ArtistType.php b/app/GraphQL/Schema/Types/Wiki/ArtistType.php index 86dcd4002..e46cf2899 100644 --- a/app/GraphQL/Schema/Types/Wiki/ArtistType.php +++ b/app/GraphQL/Schema/Types/Wiki/ArtistType.php @@ -4,6 +4,9 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types\Wiki; +use App\Enums\GraphQL\Sort\Pivot\ArtistMemberSort; +use App\Enums\GraphQL\Sort\Pivot\ImageableSort; +use App\Enums\GraphQL\Sort\Wiki\ArtistSort; use App\GraphQL\Schema\Fields\Base\CreatedAtField; use App\GraphQL\Schema\Fields\Base\DeletedAtField; use App\GraphQL\Schema\Fields\Base\IdUnbindableField; @@ -30,6 +33,14 @@ class ArtistType extends EloquentType return "Represents a musical performer of anime sequences.\n\nFor example, Chiwa Saitou is the musical performer of the Bakemonogatari OP1 theme, among many others."; } + /** + * @return class-string + */ + public function getEnumSortClass(): string + { + return ArtistSort::class; + } + /** * The fields of the type. * @@ -48,8 +59,10 @@ class ArtistType extends EloquentType new MorphManyRelation(new SynonymType(), Artist::RELATION_SYNONYMS), new BelongsToManyRelation($this, new ArtistType(), Artist::RELATION_GROUPS, new ArtistMemberType()), - new BelongsToManyRelation($this, new ArtistType(), Artist::RELATION_MEMBERS, new ArtistMemberType()), - new MorphToManyRelation($this, new ImageType(), Artist::RELATION_IMAGES, new ImageableType()), + new BelongsToManyRelation($this, new ArtistType(), Artist::RELATION_MEMBERS, new ArtistMemberType()) + ->setSortEnum(ArtistMemberSort::class), + new MorphToManyRelation($this, new ImageType(), Artist::RELATION_IMAGES, new ImageableType()) + ->setSortEnum(ImageableSort::class), new MorphToManyRelation($this, new ExternalResourceType(), Artist::RELATION_RESOURCES, new ResourceableType()), new HasManyRelation(new PerformanceType(), Artist::RELATION_PERFORMANCES), new HasManyRelation(new PerformanceType(), Artist::RELATION_MEMBER_PERFORMANCES), diff --git a/app/GraphQL/Schema/Types/Wiki/AudioType.php b/app/GraphQL/Schema/Types/Wiki/AudioType.php index fed4228f1..5e88dd7c5 100644 --- a/app/GraphQL/Schema/Types/Wiki/AudioType.php +++ b/app/GraphQL/Schema/Types/Wiki/AudioType.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types\Wiki; +use App\Enums\GraphQL\Sort\Wiki\AudioSort; use App\GraphQL\Schema\Fields\Base\CreatedAtField; use App\GraphQL\Schema\Fields\Base\DeletedAtField; use App\GraphQL\Schema\Fields\Base\IdField; @@ -26,6 +27,14 @@ class AudioType extends EloquentType return "Represents the audio track of a video.\n\nFor example, the audio Bakemonogatari-OP1.ogg represents the audio track of the Bakemonogatari-OP1.webm video."; } + /** + * @return class-string + */ + public function getEnumSortClass(): string + { + return AudioSort::class; + } + /** * The fields of the type. * diff --git a/app/GraphQL/Schema/Types/Wiki/ImageType.php b/app/GraphQL/Schema/Types/Wiki/ImageType.php index 71497119e..b6c5f87b4 100644 --- a/app/GraphQL/Schema/Types/Wiki/ImageType.php +++ b/app/GraphQL/Schema/Types/Wiki/ImageType.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types\Wiki; +use App\Enums\GraphQL\Sort\Wiki\ImageSort; use App\GraphQL\Schema\Fields\Base\CreatedAtField; use App\GraphQL\Schema\Fields\Base\DeletedAtField; use App\GraphQL\Schema\Fields\Base\IdField; @@ -25,6 +26,14 @@ class ImageType extends EloquentType return "Represents a visual component for another resource such as an anime or artist.\n\nFor example, the Bakemonogatari anime has two images to represent small and large cover images."; } + /** + * @return class-string + */ + public function getEnumSortClass(): string + { + return ImageSort::class; + } + /** * The fields of the type. * diff --git a/app/GraphQL/Schema/Types/Wiki/SeriesType.php b/app/GraphQL/Schema/Types/Wiki/SeriesType.php index 7b38e20a8..ccd2f0f66 100644 --- a/app/GraphQL/Schema/Types/Wiki/SeriesType.php +++ b/app/GraphQL/Schema/Types/Wiki/SeriesType.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types\Wiki; +use App\Enums\GraphQL\Sort\Wiki\SeriesSort; use App\GraphQL\Schema\Fields\Base\CreatedAtField; use App\GraphQL\Schema\Fields\Base\DeletedAtField; use App\GraphQL\Schema\Fields\Base\IdUnbindableField; @@ -23,6 +24,14 @@ class SeriesType extends EloquentType return "Represents a collection of related anime.\n\nFor example, the Monogatari series is the collection of the Bakemonogatari anime and its related productions."; } + /** + * @return class-string + */ + public function getEnumSortClass(): string + { + return SeriesSort::class; + } + /** * The fields of the type. * diff --git a/app/GraphQL/Schema/Types/Wiki/Song/PerformanceType.php b/app/GraphQL/Schema/Types/Wiki/Song/PerformanceType.php index 8b94fffba..d4bc8a3c2 100644 --- a/app/GraphQL/Schema/Types/Wiki/Song/PerformanceType.php +++ b/app/GraphQL/Schema/Types/Wiki/Song/PerformanceType.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types\Wiki\Song; +use App\Enums\GraphQL\Sort\Wiki\Song\PerformanceSort; use App\GraphQL\Schema\Fields\Base\CreatedAtField; use App\GraphQL\Schema\Fields\Base\DeletedAtField; use App\GraphQL\Schema\Fields\Base\IdField; @@ -27,6 +28,14 @@ class PerformanceType extends EloquentType return 'Represents the link between a song and an artist or group.'; } + /** + * @return class-string + */ + public function getEnumSortClass(): string + { + return PerformanceSort::class; + } + /** * The fields of the type. * diff --git a/app/GraphQL/Schema/Types/Wiki/SongType.php b/app/GraphQL/Schema/Types/Wiki/SongType.php index 3fbb3fa9a..508e33171 100644 --- a/app/GraphQL/Schema/Types/Wiki/SongType.php +++ b/app/GraphQL/Schema/Types/Wiki/SongType.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types\Wiki; +use App\Enums\GraphQL\Sort\Wiki\SongSort; use App\GraphQL\Schema\Fields\Base\CreatedAtField; use App\GraphQL\Schema\Fields\Base\DeletedAtField; use App\GraphQL\Schema\Fields\Base\IdField; @@ -26,6 +27,14 @@ class SongType extends EloquentType return "Represents the composition that accompanies an AnimeTheme.\n\nFor example, Staple Stable is the song for the Bakemonogatari OP1 AnimeTheme."; } + /** + * @return class-string + */ + public function getEnumSortClass(): string + { + return SongSort::class; + } + /** * The fields of the type. * diff --git a/app/GraphQL/Schema/Types/Wiki/StudioType.php b/app/GraphQL/Schema/Types/Wiki/StudioType.php index 3dccc957d..7f10696ee 100644 --- a/app/GraphQL/Schema/Types/Wiki/StudioType.php +++ b/app/GraphQL/Schema/Types/Wiki/StudioType.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types\Wiki; +use App\Enums\GraphQL\Sort\Pivot\ImageableSort; use App\GraphQL\Schema\Fields\Base\CreatedAtField; use App\GraphQL\Schema\Fields\Base\DeletedAtField; use App\GraphQL\Schema\Fields\Base\IdUnbindableField; @@ -42,7 +43,8 @@ class StudioType extends EloquentType new DeletedAtField(), new BelongsToManyRelation($this, new AnimeType(), Studio::RELATION_ANIME, new AnimeStudioType()), - new MorphToManyRelation($this, new ImageType(), Studio::RELATION_IMAGES, new ImageableType()), + new MorphToManyRelation($this, new ImageType(), Studio::RELATION_IMAGES, new ImageableType()) + ->setSortEnum(ImageableSort::class), new MorphToManyRelation($this, new ExternalResourceType(), Studio::RELATION_RESOURCES, new ResourceableType()), ]; } diff --git a/app/GraphQL/Schema/Types/Wiki/SynonymType.php b/app/GraphQL/Schema/Types/Wiki/SynonymType.php index 0458f220a..730827dec 100644 --- a/app/GraphQL/Schema/Types/Wiki/SynonymType.php +++ b/app/GraphQL/Schema/Types/Wiki/SynonymType.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types\Wiki; +use App\Enums\GraphQL\Sort\Wiki\SynonymSort; use App\GraphQL\Schema\Fields\Base\CreatedAtField; use App\GraphQL\Schema\Fields\Base\DeletedAtField; use App\GraphQL\Schema\Fields\Base\IdField; @@ -22,6 +23,14 @@ class SynonymType extends EloquentType return "Represents an alternate title or common abbreviation for an entity.\n\nFor example, the anime Bakemonogatari has the synonym \"Monstory\"."; } + /** + * @return class-string + */ + public function getEnumSortClass(): string + { + return SynonymSort::class; + } + /** * The fields of the type. * diff --git a/app/GraphQL/Schema/Types/Wiki/VideoType.php b/app/GraphQL/Schema/Types/Wiki/VideoType.php index eed198fa0..332d91cfd 100644 --- a/app/GraphQL/Schema/Types/Wiki/VideoType.php +++ b/app/GraphQL/Schema/Types/Wiki/VideoType.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\GraphQL\Schema\Types\Wiki; +use App\Enums\GraphQL\Sort\Wiki\VideoSort; use App\GraphQL\Schema\Fields\Base\CreatedAtField; use App\GraphQL\Schema\Fields\Base\DeletedAtField; use App\GraphQL\Schema\Fields\Base\IdField; @@ -43,6 +44,14 @@ class VideoType extends EloquentType return "Represents a WebM of an anime theme.\n\nFor example, the video Bakemonogatari-OP1.webm represents the WebM of the Bakemonogatari OP1 theme."; } + /** + * @return class-string + */ + public function getEnumSortClass(): string + { + return VideoSort::class; + } + /** * The fields of the type. * diff --git a/app/GraphQL/Sort/Sort.php b/app/GraphQL/Sort/Sort.php deleted file mode 100644 index 099d67b7b..000000000 --- a/app/GraphQL/Sort/Sort.php +++ /dev/null @@ -1,40 +0,0 @@ -name; - } - - /** - * Get sort column. - */ - public function getColumn(): string - { - return $this->column ?? $this->getName(); - } - - /** - * Determine if the column should be qualified for the sort. - */ - public function shouldQualifyColumn(): bool - { - return $this->qualifyColumn === QualifyColumn::YES; - } -} diff --git a/app/Providers/GraphQLServiceProvider.php b/app/Providers/GraphQLServiceProvider.php index b0fdc5dc8..e6734e1f4 100644 --- a/app/Providers/GraphQLServiceProvider.php +++ b/app/Providers/GraphQLServiceProvider.php @@ -6,7 +6,26 @@ namespace App\Providers; use App\Enums\GraphQL\Filter\ComparisonOperator; use App\Enums\GraphQL\Filter\TrashedFilter; -use App\Enums\GraphQL\Sort\SortDirection; +use App\Enums\GraphQL\Sort\Admin\AnnouncementSort; +use App\Enums\GraphQL\Sort\Admin\DumpSort; +use App\Enums\GraphQL\Sort\Document\PageSort; +use App\Enums\GraphQL\Sort\List\Playlist\PlaylistTrackSort; +use App\Enums\GraphQL\Sort\List\PlaylistSort; +use App\Enums\GraphQL\Sort\Pivot\ArtistMemberSort; +use App\Enums\GraphQL\Sort\Pivot\ImageableSort; +use App\Enums\GraphQL\Sort\Wiki\Anime\AnimeTheme\AnimeThemeEntrySort; +use App\Enums\GraphQL\Sort\Wiki\Anime\AnimeThemeSort; +use App\Enums\GraphQL\Sort\Wiki\AnimeSort; +use App\Enums\GraphQL\Sort\Wiki\ArtistSort; +use App\Enums\GraphQL\Sort\Wiki\AudioSort; +use App\Enums\GraphQL\Sort\Wiki\ImageSort; +use App\Enums\GraphQL\Sort\Wiki\SeriesSort; +use App\Enums\GraphQL\Sort\Wiki\Song\PerformanceSort; +use App\Enums\GraphQL\Sort\Wiki\SongSort; +use App\Enums\GraphQL\Sort\Wiki\StudioSort; +use App\Enums\GraphQL\Sort\Wiki\SynonymSort; +use App\Enums\GraphQL\Sort\Wiki\VideoSort; +use App\Enums\GraphQL\SortDirection; use App\Enums\Models\List\ExternalEntryStatus; use App\Enums\Models\List\ExternalProfileSite; use App\Enums\Models\List\ExternalProfileVisibility; @@ -48,6 +67,29 @@ class GraphQLServiceProvider extends ServiceProvider protected function bootEnums(): void { + // Sort Enums. + GraphQL::addType(new EnumType(AnnouncementSort::class)); + GraphQL::addType(new EnumType(DumpSort::class)); + GraphQL::addType(new EnumType(PageSort::class)); + GraphQL::addType(new EnumType(PlaylistSort::class)); + GraphQL::addType(new EnumType(PlaylistTrackSort::class)); + GraphQL::addType(new EnumType(AnimeSort::class)); + GraphQL::addType(new EnumType(AnimeThemeSort::class)); + GraphQL::addType(new EnumType(AnimeThemeEntrySort::class)); + GraphQL::addType(new EnumType(ArtistSort::class)); + GraphQL::addType(new EnumType(AudioSort::class)); + GraphQL::addType(new EnumType(ImageSort::class)); + GraphQL::addType(new EnumType(PerformanceSort::class)); + GraphQL::addType(new EnumType(SeriesSort::class)); + GraphQL::addType(new EnumType(SongSort::class)); + GraphQL::addType(new EnumType(StudioSort::class)); + GraphQL::addType(new EnumType(SynonymSort::class)); + GraphQL::addType(new EnumType(VideoSort::class)); + + // Pivot Sort Enums. + GraphQL::addType(new EnumType(ArtistMemberSort::class)); + GraphQL::addType(new EnumType(ImageableSort::class)); + GraphQL::addType(new EnumType(ComparisonOperator::class)); GraphQL::addType(new EnumType(TrashedFilter::class)); GraphQL::addType(new EnumType(SortDirection::class)); diff --git a/tests/Unit/GraphQL/Criteria/Sort/PivotSortCriteriaTest.php b/tests/Unit/GraphQL/Criteria/Sort/PivotSortCriteriaTest.php deleted file mode 100644 index 2b6e9b439..000000000 --- a/tests/Unit/GraphQL/Criteria/Sort/PivotSortCriteriaTest.php +++ /dev/null @@ -1,21 +0,0 @@ -word()), SortDirection::ASC) extends PivotSortCriteria {}; - - $this->assertStringStartsWith('PIVOT_', $criteria->__toString()); - $this->assertStringEndsNotWith('_DESC', $criteria->__toString()); -}); - -it('formats for desc', function () { - $criteria = new class(new Sort(fake()->word()), SortDirection::DESC) extends PivotSortCriteria {}; - - $this->assertStringStartsWith('PIVOT_', $criteria->__toString()); - $this->assertStringEndsWith('_DESC', $criteria->__toString()); -}); diff --git a/tests/Unit/GraphQL/Criteria/Sort/RelationSortCriteriaTest.php b/tests/Unit/GraphQL/Criteria/Sort/RelationSortCriteriaTest.php deleted file mode 100644 index 47e4d8da7..000000000 --- a/tests/Unit/GraphQL/Criteria/Sort/RelationSortCriteriaTest.php +++ /dev/null @@ -1,26 +0,0 @@ -word(); - - $criteria = new class(new Sort(fake()->word()), $relation, SortDirection::ASC) extends RelationSortCriteria {}; - - $this->assertStringStartsWith(Str::upper($relation), $criteria->__toString()); - $this->assertStringEndsNotWith('_DESC', $criteria->__toString()); -}); - -it('formats for desc', function () { - $relation = fake()->word(); - - $criteria = new class(new Sort(fake()->word()), $relation, SortDirection::DESC) extends RelationSortCriteria {}; - - $this->assertStringStartsWith(Str::upper($relation), $criteria->__toString()); - $this->assertStringEndsWith('_DESC', $criteria->__toString()); -}); diff --git a/tests/Unit/GraphQL/Criteria/Sort/SortCriteriaTest.php b/tests/Unit/GraphQL/Criteria/Sort/SortCriteriaTest.php deleted file mode 100644 index d0d681a02..000000000 --- a/tests/Unit/GraphQL/Criteria/Sort/SortCriteriaTest.php +++ /dev/null @@ -1,32 +0,0 @@ -word()), SortDirection::ASC) extends SortCriteria - { - public function sort(Builder $builder): Builder - { - return $builder; - } - }; - - $this->assertStringEndsNotWith('_DESC', $criteria->__toString()); -}); - -it('formats for desc', function () { - $criteria = new class(new Sort(fake()->word()), SortDirection::DESC) extends SortCriteria - { - public function sort(Builder $builder): Builder - { - return $builder; - } - }; - - $this->assertStringEndsWith('_DESC', $criteria->__toString()); -});