Failed Conditions
Branch prepare-alpha (4a2a7f)
by Bas
02:41
created

QueryBuilder::validateBindVariable()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 3.3332

Importance

Changes 0
Metric Value
cc 3
eloc 2
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 4
ccs 2
cts 3
cp 0.6667
crap 3.3332
rs 10
1
<?php
2
3
namespace LaravelFreelancerNL\FluentAQL;
4
5
use LaravelFreelancerNL\FluentAQL\AQL\HasFunctions;
6
use LaravelFreelancerNL\FluentAQL\AQL\HasGraphClauses;
7
use LaravelFreelancerNL\FluentAQL\AQL\HasQueryClauses;
8
use LaravelFreelancerNL\FluentAQL\AQL\HasStatementClauses;
9
use LaravelFreelancerNL\FluentAQL\AQL\HasSupportCommands;
10
use LaravelFreelancerNL\FluentAQL\Clauses\Clause;
11
use LaravelFreelancerNL\FluentAQL\Exceptions\BindException;
12
use LaravelFreelancerNL\FluentAQL\Expressions\BindExpression;
13
use LaravelFreelancerNL\FluentAQL\Expressions\Expression;
14
use LaravelFreelancerNL\FluentAQL\Expressions\ExpressionInterface;
15
use LaravelFreelancerNL\FluentAQL\Traits\NormalizesExpressions;
16
17
/**
18
 * Class QueryBuilder
19
 * Fluent ArangoDB AQL Query Builder.
20
 * Creates and compiles AQL queries. Returns all data necessary to run the query,
21
 * including bindings and a list of used read/write collections.
22
 */
