From 02f9cff8a8d961d1b4a9697e99000a0da212c9d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Mat=C4=9Bj=C4=8Dek?= Date: Thu, 2 Jan 2025 12:24:13 +0100 Subject: [PATCH] feat(AbstractEloquentQuery): add method firstOrFail --- .../Queries/AbstractEloquentQuery.php | 24 +++++++++++--- src/Database/Scopes/AbstractInScope.php | 4 ++- src/Database/Scopes/WhereIdsScope.php | 7 +++-- .../Queries/AbstractEloquentQueryTest.php | 31 +++++++++++++++++-- .../Database/Scopes/WhereIdsScopeTest.php | 15 +++++---- 5 files changed, 65 insertions(+), 16 deletions(-) diff --git a/src/Database/Queries/AbstractEloquentQuery.php b/src/Database/Queries/AbstractEloquentQuery.php index 4b82200a..2993b371 100644 --- a/src/Database/Queries/AbstractEloquentQuery.php +++ b/src/Database/Queries/AbstractEloquentQuery.php @@ -13,6 +13,7 @@ use Illuminate\Database\Eloquent\Scope; use Illuminate\Support\Arr; use LaraStrict\Database\Scopes\OrderScope; +use LaraStrict\Database\Scopes\WhereIdsScope; use Throwable; /** @@ -151,17 +152,31 @@ protected function find(string|int $id, array $scopes = []): ?Model /** * @template TException of Throwable - * @param array $scopes - * @param Closure(int|string):TException|TException|null $customException Creates a custom exceptions if model does + * @param array $scopes + * @param Closure(int|string):TException|TException|null $customException Creates a custom exceptions if model does * not exists. Receives $id argument. * @return TModel */ protected function findOrFail(string|int $key, array $scopes = [], Closure|Throwable $customException = null): Model + { + $scopes[] = new WhereIdsScope($key); + + return $this->firstOrFail($scopes, $customException); + } + + /** + * @template TException of Throwable + * @param array $scopes + * @param Closure(int|string):TException|TException|null $customException Creates a custom exceptions if model does + * not exists. Receives $id argument. + * @return TModel + */ + protected function firstOrFail(array $scopes = [], Closure|Throwable $customException = null): Model { try { /** @var TModel $model */ $model = $this->getQuery($scopes) - ->findOrFail($key); + ->firstOrFail(); return $model; } catch (ModelNotFoundException $modelNotFoundException) { @@ -170,7 +185,8 @@ protected function findOrFail(string|int $key, array $scopes = [], Closure|Throw } elseif ($customException instanceof Throwable) { throw $customException; } - throw $customException($key); + + throw $customException($modelNotFoundException->getMessage()); } } diff --git a/src/Database/Scopes/AbstractInScope.php b/src/Database/Scopes/AbstractInScope.php index 2b1c29d1..0d36c825 100644 --- a/src/Database/Scopes/AbstractInScope.php +++ b/src/Database/Scopes/AbstractInScope.php @@ -50,7 +50,9 @@ public function __construct( public function apply(Builder $builder, Model $model): void { - $column = $this->table === '' ? $this->getColumn($model) : $this->table . '.' . $this->getColumn($model); + $table = $this->table === '' ? $model->getTable() : $this->table; + $column = sprintf('%s.', $table) . $this->getColumn($model); + if (is_array($this->values) && count($this->values) === 1) { $this->values = reset($this->values); } diff --git a/src/Database/Scopes/WhereIdsScope.php b/src/Database/Scopes/WhereIdsScope.php index 08afd0a2..e167fc90 100644 --- a/src/Database/Scopes/WhereIdsScope.php +++ b/src/Database/Scopes/WhereIdsScope.php @@ -9,13 +9,16 @@ class WhereIdsScope extends AbstractInScope { + /** + * @param array|array|int|string $ids + */ public function __construct( - array|int $ids, + array|int|string $ids, private readonly ?string $key = null, #[Deprecated(reason: 'Use right parameter instead of this magic.')] string|bool|null $booleanOrTableOrNot = null, string $table = '', - bool $not = false + bool $not = false, ) { parent::__construct($ids, $booleanOrTableOrNot, $table, $not); } diff --git a/tests/Feature/Database/Queries/AbstractEloquentQueryTest.php b/tests/Feature/Database/Queries/AbstractEloquentQueryTest.php index df15cf11..e9354e8a 100644 --- a/tests/Feature/Database/Queries/AbstractEloquentQueryTest.php +++ b/tests/Feature/Database/Queries/AbstractEloquentQueryTest.php @@ -5,12 +5,17 @@ namespace Tests\LaraStrict\Feature\Database\Queries; use Closure; +use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Scope; +use LaraStrict\Database\Scopes\WhereIdsScope; +use LaraStrict\Tests\Traits\SqlTestEnable; use Tests\LaraStrict\Feature\Database\Models\Scopes\TestScope; use Tests\LaraStrict\Feature\TestCase; class AbstractEloquentQueryTest extends TestCase { + use SqlTestEnable; + public function dataScopes(): array { return [ @@ -18,21 +23,21 @@ public function dataScopes(): array static fn (self $self, string $class) => $self->assertScopes( expectedSql: 'select * from "tests" where "tests"."deleted_at" is null', scopes: [], - class: $class + class: $class, ), ], 'null' => [ static fn (self $self, string $class) => $self->assertScopes( expectedSql: 'select * from "tests" where "tests"."deleted_at" is null', scopes: [null], - class: $class + class: $class, ), ], 'null and test scope' => [ static fn (self $self, string $class) => $self->assertScopes( expectedSql: 'select * from "tests" where "test" = ? and "tests"."deleted_at" is null', scopes: [new TestScope(), null], - class: $class + class: $class, ), ], ]; @@ -67,4 +72,24 @@ public function testChunkScopes(Closure $assert): void { $assert($this, TestChunkSqlQuery::class); } + + public function testFindOrFail(): void + { + $this->assertSql(fn () => (new class() extends AbstractTestQuery { + public function execute(): Model + { + return $this->findOrFail(1); + } + })->execute(), 'select * from "tests" where "tests"."id" = 1 and "tests"."deleted_at" is null limit 1'); + } + + public function testFirstOrFail(): void + { + $this->assertSql(fn () => (new class() extends AbstractTestQuery { + public function execute(): Model + { + return $this->firstOrFail([new WhereIdsScope(2)]); + } + })->execute(), 'select * from "tests" where "tests"."id" = 2 and "tests"."deleted_at" is null limit 1'); + } } diff --git a/tests/Unit/Database/Scopes/WhereIdsScopeTest.php b/tests/Unit/Database/Scopes/WhereIdsScopeTest.php index a0292fc1..07c4d9cd 100644 --- a/tests/Unit/Database/Scopes/WhereIdsScopeTest.php +++ b/tests/Unit/Database/Scopes/WhereIdsScopeTest.php @@ -23,32 +23,35 @@ public static function data(): array return [ [ static function (self $self) { - $self->assert(new WhereIdsScope(1), 'select * from "test_models" where "id" = ?'); + $self->assert(new WhereIdsScope(1), 'select * from "test_models" where "test_models"."id" = ?'); }, ], [ static function (self $self) { - $self->assert(new WhereIdsScope([1]), 'select * from "test_models" where "id" = ?'); + $self->assert(new WhereIdsScope([1]), 'select * from "test_models" where "test_models"."id" = ?'); }, ], [ static function (self $self) { $self->assert( new WhereIdsScope([1], not: true), - 'select * from "test_models" where "id" != ?', + 'select * from "test_models" where "test_models"."id" != ?', ); }, ], [ static function (self $self) { - $self->assert(new WhereIdsScope([1, 2]), 'select * from "test_models" where "id" in (?, ?)'); + $self->assert( + new WhereIdsScope([1, 2]), + 'select * from "test_models" where "test_models"."id" in (?, ?)' + ); }, ], [ static function (self $self) { $self->assert( new WhereIdsScope([1, 2], 'foo'), - 'select * from "test_models" where "foo" in (?, ?)', + 'select * from "test_models" where "test_models"."foo" in (?, ?)', ); }, ], @@ -64,7 +67,7 @@ static function (self $self) { static function (self $self) { $self->assert( new WhereIdsScope([1, 2], not: true), - 'select * from "test_models" where "id" not in (?, ?)', + 'select * from "test_models" where "test_models"."id" not in (?, ?)', ); }, ],