Skip to content

Commit 469463b

Browse files
authored
Merge pull request #14 from simon-mundy/result-get-query-result
Implement Result::getQueryResult()
2 parents f077bee + f7ccb24 commit 469463b

8 files changed

Lines changed: 196 additions & 43 deletions

File tree

.laminas-ci.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
{
44
"name": "PhpStan",
55
"job": {
6-
"php": "8.2",
6+
"php": "8.3",
77
"dependencies": "latest",
88
"command": "composer require --dev phpstan/phpstan && vendor/bin/phpstan analyse"
99
}

composer.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"config": {
1919
"sort-packages": true,
2020
"platform": {
21-
"php": "8.2.99"
21+
"php": "8.3.99"
2222
},
2323
"allow-plugins": {
2424
"dealerdirect/phpcodesniffer-composer-installer": true
@@ -30,14 +30,14 @@
3030
}
3131
},
3232
"require": {
33-
"php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
33+
"php": "~8.3.0 || ~8.4.0 || ~8.5.0",
3434
"php-db/phpdb": "^0.6.0"
3535
},
3636
"require-dev": {
3737
"ext-pdo_pgsql": "*",
3838
"ext-pgsql": "*",
3939
"laminas/laminas-coding-standard": "^3.0.1",
40-
"phpstan/phpstan": "^2.1",
40+
"phpstan/phpstan": "^2.2",
4141
"phpstan/phpstan-phpunit": "^2.0",
4242
"phpunit/phpunit": "^11.5.42"
4343
},

composer.lock

Lines changed: 37 additions & 28 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

phpstan-baseline.neon

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,3 @@ parameters:
66
count: 1
77
path: src/Container/ConnectionInterfaceFactory.php
88

9-
-
10-
message: '#^Parameter \#2 \$array of function implode expects array\<string\>, array\<int, array\<int\|string, string\>\> given\.$#'
11-
identifier: argument.type
12-
count: 1
13-
path: src/Metadata/Source.php
14-
15-
-
16-
message: '#^Parameter \#2 \$array of function implode expects array\<string\>, array\<int, list\<string\>\> given\.$#'
17-
identifier: argument.type
18-
count: 1
19-
path: src/Metadata/Source.php

src/Result.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
use Override;
88
use PgSql\Result as PgSqlResult;
99
use PhpDb\Adapter\Driver\ResultInterface;
10+
use PhpDb\Adapter\Exception;
11+
use PhpDb\ResultSet\ResultSet;
12+
use PhpDb\ResultSet\ResultSetInterface;
1013

1114
use function pg_affected_rows;
1215
use function pg_fetch_assoc;
@@ -94,6 +97,26 @@ public function getGeneratedValue(): int|string|false|null
9497
return $this->generatedValue;
9598
}
9699

100+
/**
101+
* @throws Exception\RuntimeException When this result is not a query result.
102+
*/
103+
#[Override]
104+
public function getQueryResult(?ResultSetInterface $resultPrototype = null): ResultSetInterface
105+
{
106+
if (! $this->isQueryResult()) {
107+
throw new Exception\RuntimeException(
108+
'Cannot produce a query result set from a result that is not a query result;'
109+
. ' check isQueryResult() first'
110+
);
111+
}
112+
113+
$resultPrototype ??= new ResultSet();
114+
$resultSet = clone $resultPrototype;
115+
$resultSet->initialize($this);
116+
117+
return $resultSet;
118+
}
119+
97120
/**
98121
* Get resource
99122
*/

test/asset/ResultStub.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpDbTestAsset\Pgsql;
6+
7+
use Override;
8+
use PhpDb\Pgsql\Result;
9+
10+
/**
11+
* Result::getQueryResult() only needs isQueryResult() and getFieldCount() to be
12+
* answerable, both of which read the pgsql resource. Overriding them keeps the
13+
* method unit-testable without a live connection.
14+
*/
15+
final class ResultStub extends Result
16+
{
17+
public function __construct(private bool $isQueryResult, private int $fieldCount = 0)
18+
{
19+
}
20+
21+
#[Override]
22+
public function isQueryResult(): bool
23+
{
24+
return $this->isQueryResult;
25+
}
26+
27+
#[Override]
28+
public function getFieldCount(): int
29+
{
30+
return $this->fieldCount;
31+
}
32+
}

test/integration/ResultTest.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpDbIntegrationTest\Pgsql;
6+
7+
use PhpDb\Adapter\Exception;
8+
use PhpDb\Pgsql\Result;
9+
use PhpDbTestAsset\Pgsql\SetupTrait;
10+
use PHPUnit\Framework\Attributes\CoversMethod;
11+
use PHPUnit\Framework\TestCase;
12+
13+
#[CoversMethod(Result::class, 'getQueryResult')]
14+
#[CoversMethod(Result::class, 'isQueryResult')]
15+
class ResultTest extends TestCase
16+
{
17+
use SetupTrait;
18+
19+
public function testGetQueryResultSeedsTheResultSetFromASelect(): void
20+
{
21+
$result = $this->getAdapter()->executeQuery('SELECT id, name, value FROM test');
22+
23+
self::assertSame($result->getFieldCount(), $result->getQueryResult()->getFieldCount());
24+
}
25+
26+
public function testGetQueryResultIteratesTheSelectedRows(): void
27+
{
28+
$result = $this->getAdapter()->executeQuery('SELECT name FROM test ORDER BY id');
29+
30+
$names = [];
31+
foreach ($result->getQueryResult() as $row) {
32+
$names[] = $row['name'];
33+
}
34+
35+
self::assertSame(['foo', 'bar'], $names);
36+
}
37+
38+
public function testAStatementReturningNoFieldsIsNotAQueryResult(): void
39+
{
40+
$result = $this->getAdapter()->executeQuery('SET search_path TO public');
41+
42+
self::assertFalse($result->isQueryResult());
43+
}
44+
45+
public function testGetQueryResultRejectsAStatementThatReturnsNoFields(): void
46+
{
47+
$result = $this->getAdapter()->executeQuery('SET search_path TO public');
48+
49+
$this->expectException(Exception\RuntimeException::class);
50+
$this->expectExceptionMessage(
51+
'Cannot produce a query result set from a result that is not a query result;'
52+
. ' check isQueryResult() first'
53+
);
54+
55+
$result->getQueryResult();
56+
}
57+
}

0 commit comments

Comments
 (0)