packages/ztd-query-core/tests/Unit/ResultSelectRunnerTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use stdClass;
11use Tests\Fake\FakeStatement;
12use ZtdQuery\Connection\ResultColumn;
13use ZtdQuery\Connection\ResultSet;
14use ZtdQuery\Platform\ResultColumnTypeResolver;
15use ZtdQuery\ResultSelectRunner;
16use ZtdQuery\Schema\ColumnDeclaration;
17use ZtdQuery\Schema\ColumnTypeFamily;
18
19#[CoversClass(ResultSelectRunner::class)]
20#[UsesClass(ColumnDeclaration::class)]
21#[UsesClass(ResultColumn::class)]
22#[UsesClass(ResultSet::class)]
23#[UsesClass(\ZtdQuery\Schema\RowSet::class)]
24final class ResultSelectRunnerTest extends TestCase
25{
26    public function testRunReturnsRowsFromExecutor(): void
27    {
28        $runner = new ResultSelectRunner();
29        $rows = [['id' => 1, 'name' => 'Alice']];
30
31        $resolver = self::createStub(ResultColumnTypeResolver::class);
32        $result = $runner->run('SELECT * FROM users', fn () => new FakeStatement($rows), $resolver);
33
34        self::assertSame($rows, $result);
35    }
36
37    public function testRunReturnsEmptyWhenExecutorReturnsFalse(): void
38    {
39        $runner = new ResultSelectRunner();
40
41        $resolver = self::createStub(ResultColumnTypeResolver::class);
42        $result = $runner->run('SELECT * FROM users', fn () => false, $resolver);
43
44        self::assertSame([], $result);
45    }
46
47    public function testRunPreservesSparseDriverRowsAndOpaqueValues(): void
48    {
49        $rows = [7 => ['id' => 1, 'payload' => new stdClass()], 12 => ['id' => 2, 'payload' => ['nested']]];
50        $resolver = self::createStub(ResultColumnTypeResolver::class);
51
52        $result = (new ResultSelectRunner())->run('SELECT * FROM users', fn () => new FakeStatement($rows), $resolver);
53
54        self::assertSame($rows, $result);
55    }
56
57    public function testRunStatementReturnsRows(): void
58    {
59        $runner = new ResultSelectRunner();
60        $rows = [['id' => 1]];
61        $statement = new FakeStatement($rows);
62
63        $resolver = self::createStub(ResultColumnTypeResolver::class);
64        $result = $runner->runStatement($statement, $resolver);
65
66        self::assertSame($rows, $result);
67        self::assertTrue($statement->isExecuted());
68    }
69
70    public function testRunResultSetRetainsColumnsWhenRowsAreEmpty(): void
71    {
72        $runner = new ResultSelectRunner();
73        $column = new ResultColumn('id', new ColumnDeclaration(ColumnTypeFamily::INTEGER, 'int4'));
74
75        $resolver = self::createStub(ResultColumnTypeResolver::class);
76        $result = $runner->runResultSet(
77            'SELECT id FROM users WHERE FALSE',
78            fn () => new FakeStatement([], [$column]),
79            $resolver,
80        );
81
82        self::assertSame([], $result->rows);
83        self::assertSame([$column], $result->columns);
84    }
85
86    public function testReadResultSetReadsMetadataBeforeRows(): void
87    {
88        $runner = new ResultSelectRunner();
89        $column = new ResultColumn('id', new ColumnDeclaration(ColumnTypeFamily::INTEGER, 'int4'));
90        $statement = new FakeStatement([['id' => 1]], [$column]);
91
92        $resolver = self::createStub(ResultColumnTypeResolver::class);
93        $result = $runner->readResultSet($statement, $resolver);
94
95        self::assertSame([['id' => 1]], $result->rows);
96        self::assertSame([$column], $result->columns);
97    }
98
99    public function testReadResultSetPassesPlatformTypeResolverToStatement(): void
100    {
101        $resolver = self::createStub(ResultColumnTypeResolver::class);
102        $statement = new FakeStatement();
103
104        (new ResultSelectRunner())->readResultSet($statement, $resolver);
105
106        self::assertSame([$resolver], $statement->typeResolversAsked());
107    }
108}
109