From 585bf62fc8158faf1c0602e7300a7ff8d29efa67 Mon Sep 17 00:00:00 2001 From: gam6itko Date: Mon, 29 Jan 2024 19:16:27 +0300 Subject: [PATCH] delete-insert with unique key --- CONTRIBUTING.md | 2 +- phpunit.xml | 4 +- .../Common/Integration/Issue380/CaseTest.php | 125 +++++++++++++++--- .../Integration/Issue380/Entity/User.php | 2 +- .../Issue380/Entity/User/Alias.php | 4 +- .../Issue380/Entity/User/Email.php | 4 +- .../Issue380/Entity/User/Phone.php | 4 +- .../Common/Integration/Issue380/schema.php | 6 +- .../MySQL/Integration/Issue380/CaseTest.php | 2 +- .../Integration/Issue380/CaseTest.php | 2 +- .../Integration/Issue380/CaseTest.php | 2 +- .../SQLite/Integration/Issue380/CaseTest.php | 2 +- 12 files changed, 123 insertions(+), 36 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e60f0b8e..4bb3037f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,7 +26,7 @@ $ ./vendor/bin/phpunit To run quick test suite: ```bash -$ ./vendor/bin/phpunit tests/ORM/Driver/SQLite +$ ./vendor/bin/phpunit tests/ORM/Functional/Driver/SQLite ``` ## Help Needed In diff --git a/phpunit.xml b/phpunit.xml index bbc40674..7ed98adb 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -11,8 +11,8 @@ convertWarningsToExceptions="true" convertDeprecationsToExceptions="true" processIsolation="false" - stopOnFailure="true" - stopOnError="true" + stopOnFailure="false" + stopOnError="false" > diff --git a/tests/ORM/Functional/Driver/Common/Integration/Issue380/CaseTest.php b/tests/ORM/Functional/Driver/Common/Integration/Issue380/CaseTest.php index 5947605a..88262639 100644 --- a/tests/ORM/Functional/Driver/Common/Integration/Issue380/CaseTest.php +++ b/tests/ORM/Functional/Driver/Common/Integration/Issue380/CaseTest.php @@ -2,12 +2,13 @@ declare(strict_types=1); -namespace Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4; +namespace Cycle\ORM\Tests\Functional\Driver\Common\Integration\Issue380; +use Cycle\Database\Exception\StatementException\ConstrainException; use Cycle\ORM\EntityManager; use Cycle\ORM\Tests\Functional\Driver\Common\BaseTest; -use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\Entity\User; use Cycle\ORM\Tests\Functional\Driver\Common\Integration\IntegrationTestTrait; +use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Issue380\Entity\User; use Cycle\ORM\Tests\Traits\TableTrait; abstract class CaseTest extends BaseTest @@ -22,10 +23,10 @@ public function setUp(): void $this->makeTables(); $this->fillData(); - $this->loadSchema(__DIR__.'/schema.php'); + $this->loadSchema(__DIR__ . '/schema.php'); } - public function testOnce(): void + public function testInsertOnce(): void { /** @var User $user */ $user = $this->orm->getRepository(User::class)->findOne(['id' => 1]); @@ -35,14 +36,14 @@ public function testOnce(): void $i = 0; - $em->persist(new User\Alias($user, (string) ++$i)); - $em->persist(new User\Alias($user, (string) ++$i)); + $em->persist(new User\Alias($user, (string)++$i)); + $em->persist(new User\Alias($user, (string)++$i)); - $em->persist(new User\Email($user, (string) ++$i)); - $em->persist(new User\Email($user, (string) ++$i)); + $em->persist(new User\Email($user, (string)++$i)); + $em->persist(new User\Email($user, (string)++$i)); - $em->persist(new User\Phone($user, (string) ++$i)); - $em->persist(new User\Phone($user, (string) ++$i)); + $em->persist(new User\Phone($user, (string)++$i)); + $em->persist(new User\Phone($user, (string)++$i)); $em->run(); @@ -72,7 +73,7 @@ public function testOnce(): void /** * @dataProvider dataMatrix */ - public function testMatrix(int $cnt1, int $cnt2, int $cnt3): void + public function testInsertMatrix(int $cnt1, int $cnt2, int $cnt3): void { /** @var User $user */ $user = $this->orm->getRepository(User::class)->findOne(['id' => 1]); @@ -84,17 +85,17 @@ public function testMatrix(int $cnt1, int $cnt2, int $cnt3): void $expected = []; for ($id = 1; $id <= $cnt1; $id++) { - $em->persist(new User\Alias($user, $v = (string) ++$i)); + $em->persist(new User\Alias($user, $v = (string)++$i)); $expected['alias'][] = ['id' => $id, 'value' => $v]; } for ($id = 1; $id <= $cnt2; $id++) { - $em->persist(new User\Email($user, $v = (string) ++$i)); + $em->persist(new User\Email($user, $v = (string)++$i)); $expected['email'][] = ['id' => $id, 'value' => $v]; } for ($id = 1; $id <= $cnt3; $id++) { - $em->persist(new User\Phone($user, $v = (string) ++$i)); + $em->persist(new User\Phone($user, $v = (string)++$i)); $expected['phone'][] = ['id' => $id, 'value' => $v]; } $em->run(); @@ -116,13 +117,100 @@ public function dataMatrix(): iterable yield [1, 7, 4]; } + public function testFailOnInsertUniqueDuplicate(): void + { + self::expectException(ConstrainException::class); + + /** @var User $user */ + $user = $this->orm->getRepository(User::class)->findOne(['id' => 1]); + + // insert unique + $em = (new EntityManager($this->orm)); + $em->persist($user); + $em + ->persist(new User\Alias($user, '1')) + ->persist(new User\Alias($user, '1')) + ->run(); + } + + public function testDeleteAndInsertFainOnDuplicateUniqueKey(): void + { + /** @var User $user */ + $user = $this->orm->getRepository(User::class)->findOne(['id' => 1]); + + // insert unique + $em = (new EntityManager($this->orm)); + $em->persist($user); + $em + ->persist($a0 = new User\Alias($user, '1')) + ->persist($a1 = new User\Alias($user, '2')); + $em + ->persist($e0 = new User\Email($user, '1')) + ->persist($e1 = new User\Email($user, '2')); + $em + ->persist($p0 = new User\Phone($user, '1')) + ->persist($p1 = new User\Phone($user, '2')); + $em->run(); + + self::assertCount(2, \array_intersect([1, 2], [$a0->id, $a1->id])); + self::assertCount(2, \array_intersect([1, 2], [$e0->id, $e1->id])); + self::assertCount(2, \array_intersect([1, 2], [$p0->id, $p1->id])); + unset($a0, $a1, $e0, $e1, $p0, $p1); + + $this->orm->getHeap()->clean(); + + // delete old and persist new with same unique value + $em = (new EntityManager($this->orm)); + + /** @var User $user */ + $user = $this->orm->getRepository(User::class)->findOne(['id' => 1]); + $user->username = 'up-username'; + $em->persist($user); + + $a0 = $this->orm->get(User\Alias::class, ['id' => 1]); + $a1 = $this->orm->get(User\Alias::class, ['id' => 2]); + + $e0 = $this->orm->get(User\Email::class, ['id' => 1]); + $e1 = $this->orm->get(User\Email::class, ['id' => 2]); + + $p0 = $this->orm->get(User\Phone::class, ['id' => 1]); + $p1 = $this->orm->get(User\Phone::class, ['id' => 2]); + + $em + ->delete($a0) + ->delete($a1); + $em + ->persist(new User\Alias($user, '1')) + ->persist(new User\Alias($user, '2')); + $em + ->delete($e0) + ->delete($e1); + $em + ->persist(new User\Email($user, '1')) + ->persist(new User\Email($user, '2')); + $em + ->delete($p0) + ->delete($p1); + $em + ->persist(new User\Phone($user, '1')) + ->persist(new User\Phone($user, '2')); + + $em->run(); + + self::assertTrue(true); + } + private function fetchFromTable(string $tableName): array { $db = $this->orm->getSource(User::class)->getDatabase(); - $rows = $db->select('id', 'value')->from($tableName)->orderBy('id')->fetchAll(); + $rows = $db + ->select('id', 'value') + ->from($tableName) + ->orderBy('id') + ->fetchAll(); // cast id to int specially for mssql - return array_map(function (array $row): array { - $row['id'] = (int) $row['id']; + return \array_map(function (array $row): array { + $row['id'] = (int)$row['id']; return $row; }, $rows); } @@ -142,6 +230,7 @@ private function makeTables(): void 'user_id' => 'int', ]); $this->makeFK('user_alias', 'user_id', 'user', 'id', 'NO ACTION', 'NO ACTION'); + $this->makeIndex('user_alias', ['value'], true); $this->makeTable('user_email', [ 'id' => 'primary', @@ -149,6 +238,7 @@ private function makeTables(): void 'user_id' => 'int', ]); $this->makeFK('user_email', 'user_id', 'user', 'id', 'NO ACTION', 'NO ACTION'); + $this->makeIndex('user_email', ['value'], true); $this->makeTable('user_phone', [ 'id' => 'primary', @@ -156,6 +246,7 @@ private function makeTables(): void 'user_id' => 'int', ]); $this->makeFK('user_phone', 'user_id', 'user', 'id', 'NO ACTION', 'NO ACTION'); + $this->makeIndex('user_phone', ['value'], true); } private function fillData(): void diff --git a/tests/ORM/Functional/Driver/Common/Integration/Issue380/Entity/User.php b/tests/ORM/Functional/Driver/Common/Integration/Issue380/Entity/User.php index bd7f9ef5..89750e5c 100644 --- a/tests/ORM/Functional/Driver/Common/Integration/Issue380/Entity/User.php +++ b/tests/ORM/Functional/Driver/Common/Integration/Issue380/Entity/User.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\Entity; +namespace Cycle\ORM\Tests\Functional\Driver\Common\Integration\Issue380\Entity; class User { diff --git a/tests/ORM/Functional/Driver/Common/Integration/Issue380/Entity/User/Alias.php b/tests/ORM/Functional/Driver/Common/Integration/Issue380/Entity/User/Alias.php index 8c40aea3..f99924a6 100644 --- a/tests/ORM/Functional/Driver/Common/Integration/Issue380/Entity/User/Alias.php +++ b/tests/ORM/Functional/Driver/Common/Integration/Issue380/Entity/User/Alias.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\Entity\User; +namespace Cycle\ORM\Tests\Functional\Driver\Common\Integration\Issue380\Entity\User; -use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\Entity\User; +use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Issue380\Entity\User; class Alias { diff --git a/tests/ORM/Functional/Driver/Common/Integration/Issue380/Entity/User/Email.php b/tests/ORM/Functional/Driver/Common/Integration/Issue380/Entity/User/Email.php index 1840392d..ae020fc0 100644 --- a/tests/ORM/Functional/Driver/Common/Integration/Issue380/Entity/User/Email.php +++ b/tests/ORM/Functional/Driver/Common/Integration/Issue380/Entity/User/Email.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\Entity\User; +namespace Cycle\ORM\Tests\Functional\Driver\Common\Integration\Issue380\Entity\User; -use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\Entity\User; +use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Issue380\Entity\User; class Email { diff --git a/tests/ORM/Functional/Driver/Common/Integration/Issue380/Entity/User/Phone.php b/tests/ORM/Functional/Driver/Common/Integration/Issue380/Entity/User/Phone.php index b0b87993..afa73a30 100644 --- a/tests/ORM/Functional/Driver/Common/Integration/Issue380/Entity/User/Phone.php +++ b/tests/ORM/Functional/Driver/Common/Integration/Issue380/Entity/User/Phone.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\Entity\User; +namespace Cycle\ORM\Tests\Functional\Driver\Common\Integration\Issue380\Entity\User; -use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\Entity\User; +use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Issue380\Entity\User; class Phone { diff --git a/tests/ORM/Functional/Driver/Common/Integration/Issue380/schema.php b/tests/ORM/Functional/Driver/Common/Integration/Issue380/schema.php index 20fac7a6..3762a923 100644 --- a/tests/ORM/Functional/Driver/Common/Integration/Issue380/schema.php +++ b/tests/ORM/Functional/Driver/Common/Integration/Issue380/schema.php @@ -7,11 +7,7 @@ use Cycle\ORM\SchemaInterface as Schema; use Cycle\ORM\Select\Repository; use Cycle\ORM\Select\Source; -use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\Entity\Comment; -use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\Entity\Post; -use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\Entity\PostTag; -use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\Entity\Tag; -use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\Entity\User; +use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Issue380\Entity\User; return [ 'user' => [ diff --git a/tests/ORM/Functional/Driver/MySQL/Integration/Issue380/CaseTest.php b/tests/ORM/Functional/Driver/MySQL/Integration/Issue380/CaseTest.php index fff4a866..3e092646 100644 --- a/tests/ORM/Functional/Driver/MySQL/Integration/Issue380/CaseTest.php +++ b/tests/ORM/Functional/Driver/MySQL/Integration/Issue380/CaseTest.php @@ -5,7 +5,7 @@ namespace Cycle\ORM\Tests\Functional\Driver\MySQL\Integration\Issue380; // phpcs:ignore -use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\CaseTest as CommonClass; +use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Issue380\CaseTest as CommonClass; /** * @group driver diff --git a/tests/ORM/Functional/Driver/Postgres/Integration/Issue380/CaseTest.php b/tests/ORM/Functional/Driver/Postgres/Integration/Issue380/CaseTest.php index 38d5ea62..9256dc9c 100644 --- a/tests/ORM/Functional/Driver/Postgres/Integration/Issue380/CaseTest.php +++ b/tests/ORM/Functional/Driver/Postgres/Integration/Issue380/CaseTest.php @@ -5,7 +5,7 @@ namespace Cycle\ORM\Tests\Functional\Driver\Postgres\Integration\Issue380; // phpcs:ignore -use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\CaseTest as CommonClass; +use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Issue380\CaseTest as CommonClass; /** * @group driver diff --git a/tests/ORM/Functional/Driver/SQLServer/Integration/Issue380/CaseTest.php b/tests/ORM/Functional/Driver/SQLServer/Integration/Issue380/CaseTest.php index aa0e4c0d..8f9066ae 100644 --- a/tests/ORM/Functional/Driver/SQLServer/Integration/Issue380/CaseTest.php +++ b/tests/ORM/Functional/Driver/SQLServer/Integration/Issue380/CaseTest.php @@ -5,7 +5,7 @@ namespace Cycle\ORM\Tests\Functional\Driver\SQLServer\Integration\Issue380; // phpcs:ignore -use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\CaseTest as CommonClass; +use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Issue380\CaseTest as CommonClass; /** * @group driver diff --git a/tests/ORM/Functional/Driver/SQLite/Integration/Issue380/CaseTest.php b/tests/ORM/Functional/Driver/SQLite/Integration/Issue380/CaseTest.php index d0eb647e..39a558f2 100644 --- a/tests/ORM/Functional/Driver/SQLite/Integration/Issue380/CaseTest.php +++ b/tests/ORM/Functional/Driver/SQLite/Integration/Issue380/CaseTest.php @@ -5,7 +5,7 @@ namespace Cycle\ORM\Tests\Functional\Driver\SQLite\Integration\Issue380; // phpcs:ignore -use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\CaseTest as CommonClass; +use Cycle\ORM\Tests\Functional\Driver\Common\Integration\Case4\Issue380 as CommonClass; /** * @group driver