packages/ztd-query-pdo-adapter/tests/Unit/Session/PreparedQueryTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Session;
6
7use PDO;
8use PDOStatement;
9use PHPUnit\Framework\Attributes\CoversClass;
10use PHPUnit\Framework\Attributes\UsesClass;
11use PHPUnit\Framework\TestCase;
12use ZtdQuery\Adapter\Pdo\Driver\PdoConnection;
13use ZtdQuery\Adapter\Pdo\Session\PreparedQuery;
14use ZtdQuery\Adapter\Pdo\ZtdPdoException;
15use ZtdQuery\Config\ZtdConfig;
16use ZtdQuery\Platform\Sqlite\SqliteSessionFactory;
17
18#[CoversClass(PreparedQuery::class)]
19#[UsesClass(ZtdPdoException::class)]
20#[UsesClass(\ZtdQuery\Adapter\Pdo\ZtdPdoStatement::class)]
21#[UsesClass(\ZtdQuery\Adapter\Pdo\ZtdPdo::class)]
22#[UsesClass(PdoConnection::class)]
23#[UsesClass(\ZtdQuery\Adapter\Pdo\Driver\PdoStatement::class)]
24#[UsesClass(\ZtdQuery\Adapter\Pdo\Session\StatementExecution::class)]
25#[UsesClass(\ZtdQuery\Adapter\Pdo\Session\Bindings::class)]
26#[UsesClass(\ZtdQuery\Adapter\Pdo\Session\BufferedRow::class)]
27#[UsesClass(\ZtdQuery\Adapter\Pdo\Session\DriverSessionFactory::class)]
28#[UsesClass(\ZtdQuery\Adapter\Pdo\Session\ParameterKind::class)]
29#[UsesClass(\ZtdQuery\Adapter\Pdo\Session\ParameterBinder::class)]
30#[\PHPUnit\Framework\Attributes\Medium]
31#[UsesClass(\ZtdQuery\Adapter\Pdo\Session\ConnectionExecution::class)]
32final class PreparedQueryTest extends TestCase
33{
34    public function testRewriteUsesTheCurrentShadowOnEveryExecution(): void
35    {
36        $native = new PDO('sqlite::memory:');
37        $native->exec('CREATE TABLE items (id INTEGER PRIMARY KEY, value TEXT)');
38        $session = (new SqliteSessionFactory())->create(new PdoConnection($native), ZtdConfig::default());
39        $query = new PreparedQuery($session, 'SELECT value FROM items WHERE id = ?', static fn (string $sql): PDOStatement|false => $native->prepare($sql));
40        $session->execStatement("INSERT INTO items VALUES (1, 'before')");
41        $before = $query->prepare($query->rewrite()->sql());
42        self::assertTrue($before->execute([1]));
43        self::assertSame('before', $before->fetchColumn());
44        $session->execStatement("UPDATE items SET value = 'after' WHERE id = 1");
45        $after = $query->prepare($query->rewrite()->sql());
46        self::assertTrue($after->execute([1]));
47        self::assertSame('after', $after->fetchColumn());
48        $result1 = $native->query('SELECT COUNT(*) FROM items');
49        self::assertNotFalse($result1);
50        self::assertSame(0, $result1->fetchColumn());
51    }
52
53    public function testPrepareReportsASilentDriverFailure(): void
54    {
55        $native = new PDO('sqlite::memory:', options: [PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT]);
56        $session = (new SqliteSessionFactory())->create(new PdoConnection($native), ZtdConfig::default());
57        $query = new PreparedQuery($session, 'SELECT 1', static fn (string $sql): PDOStatement|false => $native->prepare($sql));
58        $this->expectException(ZtdPdoException::class);
59        $this->expectExceptionMessage('PDO failed to prepare rewritten SQL.');
60        $query->prepare('SELECT * FROM missing_table');
61    }
62}
63