23
class QueryBuilder
24
{
25
    use NormalizesExpressions;
26
    use HasQueryClauses;
27
    use HasStatementClauses;
28
    use HasGraphClauses;
29
    use HasFunctions;
30
    use HasSupportCommands;
31
32
    /**
33
     * The database query grammar instance.
34
     *
35
     * @var Grammar
36
     */
37
    public $grammar;
38
39
    /**
40
     * The AQL query.
41
     *
42
     * @var
43
     */
44
    public $query;
45
46
    /**
47
     * Bindings for $query.
48
     *
49
     * @var
50
     */
51
    public $binds = [];
52
53
    /**
54
     * List of read/write/exclusive collections required for transactions.
55
     *
56
     * @var array
57
     */
58
    public $collections;
59
60
    /**
61
     * List of Clauses to be compiled into a query.
62
     */
63
    protected $commands = [];
64
65
    /**
66
     * Registry of variable names used in this query.
67
     */
68
    protected $variables = [];
69
70
    /**
71
     * ID of the query
72
     * Used as prefix for automatically generated bindings.
73
     *
74
     * @var int
75
     */
76
    protected $queryId = 1;
77
78 14
    public function __construct()
79
    {
80 14
        $this->grammar = new Grammar();
81
82 14
        $this->queryId = spl_object_id($this);
83 14
    }
84
85
    /**
86
     * Add an AQL command (raw AQL and Clauses.
87
     *
88
     * @param Clause|Expression|QueryBuilder $command
89
     */
90 9
    public function addCommand($command)
91
    {
92 9
        $this->commands[] = $command;
93 9
    }
94
95
    /**
96
     * Get the clause list.
97
     *
98
     * @return mixed
99
     */
100 3
    public function getCommands()
101
    {
102 3
        return $this->commands;
103
    }
104
105
    /**
106
     * Get the last, or a specific, command.
107
     *
108
     * @param int|null $index
109
     *
110
     * @return mixed
111
     */
112 3
    public function getCommand(int $index = null)
113
    {
114 3
        if ($index === null) {
115
            return end($this->commands);
116
        }
117
118 3
        return $this->commands[$index];
119
    }
120
121
    /**
122
     * Remove the last, or the specified, Command.
123
     *
124
     * @param number|null $index
125
     * @return bool
126
     */
127 2
    public function removeCommand($index = null): bool
128
    {
129 2
        if ($index === null) {
130 1
            return (array_pop($this->commands)) ? true : false;
131
        }
132 1
        if (isset($this->commands[$index])) {
133 1
            unset($this->commands[$index]);
134
135 1
            return true;
136
        }
137
138
        return false;
139
    }
140
141
    /**
142
     * @param mixed  $collections
143
     * @param string $mode
144
     *
145
     * @return QueryBuilder
146
     */
147 1
    public function registerCollections($collections, $mode = 'write'): self
148
    {
149 1
        if (!is_array($collections)) {
150 1
            $collections = [$collections];
151
        }
152
153 1
        $this->collections[$mode] = array_unique(array_merge($collections));
154
155 1
        return $this;
156
    }
157
158
    /**
159
     * Register variables on declaration for later data normalization.
160
     *
161
     * @param string|array $variableName
162
     *
163
     * @return QueryBuilder
164
     */
165 5
    public function registerVariable($variableName): self
166
    {
167 5
        if ($variableName instanceof ExpressionInterface) {
0 ignored issues
show
introduced by
$variableName is never a sub-type of LaravelFreelancerNL\Flue...ons\ExpressionInterface.
Loading history...
168
            $variableName = $variableName->compile($this);
169
        }
170 5
        if (is_string($variableName)) {
171 5
            $variableName = [$variableName => $variableName];
172
        }
173
174 5
        $this->variables = array_unique(array_merge($this->variables, $variableName));
175
176 5
        return $this;
177
    }
178
179
    /**
180
     * Bind data to a variable.
181
     *
182
     * @param $data
183
     * @param string|null $to
184
     * @throws BindException
185
     * @return BindExpression
186
     */
187 2
    public function bind($data, $to = null): BindExpression
188
    {
189 2
        $this->validateBindVariable($to);
190
191 2
        $to = $this->generateBindVariable($to);
192
193 2
        $this->binds[$to] = $data;
194
195 2
        $to = $this->grammar->formatBind($to, false);
196
197 2
        return new BindExpression($to);
198
    }
199
200
    /**
201
     * Bind a collection name to a variable.
202
     *
203
     * @param $data
204
     * @param string|null $to
205
     * @throws BindException
206
     * @return BindExpression
207
     */
208 1
    public function bindCollection($data, $to = null): BindExpression
209
    {
210 1
        $this->validateBindVariable($to);
211
212 1
        $to = $this->generateBindVariable($to);
213
214 1
        $this->binds[$to] = $data;
215
216 1
        $to = $this->grammar->formatBind($to, true);
217
218 1
        return new BindExpression($to);
219
    }
220
221 3
    protected function validateBindVariable($to)
222
    {
223 3
        if (isset($to) && !$this->grammar->isBindParameter($to)) {
224
            throw new BindException('Invalid bind parameter.');
225
        }
226 3
    }
227
228 3
    protected function generateBindVariable($to)
229
    {
230 3
        if ($to == null) {
231 3
            $to = $this->queryId . '_' . (count($this->binds) + 1);
232
        }
233 3
        return $to;
234
    }
235
236
237
    /**
238
     * Compile the query with its bindings and collection list.
239
     *
240
     * @return mixed
241
     */
242 6
    public function compile(): self
243
    {
244 6
        $this->query = '';
245 6
        foreach ($this->commands as $command) {
246 5
            $this->query .= ' ' . $command->compile($this);
247
        }
248 6
        $this->query = trim($this->query);
249
250 6
        return $this;
251
    }
252
253
    /**
254
     * @return QueryBuilder $this
255
     */
256 6
    public function get()
257
    {
258 6
        $this->compile();
259
260 6
        return $this;
261
    }
262
263
    /**
264
     * @return QueryBuilder $this
265
     */
266 4
    public function getQueryId()
267
    {
268 4
        return $this->queryId;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->queryId returns the type integer which is incompatible with the documented return type LaravelFreelancerNL\FluentAQL\QueryBuilder.
Loading history...
269
    }
270
271
    /**
272
     * @return string
273
     */
274 5
    public function toAql()
275
    {
276 5
        return $this->get()->query;
277
    }
278
279 4
    public function __toString()
280
    {
281 4
        return $this->toAql();
282
    }
283
284 4
    public function getVariables()
285
    {
286 4
        return $this->variables;
287
    }
288
}
289