Skip to content

Refactor data readers #822

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Apr 16, 2025
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f789a1b
Refactor data readers
Tigrov Apr 17, 2024
b9f7eab
Apply fixes from StyleCI
StyleCIBot Apr 17, 2024
884e9c7
Fix psalm issue
Tigrov Apr 17, 2024
0e9afd6
Merge branch 'refs/heads/master' into refactor-data-readers
Tigrov Jan 27, 2025
2446c58
Merge branch 'master' into refactor-data-readers
vjik Apr 3, 2025
8529e81
Merge branch 'refs/heads/master' into refactor-data-readers
Tigrov Apr 3, 2025
2e131d8
Merge remote-tracking branch 'origin/refactor-data-readers' into refa…
Tigrov Apr 3, 2025
2c2e10d
Merge branch 'master' into refactor-data-readers
Tigrov Apr 4, 2025
c0c6505
Remove `populateMethod`
Tigrov Apr 5, 2025
30d5ef5
Merge branch 'master' into refactor-data-readers
Tigrov Apr 6, 2025
7605e50
Update
Tigrov Apr 6, 2025
60b0180
Apply fixes from StyleCI
StyleCIBot Apr 6, 2025
06187e7
Merge branch 'master' into refactor-data-readers
samdark Apr 8, 2025
a31a953
Update
Tigrov Apr 13, 2025
ee20ab0
Update type annotations
Tigrov Apr 13, 2025
4043713
Update type annotations
Tigrov Apr 13, 2025
abe793f
Update and improve test coverage
Tigrov Apr 14, 2025
bbede61
Apply fixes from StyleCI
StyleCIBot Apr 14, 2025
2e00a92
Fix psalm
Tigrov Apr 14, 2025
b402d50
Merge remote-tracking branch 'origin/refactor-data-readers' into refa…
Tigrov Apr 14, 2025
7d00ab8
Fix test
Tigrov Apr 14, 2025
deb81b2
Change `DataReaderInterface::resultCallback` accept one item
Tigrov Apr 14, 2025
1098597
Improve, add lines to UPGRADE.md and CHANGELOG.md
Tigrov Apr 14, 2025
1441b31
Merge branch 'master' into refactor-data-readers
Tigrov Apr 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Command/AbstractCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Closure;
use Throwable;
use Yiisoft\Db\Exception\Exception;
use Yiisoft\Db\Query\Data\DataReaderInterface;
use Yiisoft\Db\Query\DataReaderInterface;
use Yiisoft\Db\Query\QueryInterface;
use Yiisoft\Db\QueryBuilder\DMLQueryBuilderInterface;
use Yiisoft\Db\QueryBuilder\QueryBuilderInterface;
Expand Down
2 changes: 1 addition & 1 deletion src/Command/CommandInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
use Yiisoft\Db\Exception\InvalidCallException;
use Yiisoft\Db\Exception\InvalidConfigException;
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Query\Data\DataReaderInterface;
use Yiisoft\Db\Query\DataReaderInterface;
use Yiisoft\Db\Query\QueryInterface;
use Yiisoft\Db\QueryBuilder\DMLQueryBuilderInterface;
use Yiisoft\Db\Schema\Column\ColumnInterface;
Expand Down
4 changes: 2 additions & 2 deletions src/Connection/AbstractConnection.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ public function beginTransaction(?string $isolationLevel = null): TransactionInt
return $this->transaction;
}

public function createBatchQueryResult(QueryInterface $query, bool $each = false): BatchQueryResultInterface
public function createBatchQueryResult(QueryInterface $query): BatchQueryResultInterface
{
return new BatchQueryResult($query, $each);
return new BatchQueryResult($query);
}

public function getTablePrefix(): string
Expand Down
3 changes: 1 addition & 2 deletions src/Connection/ConnectionInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,10 @@ public function beginTransaction(?string $isolationLevel = null): TransactionInt
* Create a batch query result instance.
*
* @param QueryInterface $query The query to execute.
* @param bool $each Whether to return each row of the result set one at a time.
*
* @return BatchQueryResultInterface The batch query result instance.
*/
public function createBatchQueryResult(QueryInterface $query, bool $each = false): BatchQueryResultInterface;
public function createBatchQueryResult(QueryInterface $query): BatchQueryResultInterface;

