Skip to content

Commit

Permalink
test(repository): add test
Browse files Browse the repository at this point in the history
  • Loading branch information
Mohammad-Alavi committed Mar 1, 2025
1 parent a07717e commit 1a2e767
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 27 deletions.
50 changes: 24 additions & 26 deletions src/Core/Repositories/Repository.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use Apiato\Core\Repositories\Exceptions\ResourceCreationFailed;
use Apiato\Core\Repositories\Exceptions\ResourceNotFound;
use Apiato\Http\Response;
use Apiato\Support\Facades\Response;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Contracts\Database\Query\Expression;
use Illuminate\Contracts\Support\Arrayable;
Expand Down Expand Up @@ -65,35 +65,38 @@ public function shouldEagerLoadIncludes(): bool
* Eager load relations if requested by the client via "include" query parameter.
* This is a workaround for incompatible third-party packages. (Fractal, L5Repo).
*
* TODO: Do we need to do the same for the excludes?
* TODO: Or default includes! Are they eager loaded by default?
* TODO: What if the include has parameters? e.g. include=books:limit(5|3)
*
* @see https://apiato.atlassian.net/browse/API-905
*/
public function eagerLoadRequestedIncludes(): void
{
$this->scopeQuery(function (Builder|Model $model) {
$this->scope(function (Builder|Model $model) {
if (request()?->has(config('fractal.auto_includes.request_key'))) {
$validIncludes = [];
// TODO: Do we need to do the same for the excludes?
// TODO: Or default includes! Are they eager loaded by default?
// TODO: What if the include has parameters? e.g. include=books:limit(5|3)
foreach (Response::getRequestedIncludes() as $includeName) {
$relationParts = explode('.', $includeName);
$camelCasedIncludeName = $this->filterInvalidRelations($this->model, $relationParts);
if ($camelCasedIncludeName) {
$validIncludes[] = $camelCasedIncludeName;
}
}

return $model->with($validIncludes);
return $model->with($this->getValidIncludes());
}

return $model;
});
}

/**
* TODO: rename this method or maybe keep the name but dont return null.
* Returning null causes multiple if() guard clauses as you can see.
* @return string[]
*/
public function getValidIncludes(): array
{
$validIncludes = array_filter(
array_map(
fn ($includeName) => $this->filterInvalidRelations($this->model, explode('.', $includeName)),
Response::getRequestedIncludes(),
),
);

return $validIncludes;
}

public function filterInvalidRelations(Builder|Model $model, array $relationParts): string|null
{
if ([] === $relationParts) {
Expand All @@ -114,21 +117,16 @@ public function filterInvalidRelations(Builder|Model $model, array $relationPart

$nextRelation = $this->filterInvalidRelations($nextModel, $relationParts);

if (is_null($nextRelation)) {
return null;
if (!is_null($nextRelation)) {
return $relation . '.' . $nextRelation;
}

return $relation . '.' . $nextRelation;
return null;
}

public function figureOutRelationName(string $includeName): string
{
return Str::of($includeName)
->replace('-', ' ')
->replace('_', ' ')
->title()
->replace(' ', '')
->camel();
return Str::of($includeName)->camel();
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/Http/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
*
* @see Fractal
*/
final class Response extends Fractal
class Response extends Fractal
{
/**
* Parse the Request's include query parameter and return the requested includes as model relations.
Expand Down
1 change: 1 addition & 0 deletions tests/Arch/CoreTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
'Apiato\Core',
'Apiato\Generator',
'Apiato\Support\Facades',
\Apiato\Http\Response::class,
]);

arch('src/abstract')
Expand Down
46 changes: 46 additions & 0 deletions tests/Unit/Core/Repositories/RepositoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Apiato\Core\Repositories\Exceptions\ResourceCreationFailed;
use Apiato\Core\Repositories\Exceptions\ResourceNotFound;
use Apiato\Core\Repositories\Repository;
use Apiato\Support\Facades\Response;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Pest\Expectation;
Expand Down Expand Up @@ -43,6 +44,51 @@ public function shouldEagerLoadIncludes(): bool
});
});
});

it('returns valid includes', function (array $requestedIncludes, array $expected) {
$repository = new UserRepository();
Response::shouldReceive('getRequestedIncludes')
->andReturn($requestedIncludes);

$result = $repository->getValidIncludes();

expect($result)->toBe($expected);
})->with([
[['books.author', 'parent.children.parent'], ['books.author', 'parent.children.parent']],
[['books.invalidRelation'], []],
[['invalidRelation'], []],
[[], []],
[['books'], ['books']],
]);

it('filters invalid relations correctly', function (array $relationParts, string|null $expected): void {
$repository = new UserRepository();
$model = new User();

$result = $repository->filterInvalidRelations($model, $relationParts);

expect($result)->toBe($expected);
})->with([
[['books', 'author'], 'books.author'],
[['books', 'invalidRelation'], null],
[['invalidRelation'], null],
[[], null],
[['parent'], 'parent'],
]);

it('converts include name to camel case', function (string $includeName, string $expected): void {
$repository = new UserRepository();

$result = $repository->figureOutRelationName($includeName);

expect($result)->toBe($expected);
})->with([
['user-profile', 'userProfile'],
['user_profile', 'userProfile'],
['user-profile_data', 'userProfileData'],
['', ''],
['user', 'user'],
]);
});

it('can add/remove request criteria', function (): void {
Expand Down

0 comments on commit 1a2e767

Please sign in to comment.