Passed
Pull Request — master (#540)
by Def
02:57
created

BatchQueryResult::setPopulatedMethod()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
ccs 0
cts 0
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Db\Query;
6
7
use Closure;
8
use Throwable;
9
use Yiisoft\Db\Exception\Exception;
10
use Yiisoft\Db\Exception\InvalidCallException;
11
use Yiisoft\Db\Exception\InvalidConfigException;
12
use Yiisoft\Db\Query\Data\DataReaderInterface;
13
14
use function current;
15
use function key;
16
use function next;
17
use function reset;
18
19
/**
20
 * The BatchQueryResult represents the result of a batch query execution. A batch query is a group of multiple SQL
21
 * statements that are executed together as a single unit.
22
 */
23
class BatchQueryResult implements BatchQueryResultInterface
24
{
25
    protected int $batchSize = 100;
26
    private int|string|null $key = null;
27
28
    /**
29
     * @var DataReaderInterface|null the data reader associated with this batch query.
30
     */
31
    protected DataReaderInterface|null $dataReader = null;
32
33
    /**
34
     * @var array|null the data retrieved in the current batch
35
     */
36
    private array|null $batch = null;
37
38
    private Closure|null $populateMethod = null;
39
40
    /**
41
     * @var mixed the value for the current iteration
42
     */
43
    private mixed $value;
44
45
    public function __construct(
46
        private QueryInterface $query,
47
        private bool $each = false
48
    ) {
49
    }
50
51
    public function __destruct()
52
    {
53
        $this->reset();
54
    }
55
56
    public function reset(): void
57
    {
58
        $this->dataReader = null;
59
        $this->batch = null;
60
        $this->value = null;
61
        $this->key = null;
62
    }
63
64
    public function rewind(): void
65
    {
66
        $this->reset();
67
        $this->next();
68 30
    }
69
70 30
    public function next(): void
71 30
    {
72
        if ($this->batch === null || !$this->each || (next($this->batch) === false)) {
73
            $this->batch = $this->fetchData();
74
            reset($this->batch);
75
        }
76
77
        if ($this->each) {
78 30
            $this->value = current($this->batch);
79
80 30
            if ($this->query->getIndexBy() !== null) {
81 30
                $this->key = key($this->batch);
82
            } elseif (key($this->batch) !== null) {
83
                $this->key = $this->key === null ? 0 : (int) $this->key + 1;
84 30
            } else {
85 30
                $this->key = null;
86 30
            }
87 30
        } else {
88 30
            $this->value = $this->batch;
89
            $this->key = $this->key === null ? 0 : (int) $this->key + 1;
90
        }
91
    }
92
93
    /**
94
     * Fetches the next batch of data.
95 30
     *
96
     * @throws Exception
97 30
     * @throws InvalidConfigException
98 30
     * @throws Throwable
99 30
     *
100
     * @return array the data fetched.
101
     */
102
    protected function fetchData(): array
103
    {
104
        if ($this->dataReader === null) {
105
            $this->dataReader = $this->query->createCommand()->query();
106 30
        }
107
108 30
        $rows = $this->getRows();
109 30
110 30
        if ($this->populateMethod !== null) {
111
            return ($this->populateMethod)($rows, $this->query->getIndexBy());
112
        }
113 30
114 10
        return $rows;
115 10
    }
116 10
117 10
    /**
118 10
     * Reads and collects rows for batch.
119
     *
120 10
     * @throws InvalidCallException
121
     *
122
     * @psalm-suppress MixedArrayAccess
123 30
     */
124 30
    protected function getRows(): array
125
    {
126 30
        $rows = [];
127
        $count = 0;
128
129
        do {
130
            $this->dataReader?->next();
131
            /** @psalm-var array|bool $row */
132
            $row = $this->dataReader?->current();
133
        } while ($row && ($rows[] = $row) && ++$count < $this->batchSize);
134
135 30
        return $rows;
136
    }
137 30
138 30
    public function key(): int|string|null
139
    {
140
        return $this->key;
141 30
    }
142
143 30
    public function current(): mixed
144
    {
145
        return $this->value;
146
    }
147
148
    public function valid(): bool
149
    {
150
        return !empty($this->batch);
151 30
    }
152
153 30
    public function getQuery(): QueryInterface|null
154 30
    {
155
        return $this->query;
156
    }
157 30
158 30
    public function getBatchSize(): int
159
    {
160 6
        return $this->batchSize;
161 6
    }
162 6
163
    public function batchSize(int $value): self
164
    {
165
        $this->batchSize = $value;
166
167 30
        return $this;
168
    }
169
170
    public function setPopulatedMethod(Closure|null $populateMethod = null): static
171
    {
172
        $this->populateMethod = $populateMethod;
173
174
        return $this;
175
    }
176
}
177