packages/ztd-query-mysqli-adapter/tests/Unit/Driver/MysqliResultStatementTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Driver;
6
7use Container\Endpoint;
8use Container\MySqlRelease;
9use mysqli;
10use mysqli_result;
11use PHPUnit\Framework\Attributes\CoversClass;
12use PHPUnit\Framework\Attributes\Large;
13use PHPUnit\Framework\Attributes\UsesClass;
14use PHPUnit\Framework\TestCase;
15use Testcontainers\Testcontainers;
16use ZtdQuery\Adapter\Mysqli\Driver\MysqliResultColumnExtractor;
17use ZtdQuery\Adapter\Mysqli\Driver\MysqliResultStatement;
18use ZtdQuery\Platform\ResultColumnTypeResolver;
19use ZtdQuery\Schema\ColumnType;
20use ZtdQuery\Schema\ColumnTypeFamily;
21
22#[CoversClass(MysqliResultStatement::class)]
23#[Large]
24#[UsesClass(MysqliResultColumnExtractor::class)]
25final class MysqliResultStatementTest extends TestCase
26{
27    public function testExecuteRepresentsAWriteWithoutAResultSet(): void
28    {
29        $statement = new MysqliResultStatement(null, 2);
30        self::assertTrue($statement->execute());
31        self::assertTrue($statement->execute([1, 2]));
32        self::assertSame([], $statement->fetchAll());
33        self::assertSame(2, $statement->rowCount());
34        self::assertSame([], $statement->resultColumns(self::createStub(ResultColumnTypeResolver::class)));
35    }
36
37    public function testRowCountRetainsZeroAndLargeAffectedRowCounts(): void
38    {
39        self::assertSame(0, (new MysqliResultStatement(null, 0))->rowCount());
40        self::assertSame(PHP_INT_MAX, (new MysqliResultStatement(null, '999999999999999999999999999999'))->rowCount());
41    }
42
43    public function testFetchAllReadsNativeRowsWithoutLosingColumnNames(): void
44    {
45        $container = Testcontainers::run(MySqlRelease::fromEnvironment());
46        $endpoint = $container->getData(Endpoint::class);
47        try {
48            $connection = new mysqli($endpoint->host, $endpoint->username, $endpoint->password, $endpoint->database, $endpoint->port);
49            $connection->set_charset('utf8mb4');
50            $result = $connection->query("SELECT 1 AS id, 'Alice' AS name UNION ALL SELECT 2, 'Bob'");
51            self::assertInstanceOf(mysqli_result::class, $result);
52            $statement = new MysqliResultStatement($result, 2);
53            self::assertSame([['id' => '1', 'name' => 'Alice'], ['id' => '2', 'name' => 'Bob']], $statement->fetchAll());
54            self::assertSame(2, $statement->rowCount());
55            $connection->close();
56        } finally {
57            $container->stop();
58        }
59    }
60
61    public function testResultColumnsResolvesResultColumnTypes(): void
62    {
63        $container = Testcontainers::run(MySqlRelease::fromEnvironment());
64        $endpoint = $container->getData(Endpoint::class);
65        try {
66            $connection = new mysqli($endpoint->host, $endpoint->username, $endpoint->password, $endpoint->database, $endpoint->port);
67            $connection->set_charset('utf8mb4');
68            $result = $connection->query("SELECT 1 AS id, 'Alice' AS name");
69            self::assertInstanceOf(mysqli_result::class, $result);
70            $resolver = self::createStub(ResultColumnTypeResolver::class);
71            $resolver->method('resolve')->willReturnCallback(static fn (array $metadata): ColumnType =>
72                $metadata['name'] === 'id' ? new ColumnType(ColumnTypeFamily::INTEGER, 'INT') : new ColumnType(ColumnTypeFamily::STRING, 'VARCHAR'));
73            $columns = (new MysqliResultStatement($result, 1))->resultColumns($resolver);
74            self::assertSame(['id', 'name'], array_column($columns, 'name'));
75            self::assertSame(ColumnTypeFamily::INTEGER, $columns[0]->type->family);
76            self::assertSame(ColumnTypeFamily::STRING, $columns[1]->type->family);
77            $connection->close();
78        } finally {
79            $container->stop();
80        }
81    }
82
83}
84