Failed Conditions
Push — next ( ee030a...ae385d )
by Bas
02:43
created

Statement::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 5
dl 0
loc 12
ccs 6
cts 6
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace ArangoClient\Statement;
4
5
use ArangoClient\ArangoClient;
6
use ArangoClient\Exceptions\ArangoException;
7
use ArangoClient\Manager;
8
use ArrayIterator;
9
use IteratorAggregate;
10
11
/**
12
 * Executes queries on ArangoDB
13
 *
14
 * @see https://www.arangodb.com/docs/stable/http/aql-query-cursor.html
15
 *
16
 * @package ArangoClient
17
 *
18
 * @template-implements \IteratorAggregate<mixed>
19
 */
20
class Statement extends Manager implements IteratorAggregate
21
{
22
    protected ArangoClient $arangoClient;
23
24
    protected string $query;
25
26
    /**
27
     * @var array<scalar>
28
     */
29
    protected array $bindVars = [];
30
31
    /**
32
     * @var array<array<string>>
33
     */
34
    protected array $collections = [];
35
36
    /**
37
     * @var array<mixed>
38
     */
39
    protected array $options = [];
40
41
    /**
42
     * @var array<mixed>
43
     */
44
    protected array $results = [];
45
46
    /**
47
     * @var array<mixed>
48
     */
49
    protected array $stats = [];
50
51
    /**
52
     * @var array<mixed>
53
     */
54
    protected array $warnings = [];
55
56
    /**
57
     * @var int|null
58
     */
59
    protected ?int $cursorId = null;
60
61
    /**
62
     * @var bool
63
     */
64
    protected bool $cursorHasMoreResults = false;
65
66
    /**
67
     * @var int|null
68
     */
69
    protected ?int $count = null;
70
71
    /**
72
     * @var array<mixed>
73
     */
74
    protected array $extra = [];
75
76
    /**
77
     * Statement constructor.
78
     * @param  ArangoClient  $arangoClient
79
     * @param  string  $query
80
     * @param  array<scalar>  $bindVars
81
     * @param  array<array<string>>  $collections
82
     * @param  array<mixed>  $options
83
     */
84 12
    public function __construct(
85
        ArangoClient $arangoClient,
86
        string $query,
87
        array $bindVars = [],
88
        array $collections = [],
89
        array $options = []
90
    ) {
91 12
        $this->arangoClient = $arangoClient;
92 12
        $this->query = $query;
93 12
        $this->bindVars = $bindVars;
94 12
        $this->collections = $collections;
95 12
        $this->options = $options;
96 12
    }
97
98
    /**
99
     * A statement can be used like an array to access the results.
100
     *
101
     * @return ArrayIterator<array-key, mixed>
102
     */
103 1
    public function getIterator(): ArrayIterator
104
    {
105 1
        return new ArrayIterator($this->results);
106
    }
107
108
    /**
109
     * @return bool
110
     * @throws ArangoException
111
     */
112 6
    public function execute(): bool
113
    {
114 6
        $this->results = [];
115
116 6
        $bodyContent = $this->prepareQueryBodyContent();
117 6
        $body = $this->arangoClient->jsonEncode($bodyContent);
118
119 6
        $results = $this->arangoClient->request('post', '/_api/cursor', ['body' => $body]);
120
121 6
        $this->handleQueryResults($results);
122
123 6
        $this->requestOutstandingResults($body);
124
125 6
        return ! $results['error'];
126
    }
127
128
    /**
129
     * @return array<mixed>
130
     */
131 10
    protected function prepareQueryBodyContent(): array
132
    {
133 10
        $bodyContent = $this->options;
134 10
        $bodyContent['query'] = $this->query;
135 10
        $bodyContent['bindVars'] = $this->bindVars;
136 10
        $bodyContent['collections'] = $this->collections;
137
138 10
        return $bodyContent;
139
    }
140
141
    /**
142
     * @param  array<mixed>  $results
143
     */
144 8
    protected function handleQueryResults(array $results): void
145
    {
146 8
        $this->results = array_merge($this->results, (array) $results['result']);
147
148 8
        if (isset($results['extra'])) {
149 8
            $this->extra = (array) $results['extra'];
150
        }
151
152 8
        if (array_key_exists('count', $results)) {
153 1
            $this->count = (int) $results['count'];
154
        }
155
156 8
        $this->cursorHasMoreResults = (bool) $results['hasMore'];
157 8
        $this->cursorId = $results['hasMore'] ?  (int) $results['id'] : null;
158 8
    }
159
160
    /**
161
     * @param  string  $body
162
     * @throws ArangoException
163
     */
164 8
    protected function requestOutstandingResults(string $body): void
165
    {
166 8
        while ($this->cursorHasMoreResults) {
167 1
            $uri = '/_api/cursor/' . (string) $this->cursorId;
168
169 1
            $results = $this->arangoClient->request('put', $uri, ['body' => $body]);
170
171 1
            $this->handleQueryResults($results);
172
        }
173 8
    }
174
175
    /**
176
     * Explain the given query
177
     *
178
     * @return array<mixed>
179
     * @throws ArangoException
180
     */
181 1
    public function explain(): array
182
    {
183 1
        $bodyContent = $this->prepareQueryBodyContent();
184 1
        $body = $this->arangoClient->jsonEncode($bodyContent);
185
186 1
        $results = $this->arangoClient->request('post', '/_api/explain', ['body' => $body]);
187
188 1
        return $this->sanitizeRequestMetadata($results);
189
    }
190
191
    /**
192
     * Parse and validate the query, will through an ArangoException if the query is invalid.
193
     *
194
     * @return array<mixed>
195
     * @throws ArangoException
196
     */
197 1
    public function parse(): array
198
    {
199 1
        $bodyContent = $this->prepareQueryBodyContent();
200 1
        $body = $this->arangoClient->jsonEncode($bodyContent);
201
202 1
        $results = $this->arangoClient->request('post', '/_api/query', ['body' => $body]);
203
204 1
        return $this->sanitizeRequestMetadata($results);
205
    }
206
207
208
    /**
209
     * Execute the query and return performance information on the query.
210
     * @see https://www.arangodb.com/docs/3.7/aql/execution-and-performance-query-profiler.html
211
     *
212
     * @param  int|bool  $mode
213
     * @return array<mixed>
214
     * @throws ArangoException
215
     */
216 2
    public function profile($mode = 1): array
217
    {
218 2
        $bodyContent = $this->prepareQueryBodyContent();
219
220 2
        if (! isset($bodyContent['options']) || ! is_array($bodyContent['options'])) {
221 2
            $bodyContent['options'] = [];
222
        }
223 2
        $bodyContent['options']['profile'] = $mode;
224
225 2
        $body = $this->arangoClient->jsonEncode($bodyContent);
226
227 2
        $results = $this->arangoClient->request('post', '/_api/cursor', ['body' => $body]);
228
229 2
        $this->handleQueryResults($results);
230
231 2
        $this->requestOutstandingResults($body);
232
233 2
        return $this->extra;
234
    }
235
236
237
    /**
238
     * Set a query on the statement
239
     *
240
     * @param  string  $query
241
     * @return Statement
242
     */
243 2
    public function setQuery(string $query): self
244
    {
245 2
        $this->query = $query;
246
247 2
        return $this;
248
    }
249
250
    /**
251
     * Get the statement's query.
252
     *
253
     * @return string
254
     */
255 1
    public function getQuery(): string
256
    {
257 1
        return $this->query;
258
    }
259
260
    /**
261
     * Fetch all results.
262
     *
263
     * @return array<mixed>
264
     */
265 2
    public function fetchAll(): array
266
    {
267 2
        return $this->results;
268
    }
269
270
    /**
271
     * Return the total number of results.
272
     * Useful if not all results have been retrieved from the database yet.
273
     *
274
     * @return int|null
275
     */
276 2
    public function getCount(): ?int
277
    {
278 2
        return $this->count;
279
    }
280
}
281