Failed Conditions
Branch prepare-alpha (89acfc)
by Bas
08:11
created

QueryBuilder::__toString()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 2
b 0
f 0
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
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 13
    public function __construct()
79
    {
80 13
        $this->grammar = new Grammar();
81
82 13
        $this->queryId = spl_object_id($this);
83 13
    }
84
85
    /**
86
     * Add an AQL command (raw AQL and Clauses.
87
     *
88
     * @param Clause|Expression|QueryBuilder $command
89
     */
90 8
    public function addCommand($command)
91
    {
92 8
        $this->commands[] = $command;
93 8
    }
94
95
    /**
96
     * Get the clause list.
97
     *
98
     * @return mixed
99
     */
100 2
    public function getCommands()
101
    {
102 2
        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 2
    public function getCommand(int $index = null)
113
    {
114 2
        if ($index === null) {
115
            return end($this->commands);
116
        }
117
118 2
        return $this->commands[$index];
119
    }
120
121
    /**
122
     * Remove the last, or the specified, Command.
123
     *
124
     * @param null $index
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $index is correct as it would always require null to be passed?
Loading history...
125
     *
126
     * @return bool
127
     */
128 1
    public function removeCommand($index = null): bool
129
    {
130 1
        if ($index === null) {
0 ignored issues
show
introduced by
The condition $index === null is always true.
Loading history...
131
            return (array_pop($this->commands)) ? true : false;
132
        }
133 1
        if (isset($this->commands[$index])) {
134 1
            unset($this->commands[$index]);
135
136 1
            return true;
137
        }
138
139
        return false;
140
    }
141
142
    /**
143
     * @param mixed  $collections
144
     * @param string $mode
145
     *
146
     * @return QueryBuilder
147
     */
148 1
    public function registerCollections($collections, $mode = 'write'): self
149
    {
150 1
        if (!is_array($collections)) {
151 1
            $collections = [$collections];
152
        }
153
154 1
        $this->collections[$mode] = array_unique(array_merge($collections));
155
156 1
        return $this;
157
    }
158
159
    /**
160
     * Register variables on declaration for later data normalization.
161
     *
162
     * @param string|array $variableName
163
     *
164
     * @return QueryBuilder
165
     */
166 5
    public function registerVariable($variableName): self
167
    {
168 5
        if ($variableName instanceof ExpressionInterface) {
0 ignored issues
show
introduced by
$variableName is never a sub-type of LaravelFreelancerNL\Flue...ons\ExpressionInterface.
Loading history...
169
            $variableName = $variableName->compile($this);
170
        }
171 5
        if (is_string($variableName)) {
172 5
            $variableName = [$variableName => $variableName];
173
        }
174
175 5
        $this->variables = array_unique(array_merge($this->variables, $variableName));
176
177 5
        return $this;
178
    }
179
180
    /**
181
     * Bind data or a collection name to a variable.
182
     *
183
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
184
     *
185
     * @param $data
186
     * @param string|null $to
187
     * @param bool $collection
188
     *
189
     * @throws BindException
190
     *
191
     * @return BindExpression
192
     */
193 2
    public function bind($data, $to = null, $collection = false): BindExpression
194
    {
195 2
        if (isset($to) && !$this->grammar->isBindParameter($to)) {
196
            throw new BindException('Invalid bind parameter.');
197
        }
198
199 2
        if ($to == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $to of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
200 2
            $to = $this->queryId . '_' . (count($this->binds) + 1);
201
        }
202
203 2
        $this->binds[$to] = $data;
204
205 2
        $to = $this->grammar->formatBind($to, $collection);
206
207 2
        return new BindExpression($to);
208
    }
209
210
    /**
211
     * Compile the query with its bindings and collection list.
212
     *
213
     * @return mixed
214
     */
215 6
    public function compile(): self
216
    {
217 6
        $this->query = '';
218 6
        foreach ($this->commands as $command) {
219 5
            $this->query .= ' ' . $command->compile($this);
220
        }
221 6
        $this->query = trim($this->query);
222
223 6
        return $this;
224
    }
225
226
    /**
227
     * @return QueryBuilder $this
228
     */
229 6
    public function get()
230
    {
231 6
        $this->compile();
232
233 6
        return $this;
234
    }
235
236
    /**
237
     * @return QueryBuilder $this
238
     */
239 3
    public function getQueryId()
240
    {
241 3
        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...
242
    }
243
244
    /**
245
     * @return string
246
     */
247 5
    public function toAql()
248
    {
249 5
        return $this->get()->query;
250
    }
251
252 4
    public function __toString()
253
    {
254 4
        return $this->toAql();
255
    }
256
257 1
    public function wrap($value)
258
    {
259 1
        return $this->grammar->wrap($value);
260
    }
261
262 4
    public function getVariables()
263
    {
264 4
        return $this->variables;
265
    }
266
}