/**
* Creates a command for execution.
Expand Down
2 changes: 1 addition & 1 deletion src/Debug/CommandInterfaceProxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Closure;
use Throwable;
use Yiisoft\Db\Command\CommandInterface;
use Yiisoft\Db\Query\Data\DataReaderInterface;
use Yiisoft\Db\Query\DataReaderInterface;
use Yiisoft\Db\Query\QueryInterface;
use Yiisoft\Db\Schema\Column\ColumnInterface;

Expand Down
4 changes: 2 additions & 2 deletions src/Debug/ConnectionInterfaceProxy.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ public function beginTransaction(?string $isolationLevel = null): TransactionInt
return new TransactionInterfaceDecorator($result, $this->collector);
}

public function createBatchQueryResult(QueryInterface $query, bool $each = false): BatchQueryResultInterface
public function createBatchQueryResult(QueryInterface $query): BatchQueryResultInterface
{
return $this->connection->createBatchQueryResult($query, $each);
return $this->connection->createBatchQueryResult($query);
}

public function createCommand(?string $sql = null, array $params = []): CommandInterface
Expand Down
3 changes: 1 addition & 2 deletions src/Driver/Pdo/AbstractPdoCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
use Yiisoft\Db\Profiler\Context\CommandContext;
use Yiisoft\Db\Profiler\ProfilerAwareInterface;
use Yiisoft\Db\Profiler\ProfilerAwareTrait;
use Yiisoft\Db\Query\Data\DataReader;
use Yiisoft\Db\QueryBuilder\QueryBuilderInterface;

use function restore_error_handler;
Expand Down Expand Up @@ -238,7 +237,7 @@ protected function internalExecute(): void
protected function internalGetQueryResult(int $queryMode): mixed
{
if ($queryMode === self::QUERY_MODE_CURSOR) {
return new DataReader($this);
return new PdoDataReader($this);
}

if ($queryMode === self::QUERY_MODE_EXECUTE) {
Expand Down
82 changes: 59 additions & 23 deletions src/Query/Data/DataReader.php → src/Driver/Pdo/PdoDataReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@

declare(strict_types=1);

namespace Yiisoft\Db\Query\Data;
namespace Yiisoft\Db\Driver\Pdo;

use Closure;
use Countable;
use Iterator;
use PDO;
use PDOStatement;
use Yiisoft\Db\Driver\Pdo\PdoCommandInterface;
use Yiisoft\Db\Exception\InvalidCallException;
use Yiisoft\Db\Exception\InvalidParamException;
use Yiisoft\Db\Query\DataReaderInterface;
use Yiisoft\Db\Query\QueryInterface;

use function is_string;

/**
* Provides an abstract way to read data from a database.
Expand All @@ -21,11 +25,18 @@
* to execute a SELECT statement and read the results.
*
* The class provides methods for accessing the data returned by the query.
*
* @psalm-import-type IndexBy from QueryInterface
* @psalm-import-type ResultCallback from QueryInterface
*/
final class DataReader implements DataReaderInterface
final class PdoDataReader implements DataReaderInterface
{
private int $index = -1;
private mixed $row;
/** @psalm-var IndexBy|null $indexBy */
private Closure|string|null $indexBy = null;
private int $index = 0;
/** @psalm-var ResultCallback|null $resultCallback */
private Closure|null $resultCallback = null;
private array|false $row;
private PDOStatement $statement;

/**
Expand All @@ -40,6 +51,13 @@
}

$this->statement = $statement;
/** @var array|false */
$this->row = $statement->fetch(PDO::FETCH_ASSOC);
}

public function __destruct()
{
$this->statement->closeCursor();
}

/**
Expand All @@ -64,31 +82,36 @@
*/
public function rewind(): void
{
if ($this->index < 0) {
$this->row = $this->statement->fetch(PDO::FETCH_ASSOC);
$this->index = 0;
} else {
throw new InvalidCallException('DataReader cannot rewind. It is a forward-only reader.');
if ($this->index === 0) {
return;
}

throw new InvalidCallException('DataReader cannot rewind. It is a forward-only reader.');
}

/**
* Returns the index of the current row.
*
* This method is required by the interface {@see Iterator}.
*/
public function key(): int
public function key(): int|string|null
{
return $this->index;
if ($this->indexBy === null) {
return $this->index;
}

if ($this->row === false) {
return null;

Check warning on line 99 in src/Driver/Pdo/PdoDataReader.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/Pdo/PdoDataReader.php#L99

Added line #L99 was not covered by tests
}

if (is_string($this->indexBy)) {
return (string) $this->row[$this->indexBy];
}

return ($this->indexBy)($this->row);

Check warning on line 106 in src/Driver/Pdo/PdoDataReader.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/Pdo/PdoDataReader.php#L106

Added line #L106 was not covered by tests
}

/**
* Returns the current row.
*
* This method is required by the interface {@see Iterator}.
*/
public function current(): mixed
public function current(): array|object|false
{
if ($this->resultCallback !== null && $this->row !== false) {
return ($this->resultCallback)([$this->row])[0];

Check warning on line 112 in src/Driver/Pdo/PdoDataReader.php

View check run for this annotation

Codecov / codecov/patch

src/Driver/Pdo/PdoDataReader.php#L112

Added line #L112 was not covered by tests
}

return $this->row;
}

Expand All @@ -99,6 +122,7 @@
*/
public function next(): void
{
/** @var array|false */
$this->row = $this->statement->fetch(PDO::FETCH_ASSOC);
$this->index++;
}
Expand All @@ -112,4 +136,16 @@
{
return $this->row !== false;
}

public function indexBy(Closure|string|null $indexBy): static
{
$this->indexBy = $indexBy;
return $this;
}

public function resultCallback(Closure|null $resultCallback): static
{
$this->resultCallback = $resultCallback;
return $this;
}
}
Loading
Loading