diff --git a/app/Repositories/DefaultAnimeRepository.php b/app/Repositories/DefaultAnimeRepository.php index e337182..4a29a48 100644 --- a/app/Repositories/DefaultAnimeRepository.php +++ b/app/Repositories/DefaultAnimeRepository.php @@ -5,15 +5,12 @@ namespace App\Repositories; use App\Anime; use App\Contracts\AnimeRepository; use App\Contracts\Repository; -use App\Enums\AnimeRatingEnum; use App\Enums\AnimeScheduleFilterEnum; -use App\Enums\AnimeSeasonEnum; use App\Enums\AnimeStatusEnum; use App\Enums\AnimeTypeEnum; use Illuminate\Contracts\Database\Query\Builder as EloquentBuilder; use Illuminate\Database\Eloquent\Collection; use Illuminate\Support\Carbon; -use Jikan\Helper\Constants; use Laravel\Scout\Builder as ScoutBuilder; /** @@ -120,44 +117,49 @@ final class DefaultAnimeRepository extends DatabaseRepository implements AnimeRe ?string $premiered = null ): EloquentBuilder { - /** @noinspection PhpParamsInspection */ $queryable = $this->queryable(true); - $airedFilter = ["aired.from" => [ + $airedFilter = ['aired.from' => [ '$gte' => $from->toAtomString(), - '$lte' => $to->modify("last day of this month")->toAtomString() + '$lte' => $to->modify('last day of this month')->toAtomString() ]]; $finalFilter = []; // if the premiered parameter for the filter is not null, look for those items which have a premiered attribute set, // and equals to the parameter value, OR look for those items which doesn't have premired attribute set, - // they don't have a garbled aired string and their aired.from date is within the from-to parameters range + // they don't have a garbled aired string and their aired.from date is within the from-to parameters range. + // Additionally, we want to include all those items which are carry overs from previous seasons. if ($premiered !== null) { $finalFilter['$or'] = [ - ["premiered" => $premiered], + ['premiered' => $premiered], [ - "premiered" => null, - "aired.string" => [ - '$not' => ['$regex' => "{$from->year} to ?"] + 'premiered' => null, + 'aired.string' => [ + '$nin' => ["{$from->year} to ?"] ], ...$airedFilter + ], + // this condition will include "continuing" items from previous seasons + [ + 'aired.from' => ['$lte' => $from->toAtomString()], + 'airing' => true ] ]; } else { $finalFilter = array_merge($finalFilter, $airedFilter); - $finalFilter["aired.string"] = [ - '$not' => ['$regex' => "{$from->year} to ?"] + $finalFilter['aired.string'] = [ + '$nin' => ["{$from->year} to ?"] ]; } if (!is_null($type)) { - $finalFilter["type"] = $type->label; + $finalFilter['type'] = $type->label; } $queryable = $queryable->whereRaw($finalFilter); - return $queryable->orderBy("members", "desc"); + return $queryable->orderBy('members', 'desc'); } public function getUpcomingSeasonItems( diff --git a/app/Support/RepositoryQueryBase.php b/app/Support/RepositoryQueryBase.php index 0463586..17fcd19 100644 --- a/app/Support/RepositoryQueryBase.php +++ b/app/Support/RepositoryQueryBase.php @@ -3,6 +3,7 @@ namespace App\Support; use Laravel\Scout\Builder as ScoutBuilder; use Illuminate\Contracts\Database\Query\Builder; +use Jenssegers\Mongodb\Eloquent\Builder as MongoDbBuilder; class RepositoryQueryBase { @@ -15,7 +16,7 @@ class RepositoryQueryBase { } - protected function queryable(bool $createNew = false): Builder + protected function queryable(bool $createNew = false): Builder|MongoDbBuilder { if ($createNew) { $callback = $this->getQueryable; diff --git a/tests/Integration/SeasonControllerTest.php b/tests/Integration/SeasonControllerTest.php index 2879209..44a71db 100644 --- a/tests/Integration/SeasonControllerTest.php +++ b/tests/Integration/SeasonControllerTest.php @@ -25,7 +25,7 @@ class SeasonControllerTest extends TestCase $state = $f->serializeStateDefinition([ "aired" => new CarbonDateRange($carbonStartDate, null) ]); - $state["aired"]["string"] = "Jan 1, 2024 to ?"; + $state["aired"]["string"] = "2024 to ?"; $state["premiered"] = null; $state["status"] = "Not yet aired"; $state["airing"] = false; @@ -49,4 +49,91 @@ class SeasonControllerTest extends TestCase $this->assertIsArray($content["data"]); $this->assertCount(1, $content["data"]); } + + public function testShouldNotFilterOutFutureAiringDates() + { + Carbon::setTestNow(Carbon::parse("2024-01-11")); + // an item in the future airing + $f = Anime::factory(1); + $startDate = "2024-02-24"; + $carbonStartDate = Carbon::parse($startDate); + $state = $f->serializeStateDefinition([ + "aired" => new CarbonDateRange($carbonStartDate, null) + ]); + $state["aired"]["string"] = "Feb 24, 2024 to ?"; + $state["premiered"] = null; + $state["status"] = "Not yet aired"; + $state["airing"] = false; + $f->create($state); + + // the "garbled" wrong item + $f = Anime::factory(1); + $startDate = "2024-01-01"; + $carbonStartDate = Carbon::parse($startDate); + $state = $f->serializeStateDefinition([ + "aired" => new CarbonDateRange($carbonStartDate, null) + ]); + $state["aired"]["string"] = "2024 to ?"; + $state["premiered"] = null; + $state["status"] = "Not yet aired"; + $state["airing"] = false; + $f->create($state); + + // the absolutely correct item + $f = Anime::factory(1); + $state = $f->serializeStateDefinition([ + "aired" => new CarbonDateRange(Carbon::parse("2024-01-10"), Carbon::parse("2024-02-15")) + ]); + $state["premiered"] = "Winter 2024"; + $state["status"] = "Currently Airing"; + $state["airing"] = true; + $f->create($state); + + $content = $this->getJsonResponse([], "/v4/seasons/2024/winter"); + $this->seeStatusCode(200); + $this->assertIsArray($content["data"]); + $this->assertCount(2, $content["data"]); + } + + public function testShouldNotFilterOutContinuingItemsFromPreviousSeasons() + { + Carbon::setTestNow(Carbon::parse("2024-01-11")); + // an item in the future airing + $f = Anime::factory(1); + $startDate = "2024-02-24"; + $carbonStartDate = Carbon::parse($startDate); + $state = $f->serializeStateDefinition([ + "aired" => new CarbonDateRange($carbonStartDate, null) + ]); + $state["aired"]["string"] = "Feb 24, 2024 to ?"; + $state["premiered"] = null; + $state["status"] = "Not yet aired"; + $state["airing"] = false; + $f->create($state); + + // the absolutely correct item + $f = Anime::factory(1); + $state = $f->serializeStateDefinition([ + "aired" => new CarbonDateRange(Carbon::parse("2024-01-10"), Carbon::parse("2024-02-15")) + ]); + $state["premiered"] = "Winter 2024"; + $state["status"] = "Currently Airing"; + $state["airing"] = true; + $f->create($state); + + // the continuing item + $f = Anime::factory(1); + $state = $f->serializeStateDefinition([ + "aired" => new CarbonDateRange(Carbon::parse("2023-10-10"), null) + ]); + $state["premiered"] = "Fall 2023"; + $state["status"] = "Currently Airing"; + $state["airing"] = true; + $f->create($state); + + $content = $this->getJsonResponse([], "/v4/seasons/2024/winter"); + $this->seeStatusCode(200); + $this->assertIsArray($content["data"]); + $this->assertCount(3, $content["data"]); + } }