From c7c2dc653968cf0c649499a91c98c410f6757cc7 Mon Sep 17 00:00:00 2001 From: barbosa89 Date: Tue, 31 Mar 2026 21:18:23 +0000 Subject: [PATCH] fix: enhance insertGetId handling for zero return values and improve model ID assignment --- src/Database/Models/DatabaseModel.php | 16 +++--- .../QueryBuilders/DatabaseQueryBuilder.php | 8 +-- tests/Feature/Database/DatabaseModelTest.php | 55 +++++++++++++++++++ 3 files changed, 67 insertions(+), 12 deletions(-) diff --git a/src/Database/Models/DatabaseModel.php b/src/Database/Models/DatabaseModel.php index 83852c61..ce844d81 100644 --- a/src/Database/Models/DatabaseModel.php +++ b/src/Database/Models/DatabaseModel.php @@ -177,17 +177,17 @@ public function save(TransactionManager|null $transactionManager = null): bool $result = $queryBuilder ->insertGetId($data, $this->getModelKeyColumnName()); - if ($result) { - if (! $this->keyIsInitialized()) { - $this->{$this->getModelKeyName()} = $result; - } - - $this->setAsExisting(); + if ($result === false) { + return false; + } - return true; + if (! $this->keyIsInitialized() && $result !== null) { + $this->{$this->getModelKeyName()} = $result; } - return false; + $this->setAsExisting(); + + return true; } public function delete(TransactionManager|null $transactionManager = null): bool diff --git a/src/Database/Models/QueryBuilders/DatabaseQueryBuilder.php b/src/Database/Models/QueryBuilders/DatabaseQueryBuilder.php index 3a7c3ed8..e3f25e50 100644 --- a/src/Database/Models/QueryBuilders/DatabaseQueryBuilder.php +++ b/src/Database/Models/QueryBuilders/DatabaseQueryBuilder.php @@ -204,12 +204,12 @@ public function create(array $attributes): DatabaseModel $queryBuilder = clone $this; $queryBuilder->setModel($model); + $modelKeyName = $model->getModelKeyName(); + $keyWasInitialized = isset($model->{$modelKeyName}); $result = $queryBuilder->insertGetId($data, $model->getModelKeyColumnName()); - if ($result) { - $modelKeyName = $model->getModelKeyName(); - - if (! isset($model->{$modelKeyName})) { + if ($result !== false && ($keyWasInitialized || $result !== null)) { + if (! $keyWasInitialized) { $model->{$modelKeyName} = $result; } diff --git a/tests/Feature/Database/DatabaseModelTest.php b/tests/Feature/Database/DatabaseModelTest.php index c81eeeaf..b36da7ed 100644 --- a/tests/Feature/Database/DatabaseModelTest.php +++ b/tests/Feature/Database/DatabaseModelTest.php @@ -783,6 +783,34 @@ expect($model->createdAt)->toBeInstanceOf(Date::class); }); +it('creates model with manually assigned string ID when insertGetId returns zero', function () { + $insertResult = new Result([['Query OK']]); + $insertResult->setLastInsertedId(0); + + $connection = $this->getMockBuilder(MysqlConnectionPool::class)->getMock(); + + $connection->expects($this->exactly(1)) + ->method('prepare') + ->willReturnOnConsecutiveCalls( + new Statement($insertResult), + ); + + $this->app->swap(Connection::default(), $connection); + + $uuid = Str::uuid()->toString(); + + $model = UserWithUuid::create([ + 'id' => $uuid, + 'name' => 'John Doe', + 'email' => faker()->email(), + 'created_at' => Date::now(), + ]); + + expect($model->isExisting())->toBeTrue(); + expect($model->id)->toBe($uuid); + expect($model->createdAt)->toBeInstanceOf(Date::class); +}); + it('throws an exception when column in invalid on create instance', function () { expect(function () { $connection = $this->getMockBuilder(MysqlConnectionPool::class)->getMock(); @@ -895,6 +923,33 @@ expect($model->createdAt)->toBeInstanceOf(Date::class); }); +it('saves a new model with manually assigned string ID when insertGetId returns zero', function () { + $insertResult = new Result([['Query OK']]); + $insertResult->setLastInsertedId(0); + + $connection = $this->getMockBuilder(MysqlConnectionPool::class)->getMock(); + + $connection->expects($this->exactly(1)) + ->method('prepare') + ->willReturnOnConsecutiveCalls( + new Statement($insertResult), + ); + + $this->app->swap(Connection::default(), $connection); + + $uuid = Str::uuid()->toString(); + $model = new UserWithUuid(); + $model->id = $uuid; + $model->name = 'John Doe'; + $model->email = faker()->email(); + + expect($model->isExisting())->toBeFalse(); + expect($model->save())->toBeTrue(); + expect($model->isExisting())->toBeTrue(); + expect($model->id)->toBe($uuid); + expect($model->createdAt)->toBeInstanceOf(Date::class); +}); + it('updates an existing model with string ID correctly', function () { $uuid = Str::uuid()->toString(); $data = [