kak-clickhouse
kak-clickhouse copied to clipboard
BatchQueryResult compatibility with Iterable interface
https://github.com/sanchezzzhak/kak-clickhouse/blob/29a317fc60da43b38408f9ecddfd6f7f9faa9810/BatchQueryResult.php#L76
BatchQueryResult should be modified to
<?php
namespace kak\clickhouse;
use yii\base\BaseObject;
/**
* BatchQueryResult represents a batch query from which you can retrieve data in batches.
*
* You usually do not instantiate BatchQueryResult directly. Instead, you obtain it by
* calling [[Query::batch()]] or [[Query::each()]]. Because BatchQueryResult implements the [[\Iterator]] interface,
* you can iterate it to obtain a batch of data in each iteration. For example,
*
* ```php
* $query = (new Query)->from('user');
* foreach ($query->batch() as $i => $users) {
* // $users represents the rows in the $i-th batch
* }
* foreach ($query->each() as $user) {
* }
* ```
*
* Class BatchQueryResult
* @package kak\clickhouse
*/
class BatchQueryResult extends BaseObject implements \Iterator
{
/**
* @var Connection the DB connection to be used when performing batch query.
* If null, the "db" application component will be used.
*/
public $db;
/**
* @var Query the query object associated with this batch query.
* Do not modify this property directly unless after [[reset()]] is called explicitly.
*/
public $query;
/**
* @var int the number of rows to be returned in each batch.
*/
public $batchSize = 100;
/**
* @var bool whether to return a single row during each iteration.
* If false, a whole batch of rows will be returned in each iteration.
*/
public $each = false;
/**
* @var array the data retrieved in the current batch
*/
private $batch;
/**
* @var mixed the value for the current iteration
*/
private $value;
/**
* @var string|int the key for the current iteration
*/
private $key;
private $index = 0;
/**
* Destructor.
*/
public function __destruct()
{
$this->reset();
}
/**
* Resets the batch query.
* This method will clean up the existing batch query so that a new batch query can be performed.
*/
public function reset(): void
{
$this->batch = null;
$this->value = null;
$this->key = null;
$this->index = 0;
}
/**
* Resets the iterator to the initial state.
* This method is required by the interface [[\Iterator]].
*/
public function rewind(): void
{
$this->reset();
$this->next();
}
/**
* Moves the internal pointer to the next dataset.
* This method is required by the interface [[\Iterator]].
*/
public function next(): void
{
if ($this->batch === null || !$this->each || $this->each && next($this->batch) === false) {
$this->batch = $this->fetchData();
reset($this->batch);
}
if ($this->each) {
$this->value = current($this->batch);
if ($this->query->indexBy !== null) {
$this->key = key($this->batch);
} elseif (key($this->batch) !== null) {
$this->key = $this->key === null ? 0 : $this->key + 1;
} else {
$this->key = null;
}
} else {
$this->value = $this->batch;
$this->key = $this->key === null ? 0 : $this->key + 1;
}
}
/**
* Fetches the next batch of data.
* @return array the data fetched
*/
protected function fetchData(): array
{
$command = $this->query->createCommand($this->db);
$offset = ($this->index * $this->batchSize);
$this->index++;
$limit = $this->batchSize;
$rawSql = $command->getRawSql();
$command->setSql("{$rawSql} LIMIT {$offset},{$limit}");
$rows = $command->queryAll();
return $this->query->populate($rows);
}
/**
* Returns the index of the current dataset.
* This method is required by the interface [[\Iterator]].
* @return string|int the index of the current row.
*/
public function key(): string|int
{
return $this->key;
}
/**
* Returns the current dataset.
* This method is required by the interface [[\Iterator]].
* @return mixed the current dataset.
*/
public function current(): mixed
{
return $this->value;
}
/**
* Returns whether there is a valid dataset at the current position.
* This method is required by the interface [[\Iterator]].
* @return bool whether there is a valid dataset at the current position.
*/
public function valid(): bool
{
return !empty($this->batch);
}
}