diff --git a/src/Enums/StatusEnum.php b/src/Enums/StatusEnum.php index 9cc86df..ba3d7e9 100644 --- a/src/Enums/StatusEnum.php +++ b/src/Enums/StatusEnum.php @@ -2,8 +2,6 @@ namespace EscolaLms\Core\Enums; -use EscolaLms\Core\Enums\BasicEnum; - class StatusEnum extends BasicEnum { const INACTIVE = 0; diff --git a/src/Repositories/Criteria/CourseSearch.php b/src/Repositories/Criteria/CourseSearch.php deleted file mode 100644 index abeeadd..0000000 --- a/src/Repositories/Criteria/CourseSearch.php +++ /dev/null @@ -1,28 +0,0 @@ -where(function (Builder $query): Builder { - $like = DB::connection()->getPdo()->getAttribute(\PDO::ATTR_DRIVER_NAME) === 'pgsql' ? 'ILIKE' : 'LIKE'; - - - return $query - ->where('courses.course_title', $like, '%' . $this->value . '%') - ->orWhere('courses.course_slug', $like, '%' . $this->value . '%') - ->orWhere('categories.name', $like, '%' . $this->value . '%'); - }); - } -} diff --git a/src/Repositories/Criteria/NotRelatedCourses.php b/src/Repositories/Criteria/NotRelatedCourses.php deleted file mode 100644 index b6ae9e4..0000000 --- a/src/Repositories/Criteria/NotRelatedCourses.php +++ /dev/null @@ -1,15 +0,0 @@ -where('courses.id', '!=', $this->value->getKey()) - ->whereNotIn('courses.id', $this->value->related()->pluck('id')); - } -} diff --git a/tests/Api/CriteriaApiTest.php b/tests/Api/CriteriaApiTest.php new file mode 100644 index 0000000..162e3b9 --- /dev/null +++ b/tests/Api/CriteriaApiTest.php @@ -0,0 +1,150 @@ +count(10) + ->create(); + + $response = $this->json('GET', 'api/core?limit=5'); + $response->assertJsonCount(5, 'data'); + } + + public function testDateCriterion() + { + $date = Carbon::now()->addDays(5); + + ExampleEntity::factory() + ->count(5) + ->create(['created_at' => $date]); + + ExampleEntity::factory() + ->count(5) + ->create(); + + $response = $this->json('GET', 'api/core?gt_created_at=' . $date); + + $response->assertJsonCount(5, 'data'); + } + + public function testLikeCriterion() + { + ExampleEntity::factory() + ->count(5) + ->create(['name' => 'simple name']); + + ExampleEntity::factory() + ->count(5) + ->create(['name' => $this->faker->word]); + + $response = $this->json('GET', 'api/core?name=simple'); + $response->assertJsonCount(5, 'data'); + } + + public function testInCriterion() + { + $ids = ExampleEntity::factory() + ->count(5) + ->create() + ->pluck('id') + ->map(fn ($item) => 'ids[]=' . $item . '&'); + + ExampleEntity::factory() + ->count(5) + ->create(); + + $response = $this->json('GET', 'api/core?' . $ids->implode('')); + $response->assertJsonCount(5, 'data'); + } + + public function testIsNullCriterion() + { + ExampleEntity::factory() + ->count(5) + ->create(); + + ExampleEntity::factory() + ->count(5) + ->create(['description' => null]); + + $response = $this->json('GET', 'api/core?nullable=1'); + $response->assertJsonCount(5, 'data'); + } + + public function testEqualsCriterion() + { + ExampleEntity::factory() + ->count(5) + ->create(['status' => StatusEnum::INACTIVE]); + + ExampleEntity::factory() + ->count(5) + ->create(['status' => StatusEnum::ACTIVE]); + + $response = $this->json('GET', 'api/core?status=' . StatusEnum::ACTIVE); + $response->assertJsonCount(5, 'data'); + } + + public function testPeriodCriterion() + { + $dateFrom = Carbon::now(); + $dateTo = Carbon::now()->addDays(5); + + ExampleEntity::factory() + ->count(5) + ->create(['date_time' => Carbon::now()->subYear()]); + + ExampleEntity::factory() + ->count(5) + ->create(['date_time' => $dateFrom]); + + ExampleEntity::factory() + ->count(5) + ->create(['date_time' => $dateTo]); + + ExampleEntity::factory() + ->count(5) + ->create(['date_time' => Carbon::now()->addYear()]); + + $response = $this->json('GET', 'api/core?from=' . $dateFrom . '&to=' . $dateTo); + $response->assertJsonCount(10, 'data'); + } + + public function testPeriodDto() + { + $dateFrom = Carbon::now(); + $dateTo = Carbon::now()->addDays(5); + + ExampleEntity::factory() + ->count(5) + ->create(['date_time' => Carbon::now()->subYear()]); + + ExampleEntity::factory() + ->count(5) + ->create(['date_time' => $dateFrom]); + + ExampleEntity::factory() + ->count(5) + ->create(['date_time' => $dateTo]); + + ExampleEntity::factory() + ->count(5) + ->create(['date_time' => Carbon::now()->addYear()]); + + $response = $this->json('GET', 'api/core/period?from=' . $dateFrom . '&to=' . $dateTo); + $response->assertJsonCount(10); + } +} diff --git a/tests/Features/BaseRepositoryTest.php b/tests/Features/BaseRepositoryTest.php index e32686c..6392c52 100644 --- a/tests/Features/BaseRepositoryTest.php +++ b/tests/Features/BaseRepositoryTest.php @@ -3,8 +3,14 @@ namespace EscolaLms\Core\Tests\Features; use EscolaLms\Core\Dtos\PaginationDto; +use EscolaLms\Core\Enums\UserRole; use EscolaLms\Core\Models\User; +use EscolaLms\Core\Repositories\Criteria\Primitives\DoesntHasCriterion; use EscolaLms\Core\Repositories\Criteria\Primitives\EqualCriterion; +use EscolaLms\Core\Repositories\Criteria\Primitives\HasCriterion; +use EscolaLms\Core\Repositories\Criteria\Primitives\ModelCriterion; +use EscolaLms\Core\Repositories\Criteria\UserCriterion; +use EscolaLms\Core\Repositories\Criteria\UserSearchCriterion; use EscolaLms\Core\Tests\Mocks\BaseRepository; use EscolaLms\Core\Tests\Mocks\CompareDto; use EscolaLms\Core\Tests\Mocks\UpdateDto; @@ -12,12 +18,13 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; use Illuminate\Foundation\Testing\DatabaseTransactions; +use Illuminate\Foundation\Testing\WithFaker; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Support\Facades\DB; class BaseRepositoryTest extends TestCase { - use DatabaseTransactions; + use DatabaseTransactions, WithFaker; protected BaseRepository $repository; protected User $user; @@ -28,8 +35,11 @@ protected function setUp(): void parent::setUp(); $this->repository = app(BaseRepository::class); $this->user = User::factory()->create([ + 'first_name' => $this->faker->firstName . $this->faker->numberBetween(), + 'last_name' => $this->faker->lastName . $this->faker->numberBetween(), 'country' => 'Old Country' ]); + $this->user->assignRole(UserRole::ADMIN); $users = User::factory()->count(8)->create(); $this->last_user = User::factory()->create(); } @@ -165,6 +175,67 @@ public function testSearchByCriteria() $this->assertEquals($this->user->email, $collection->first()->email); } + public function testSearchByUserCriteria() + { + $criteria = [ + new UserCriterion('id', $this->user) + ]; + $result = $this->repository->searchByCriteria($criteria); + $this->assertCount(1, $result); + $this->assertEquals($this->user->getKey(), $result->first()->getKey()); + + $criteria = [ + new UserSearchCriterion($this->user->first_name) + ]; + $result = $this->repository->searchByCriteria($criteria); + $this->assertCount(1, $result); + $this->assertEquals($this->user->first_name, $result->first()->first_name); + + $criteria = [ + new UserSearchCriterion($this->user->last_name) + ]; + $result = $this->repository->searchByCriteria($criteria); + $this->assertCount(1, $result); + $this->assertEquals($this->user->last_name, $result->first()->last_name); + + $criteria = [ + new UserSearchCriterion($this->user->email) + ]; + $result = $this->repository->searchByCriteria($criteria); + $this->assertCount(1, $result); + $this->assertEquals($this->user->email, $result->first()->email); + + $criteria = [ + new ModelCriterion('id', $this->user) + ]; + $result = $this->repository->searchByCriteria($criteria); + $this->assertCount(1, $result); + $this->assertEquals($this->user->getKey(), $result->first()->getKey()); + } + + public function testSearchByRoles() + { + $criteria = [ + new HasCriterion('roles', fn ($query) => $query->where('name', UserRole::ADMIN)) + ]; + $result = $this->repository->searchByCriteria($criteria); + $this->assertCount(1, $result); + $this->assertEquals($this->user->getKey(), $result->first()->getKey()); + + $criteria = [ + new HasCriterion('roles', fn ($query) => $query->where('name', UserRole::STUDENT)) + ]; + $result = $this->repository->searchByCriteria($criteria); + $this->assertCount(0, $result); + + $this->last_user->assignRole(UserRole::STUDENT); + $criteria = [ + new DoesntHasCriterion('roles', fn ($query) => $query->where('name', UserRole::STUDENT)) + ]; + $result = $this->repository->searchByCriteria($criteria); + $this->assertCount(9, $result); + } + public function testQueryWithAppliedCriteria() { diff --git a/tests/Mocks/ExampleEntity/ExampleEntity.php b/tests/Mocks/ExampleEntity/ExampleEntity.php new file mode 100644 index 0000000..9958136 --- /dev/null +++ b/tests/Mocks/ExampleEntity/ExampleEntity.php @@ -0,0 +1,20 @@ +service = $service; + } + + public function index(Request $request): JsonResponse + { + $orderDto = OrderDto::instantiateFromRequest($request); + $paginationDto = PaginationDto::instantiateFromRequest($request); + $searchDto = ExampleEntitySearchDto::instantiateFromRequest($request); + + $results = $this->service->getExampleEntities($searchDto, $paginationDto, $orderDto); + + return new JsonResponse($results); + } + + public function period(Request $request): JsonResponse + { + $periodDto = PeriodDto::instantiateFromRequest($request); + + $results = $this->service->getByPeriod($periodDto); + + return new JsonResponse($results); + } +} diff --git a/tests/Mocks/ExampleEntity/ExampleEntityFactory.php b/tests/Mocks/ExampleEntity/ExampleEntityFactory.php new file mode 100644 index 0000000..e0f6542 --- /dev/null +++ b/tests/Mocks/ExampleEntity/ExampleEntityFactory.php @@ -0,0 +1,21 @@ + $this->faker->word(), + 'description' => $this->faker->words(3, true), + 'status' => $this->faker->randomElement(StatusEnum::asArray()), + 'date_time' => $this->faker->dateTimeBetween(), + ]; + } +} diff --git a/tests/Mocks/ExampleEntity/ExampleEntityMigration.php b/tests/Mocks/ExampleEntity/ExampleEntityMigration.php new file mode 100644 index 0000000..01a75a1 --- /dev/null +++ b/tests/Mocks/ExampleEntity/ExampleEntityMigration.php @@ -0,0 +1,26 @@ +id(); + $table->string('name'); + $table->string('description')->nullable(); + $table->integer('status')->default(StatusEnum::ACTIVE); + $table->dateTime('date_time'); + $table->timestamps(); + }); + } +} diff --git a/tests/Mocks/ExampleEntity/ExampleEntityRepository.php b/tests/Mocks/ExampleEntity/ExampleEntityRepository.php new file mode 100644 index 0000000..a2d58b5 --- /dev/null +++ b/tests/Mocks/ExampleEntity/ExampleEntityRepository.php @@ -0,0 +1,35 @@ +model->newQuery(); + $query = $this->applyCriteria($query, $criteria->toArray()); + + return $query + ->orderBy($orderDto->getOrderBy() ?? 'id', $orderDto->getOrder() ?? 'asc') + ->paginate($paginationDto->getLimit()); + } +} diff --git a/tests/Mocks/ExampleEntity/ExampleEntitySearchDto.php b/tests/Mocks/ExampleEntity/ExampleEntitySearchDto.php new file mode 100644 index 0000000..34cfa0b --- /dev/null +++ b/tests/Mocks/ExampleEntity/ExampleEntitySearchDto.php @@ -0,0 +1,53 @@ +get('name')) { + $criteria->push(new LikeCriterion('name', $request->get('name'))); + } + if ($request->get('status')) { + $criteria->push(new EqualCriterion('status', $request->get('status'))); + } + if ($request->get('gt_created_at')) { + $criteria->push(new DateCriterion( + 'created_at', + new Carbon($request->get($request->get('gt_created_at'))), + '>' + )); + } + if ($request->get('from') || $request->get('to')) { + $criteria->push(new PeriodCriterion( + new Carbon($request->get('from') ?? 0), + new Carbon($request->get('to') ?? null), + 'date_time' + )); + } + if ($request->get('ids')) { + $criteria->push(new InCriterion('id', $request->get('ids'))); + } + if ($request->get('nullable')) { + $criteria->push(new IsNullCriterion('description', $request->get('nullable'))); + } + + return new static($criteria); + } +} diff --git a/tests/Mocks/ExampleEntity/ExampleEntityService.php b/tests/Mocks/ExampleEntity/ExampleEntityService.php new file mode 100644 index 0000000..001ad54 --- /dev/null +++ b/tests/Mocks/ExampleEntity/ExampleEntityService.php @@ -0,0 +1,36 @@ +repository = $repository; + } + + public function getByPeriod(PeriodDto $periodDto): Collection + { + return $this->repository->searchByCriteria([ + new PeriodCriterion($periodDto->from(), $periodDto->to(), 'date_time') + ]); + } + + public function getExampleEntities(ExampleEntitySearchDto $searchDto, PaginationDto $paginationDto, OrderDto $orderDto): LengthAwarePaginator + { + return $this->repository->searchAndPaginateByCriteria( + $searchDto, + $paginationDto, + $orderDto + ); + } +} diff --git a/tests/Mocks/ExampleEntity/ExampleEntityServiceProvider.php b/tests/Mocks/ExampleEntity/ExampleEntityServiceProvider.php new file mode 100644 index 0000000..383954e --- /dev/null +++ b/tests/Mocks/ExampleEntity/ExampleEntityServiceProvider.php @@ -0,0 +1,13 @@ +loadRoutesFrom(__DIR__ . '/routes.php'); + } +} diff --git a/tests/Mocks/ExampleEntity/TestCase.php b/tests/Mocks/ExampleEntity/TestCase.php new file mode 100644 index 0000000..43d316d --- /dev/null +++ b/tests/Mocks/ExampleEntity/TestCase.php @@ -0,0 +1,22 @@ + 'api/core'], function () { + Route::get('/', [ExampleEntityController::class, 'index']); + Route::get('/period', [ExampleEntityController::class, 'period']); +});