packages/ztd-query-mysqli-adapter/tests/Unit/Session/StatementExecutionTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Session;
6
7use Container\MySql80Container;
8use Container\MySql84Container;
9use mysqli;
10use mysqli_result;
11use mysqli_stmt;
12use PHPUnit\Framework\Attributes\CoversClass;
13use PHPUnit\Framework\Attributes\Large;
14use PHPUnit\Framework\Attributes\UsesClass;
15use PHPUnit\Framework\TestCase;
16use Testcontainers\Testcontainers;
17use ZtdQuery\Adapter\Mysqli\Driver\MysqliConnection;
18use ZtdQuery\Adapter\Mysqli\Driver\MysqliResultColumnExtractor;
19use ZtdQuery\Adapter\Mysqli\Driver\MysqliResultStatement;
20use ZtdQuery\Adapter\Mysqli\Session\ConnectionExecution;
21use ZtdQuery\Adapter\Mysqli\Session\MysqliResultProcessor;
22use ZtdQuery\Adapter\Mysqli\Session\StatementExecution;
23use ZtdQuery\Adapter\Mysqli\ZtdMysqliException;
24
25#[CoversClass(StatementExecution::class)]
26#[Large]
27#[UsesClass(MysqliConnection::class)]
28#[UsesClass(MysqliResultStatement::class)]
29#[UsesClass(MysqliResultColumnExtractor::class)]
30#[UsesClass(MysqliResultProcessor::class)]
31#[UsesClass(ZtdMysqliException::class)]
32#[UsesClass(ConnectionExecution::class)]
33final class StatementExecutionTest extends TestCase
34{
35 public function testNativeReturnsThePreparedStatement(): void
36 {
37 $container = Testcontainers::run(getenv('MYSQL_VERSION') === '8.4.7' ? MySql84Container::class : MySql80Container::class);
38 try {
39 $native = new mysqli(str_replace('localhost', '127.0.0.1', $container->getHost()), 'root', 'root', 'test', $container->getMappedPort(3306));
40 $native->set_charset('utf8mb4');
41 $native->query('CREATE TABLE items (id INT PRIMARY KEY)');
42 $session = (new ConnectionExecution($native))->session();
43 $plan = $session->rewrite('INSERT INTO items VALUES (7)');
44 $statement = $native->prepare($plan->sql());
45 self::assertInstanceOf(mysqli_stmt::class, $statement);
46 $execution = new StatementExecution($statement, $session, $plan);
47
48 self::assertSame($statement, $execution->native());
49 } finally {
50 $container->stop();
51 }
52 }
53
54 public function testResultTracksSimulatedWrites(): void
55 {
56 $container = Testcontainers::run(getenv('MYSQL_VERSION') === '8.4.7' ? MySql84Container::class : MySql80Container::class);
57 try {
58 $native = new mysqli(str_replace('localhost', '127.0.0.1', $container->getHost()), 'root', 'root', 'test', $container->getMappedPort(3306));
59 $native->set_charset('utf8mb4');
60 $native->query('CREATE TABLE items (id INT PRIMARY KEY)');
61 $session = (new ConnectionExecution($native))->session();
62 $plan = $session->rewrite('INSERT INTO items VALUES (7)');
63 $statement = $native->prepare($plan->sql());
64 self::assertInstanceOf(mysqli_stmt::class, $statement);
65 $execution = new StatementExecution($statement, $session, $plan);
66
67 self::assertNull($execution->result());
68 self::assertTrue($execution->execute());
69 self::assertNotNull($execution->result());
70 self::assertSame(1, $execution->result()->rowCount());
71 } finally {
72 $container->stop();
73 }
74 }
75
76 public function testAffectedRowsReturnsTheSimulatedCount(): void
77 {
78 $container = Testcontainers::run(getenv('MYSQL_VERSION') === '8.4.7' ? MySql84Container::class : MySql80Container::class);
79 try {
80 $native = new mysqli(str_replace('localhost', '127.0.0.1', $container->getHost()), 'root', 'root', 'test', $container->getMappedPort(3306));
81 $native->set_charset('utf8mb4');
82 $native->query('CREATE TABLE items (id INT PRIMARY KEY)');
83 $session = (new ConnectionExecution($native))->session();
84 $plan = $session->rewrite('INSERT INTO items VALUES (7)');
85 $statement = $native->prepare($plan->sql());
86 self::assertInstanceOf(mysqli_stmt::class, $statement);
87 $execution = new StatementExecution($statement, $session, $plan);
88
89 self::assertTrue($execution->execute());
90 self::assertSame(1, $execution->affectedRows());
91 } finally {
92 $container->stop();
93 }
94 }
95
96 public function testExecuteDoesNotWriteThePhysicalTable(): void
97 {
98 $container = Testcontainers::run(getenv('MYSQL_VERSION') === '8.4.7' ? MySql84Container::class : MySql80Container::class);
99 try {
100 $native = new mysqli(str_replace('localhost', '127.0.0.1', $container->getHost()), 'root', 'root', 'test', $container->getMappedPort(3306));
101 $native->set_charset('utf8mb4');
102 $native->query('CREATE TABLE items (id INT PRIMARY KEY)');
103 $session = (new ConnectionExecution($native))->session();
104 $plan = $session->rewrite('INSERT INTO items VALUES (7)');
105 $statement = $native->prepare($plan->sql());
106 self::assertInstanceOf(mysqli_stmt::class, $statement);
107 $execution = new StatementExecution($statement, $session, $plan);
108
109 self::assertTrue($execution->execute());
110 $result = $native->query('SELECT COUNT(*) FROM items');
111 self::assertInstanceOf(mysqli_result::class, $result);
112 self::assertSame(['0'], $result->fetch_row());
113 } finally {
114 $container->stop();
115 }
116 }
117
118 public function testGetResultReturnsTheBufferedSelect(): void
119 {
120 $container = Testcontainers::run(getenv('MYSQL_VERSION') === '8.4.7' ? MySql84Container::class : MySql80Container::class);
121 try {
122 $native = new mysqli(str_replace('localhost', '127.0.0.1', $container->getHost()), 'root', 'root', 'test', $container->getMappedPort(3306));
123 $native->set_charset('utf8mb4');
124 $native->query('CREATE TABLE items (id INT PRIMARY KEY)');
125 $session = (new ConnectionExecution($native))->session();
126 $plan = $session->rewrite('SELECT 7 AS id');
127 $statement = $native->prepare($plan->sql());
128 self::assertInstanceOf(mysqli_stmt::class, $statement);
129 $execution = new StatementExecution($statement, $session, $plan);
130
131 self::assertTrue($execution->execute());
132 $result = $execution->getResult();
133 self::assertInstanceOf(mysqli_result::class, $result);
134 self::assertSame([['id' => 7]], $result->fetch_all(MYSQLI_ASSOC));
135 } finally {
136 $container->stop();
137 }
138 }
139
140 public function testFetchReturnsNullForAWritingStatement(): void
141 {
142 $container = Testcontainers::run(getenv('MYSQL_VERSION') === '8.4.7' ? MySql84Container::class : MySql80Container::class);
143 try {
144 $native = new mysqli(str_replace('localhost', '127.0.0.1', $container->getHost()), 'root', 'root', 'test', $container->getMappedPort(3306));
145 $native->set_charset('utf8mb4');
146 $native->query('CREATE TABLE items (id INT PRIMARY KEY)');
147 $session = (new ConnectionExecution($native))->session();
148 $plan = $session->rewrite('INSERT INTO items VALUES (7)');
149 $statement = $native->prepare($plan->sql());
150 self::assertInstanceOf(mysqli_stmt::class, $statement);
151 $execution = new StatementExecution($statement, $session, $plan);
152
153 self::assertTrue($execution->execute());
154 self::assertNull($execution->fetch());
155 } finally {
156 $container->stop();
157 }
158 }
159
160 public function testResetDiscardsTheSimulatedResult(): void
161 {
162 $container = Testcontainers::run(getenv('MYSQL_VERSION') === '8.4.7' ? MySql84Container::class : MySql80Container::class);
163 try {
164 $native = new mysqli(str_replace('localhost', '127.0.0.1', $container->getHost()), 'root', 'root', 'test', $container->getMappedPort(3306));
165 $native->set_charset('utf8mb4');
166 $native->query('CREATE TABLE items (id INT PRIMARY KEY)');
167 $session = (new ConnectionExecution($native))->session();
168 $plan = $session->rewrite('INSERT INTO items VALUES (7)');
169 $statement = $native->prepare($plan->sql());
170 self::assertInstanceOf(mysqli_stmt::class, $statement);
171 $execution = new StatementExecution($statement, $session, $plan);
172
173 self::assertTrue($execution->execute());
174 self::assertNotNull($execution->result());
175 self::assertTrue($execution->reset());
176 self::assertNull($execution->result());
177 } finally {
178 $container->stop();
179 }
180 }
181
182}
183