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

BatchQueryResult::key()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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