From ab003199caa200327e3225bca66f1471d6631950 Mon Sep 17 00:00:00 2001 From: Maxim Smakouz Date: Thu, 28 Mar 2024 18:12:17 +0200 Subject: [PATCH] Fix caching for insert queries with fragments (#177) --- src/Driver/CompilerCache.php | 3 + .../Driver/Common/Query/InsertQueryTest.php | 89 +++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/src/Driver/CompilerCache.php b/src/Driver/CompilerCache.php index 7ca1ecf9..8c8d8cf7 100644 --- a/src/Driver/CompilerCache.php +++ b/src/Driver/CompilerCache.php @@ -122,6 +122,9 @@ protected function hashInsertQuery(QueryParameters $params, array $tokens): stri if ($value->isArray()) { foreach ($value->getValue() as $child) { if ($child instanceof FragmentInterface) { + if ($child instanceof \Stringable) { + $hash .= '_F_' . $child; + } continue; } diff --git a/tests/Database/Functional/Driver/Common/Query/InsertQueryTest.php b/tests/Database/Functional/Driver/Common/Query/InsertQueryTest.php index 3fc36f7b..e4085ab8 100644 --- a/tests/Database/Functional/Driver/Common/Query/InsertQueryTest.php +++ b/tests/Database/Functional/Driver/Common/Query/InsertQueryTest.php @@ -4,6 +4,10 @@ namespace Cycle\Database\Tests\Functional\Driver\Common\Query; +use Cycle\Database\Driver\CompilerInterface; +use Cycle\Database\Injection\Expression; +use Cycle\Database\Injection\Fragment; +use Cycle\Database\Injection\FragmentInterface; use Cycle\Database\Query\InsertQuery; use Cycle\Database\Tests\Functional\Driver\Common\BaseTest; @@ -99,4 +103,89 @@ public function testInsertMultipleRowsAsArray(): void $insert ); } + + public function testInsertWithExpressions(): void + { + $insert = $this->database->insert()->into('table')->values([ + 'name' => 'Anton', + 'updated_at' => new Expression('NOW()'), + 'deleted_at' => new Expression('NOW()'), + ]); + + $this->assertSameQuery( + 'INSERT INTO {table} ({name}, {updated_at}, {deleted_at}) VALUES (?, NOW(), NOW())', + $insert + ); + $this->assertSameParameters(['Anton'], $insert); + + $insert = $this->database->insert()->into('table')->values([ + 'name' => 'Anton', + 'updated_at' => new Expression('NOW()'), + 'deleted_at' => null, + ]); + + $this->assertSameQuery( + 'INSERT INTO {table} ({name}, {updated_at}, {deleted_at}) VALUES (?, NOW(), ?)', + $insert, + ); + $this->assertSameParameters(['Anton', null], $insert); + } + + public function testInsertWithFragmentsThatHaveDifferentStatements(): void + { + $insert = $this->database->insert()->into('table')->values([ + 'name' => 'Anton', + 'updated_at' => new Fragment('NOW()'), + 'deleted_at' => new Fragment('NOW()'), + ]); + + $this->assertSameQuery( + 'INSERT INTO {table} ({name}, {updated_at}, {deleted_at}) VALUES (?, NOW(), NOW())', + $insert + ); + + $insert = $this->database->insert()->into('table')->values([ + 'name' => 'Anton', + 'updated_at' => new Fragment('NOW()'), + 'deleted_at' => new Fragment('datetime(\'now\')'), + ]); + + $this->assertSameQuery( + 'INSERT INTO {table} ({name}, {updated_at}, {deleted_at}) VALUES (?, NOW(), datetime(\'now\'))', + $insert, + ); + } + + public function testInsertWithCustomFragment(): void + { + $fragment = $this->createMock(FragmentInterface::class); + $fragment->method('getType')->willReturn(CompilerInterface::FRAGMENT); + $fragment->method('getTokens')->willReturn([ + 'fragment' => 'NOW()', + 'parameters' => [], + ]); + + $insert = $this->database->insert()->into('table')->values([ + 'name' => 'Anton', + 'updated_at' => $fragment, + ]); + + $this->assertSameQuery( + 'INSERT INTO {table} ({name}, {updated_at}) VALUES (?, NOW())', + $insert + ); + $this->assertSameParameters(['Anton'], $insert); + + // cached query + $insert = $this->database->insert()->into('table')->values([ + 'name' => 'Anton', + 'updated_at' => $fragment, + ]); + + $this->assertSameQuery( + 'INSERT INTO {table} ({name}, {updated_at}) VALUES (?, NOW())', + $insert + ); + $this->assertSameParameters(['Anton'], $insert); + } }