Failed Conditions
Push — refactor/improve-static-analys... ( 8da3ef...a7b39f )
by Bas
09:53
created

Grammar::getBitwiseOperators()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 1
cts 1
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace LaravelFreelancerNL\Aranguent\Query;
6
7
use LaravelFreelancerNL\Aranguent\Query\Concerns\HandlesAqlGrammar;
8
use Illuminate\Database\Query\Builder as IlluminateBuilder;
9
use Illuminate\Database\Query\Grammars\Grammar as IlluminateGrammar;
10
use Illuminate\Support\Arr;
11
use Illuminate\Support\Facades\DB;
12
use Illuminate\Support\Traits\Macroable;
13
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesAggregates;
14
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesColumns;
15
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesGroups;
16
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesJoins;
17
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesWhereClauses;
18
use LaravelFreelancerNL\Aranguent\Query\Concerns\ConvertsIdToKey;
19
use LaravelFreelancerNL\Aranguent\Query\Concerns\HasAliases;
20
use LaravelFreelancerNL\FluentAQL\Exceptions\BindException as BindException;
21
22
class Grammar extends IlluminateGrammar
23
{
24
    use CompilesAggregates;
25
    use CompilesColumns;
0 ignored issues
show
introduced by
The trait LaravelFreelancerNL\Aran...oncerns\CompilesColumns requires some properties which are not provided by LaravelFreelancerNL\Aranguent\Query\Grammar: $variables, $groups, $distinct, $from, $joins, $table
Loading history...
26
    use CompilesJoins;
0 ignored issues
show
introduced by
The trait LaravelFreelancerNL\Aran...\Concerns\CompilesJoins requires some properties which are not provided by LaravelFreelancerNL\Aranguent\Query\Grammar: $type, $table
Loading history...
27
    use CompilesGroups;
0 ignored issues
show
Bug introduced by
The trait LaravelFreelancerNL\Aran...Concerns\CompilesGroups requires the property $havings which is not provided by LaravelFreelancerNL\Aranguent\Query\Grammar.
Loading history...
28
    use CompilesWhereClauses;
29
    use ConvertsIdToKey;
30
    use HasAliases;
31
    use Macroable;
32
    use HandlesAqlGrammar;
33
34
    public $name;
35
36
    /**
37
     * The grammar table prefix.
38
     *
39
     * @var string
40
     */
41
    protected $tablePrefix = '';
42
43
    /**
44
     * The grammar table prefix.
45
     *
46
     * @var null|int
47
     */
48
    protected $offset = null;
49
50
    /**
51
     * The components that make up a select clause.
52
     *
53
     * @var array
54
     */
55
    protected $selectComponents = [
56
        'from',
57
        'search',
58
        'variables',
59
        'joins',
60
        'wheres',
61
        'groups',
62
        'aggregate',
63
        'havings',
64
        'orders',
65
        'offset',
66
        'limit',
67
        'columns',
68
    ];
69
70
    protected $operatorTranslations = [
71
        '='          => '==',
72
        '<>'         => '!=',
73
        '<=>'        => '==',
74
        'rlike'      => '=~',
75
        'not rlike'  => '!~',
76
        'regexp'     => '=~',
77
        'not regexp' => '!~',
78
    ];
79
80
    protected $whereTypeOperators = [
81
        'In'    => 'IN',
82
        'NotIn' => 'NOT IN',
83
    ];
84
85
    /**
86 49
     * The grammar specific bitwise operators.
87
     *
88 49
     * @var array
89
     */
90
    protected $bitwiseOperators = [];
91
92
    /**
93
     * Get the format for database stored dates.
94
     *
95
     * @return string
96 12
     */
97
    public function getDateFormat()
98 12
    {
99
        return 'Y-m-d\TH:i:s.v\Z';
100
    }
101 162
102
    /**
103 162
     * Get the grammar specific operators.
104
     *
105
     * @return array<mixed>
106
     */
107
    public function getOperators()
108
    {
109
        return $this->comparisonOperators;
110
    }
111
112
    protected function prefixTable($table)
113
    {
114
        return $this->tablePrefix . $table;
115
    }
116 44
117
    /**
118 44
     * Compile an insert statement into AQL.
119 1
     *
120
     * @param IlluminateBuilder $query
121 44
     * @param array<mixed>   $values
122
     *
123 44
     * @return IlluminateBuilder
124
     *@throws BindException
125
     *
126
     */
127
    public function compileInsert(IlluminateBuilder $query, array $values)
128
    {
129
        if (Arr::isAssoc($values)) {
130 44
            $values = [$values];
131 44
        }
132
        $table = $this->prefixTable($query->from);
133
134 44
        if (empty($values)) {
135 44
            $query->aqb = $query->aqb->insert('{}', $table);
136 44
137 44
            return $query;
138
        }
139 44
140
        // Convert id to _key
141
        foreach ($values as $key => $value) {
142
            $values[$key] = $this->convertIdToKey($value);
143
        }
144
145
        $query->aqb = $query->aqb->let('values', $values)
146
            ->for('value', 'values')
147 10
            ->insert('value', $table)
148
            ->return('NEW._key');
149 10
150 10
        return $query;
151
    }
152 10
153
    /**
154 10
     * Compile an insert and get ID statement into SQL.
155 9
     *
156
     * @param array<mixed> $values
157
     */
158 10
    public function compileInsertGetId(IlluminateBuilder $query, $values, $sequence = "_key"): IlluminateBuilder
159
    {
160
        if (Arr::isAssoc($values)) {
161
            $values = [$values];
162
        }
163
        $table = $this->prefixTable($query->from);
164
165
        if (isset($sequence)) {
166 10
            $sequence = $this->convertIdToKey($sequence);
167 10
        }
168
169
        if (empty($values)) {
170 10
            $query->aqb = $query->aqb->insert('{}', $table)
171 10
                ->return('NEW.' . $sequence);
172 10
173 10
            return $query;
174
        }
175 10
176
        // Convert id to _key
177
        foreach ($values as $key => $value) {
178
            $values[$key] = $this->convertIdToKey($value);
179
        }
180
181
        $query->aqb = $query->aqb->let('values', $values)
182
            ->for('value', 'values')
183
            ->insert('value', $table)
184
            ->return('NEW.' . $sequence);
185 98
186
        return $query;
187 98
    }
188 98
189
    /**
190 98
     * Compile an insert statement into AQL.
191
     *
192 98
     * @param IlluminateBuilder $query
193
     * @param array<mixed> $values
194
     * @return IlluminateBuilder
195
     */
196
    public function compileInsertOrIgnore(IlluminateBuilder $query, array $values)
197
    {
198
        if (Arr::isAssoc($values)) {
199 98
            $values = [$values];
200 98
        }
201
        $table = $this->prefixTable($query->from);
202
203 98
        if (empty($values)) {
204 98
            $query->aqb = $query->aqb->insert('{}', $table);
205 98
206 98
            return $query;
207 98
        }
208
209 98
        // Convert id to _key
210
        foreach ($values as $key => $value) {
211
            $values[$key] = $this->convertIdToKey($value);
212
        }
213
214
        $query->aqb = $query->aqb->let('values', $values)
215
            ->for('value', 'values')
216
            ->insert('value', $table)
217
            ->options(["ignoreErrors" => true])
218
            ->return('NEW._key');
219
220 146
        return $query;
221
    }
222
223
    /**
224
     * Compile a truncate table statement into SQL.
225
     *
226
     * @param IlluminateBuilder $query
227
     * @return array<mixed>
228
     */
229
    public function compileTruncate(IlluminateBuilder $query)
230 146
    {
231
        /** @phpstan-ignore-next-line */
232
        $aqb = DB::aqb();
233
        $aqb = $aqb->for('doc', $query->from)->remove('doc', $query->from)->get();
234
        return [$aqb->query => []];
235
    }
236 146
237
    /**
238
     * Compile the "from" portion of the query -> FOR in AQL.
239
     *
240
     * @param IlluminateBuilder $query
241
     * @param string  $table
242
     *
243
     * @return IlluminateBuilder
244
     */
245 1
    protected function compileFrom(IlluminateBuilder $query, $table)
246
    {
247
        $table = $this->prefixTable($table);
248 1
        $alias = $this->registerTableAlias($table);
249 1
250 1
        return "FOR $alias IN $table";
0 ignored issues
show
Bug Best Practice introduced by
The expression return 'FOR '.$alias.' IN '.$table returns the type string which is incompatible with the documented return type Illuminate\Database\Query\Builder.
Loading history...
251
    }
252
253
    /**
254
     * @param  array<mixed> $variables
255
     */
256
    protected function compileVariables(IlluminateBuilder $query, array $variables): string
0 ignored issues
show
Unused Code introduced by
The parameter $query is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

256
    protected function compileVariables(/** @scrutinizer ignore-unused */ IlluminateBuilder $query, array $variables): string

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
257
    {
258
        if (empty($variables)) {
259
            return '';
260 146
        }
261
262 146
        $lets = [];
263
        foreach ($variables as $variable => $data) {
264
            $lets[] = "LET $variable =" . json_encode($data);
265
        }
266
267 146
        return implode(' ', $lets);
268 146
    }
269
270 146
    /**
271
     * Compile the "order by" portions of the query.
272
     *
273
     * @param IlluminateBuilder $query
274 146
     * @param array<mixed>   $orders
275
     *
276
     * @return IlluminateBuilder
277
     */
278
    protected function compileOrders(IlluminateBuilder $query, $orders)
279
    {
280
        if (!empty($orders)) {
281
            $orders = $this->compileOrdersToFlatArray($query, $orders);
282
            $query->aqb = $query->aqb->sort(...$orders);
283
284
            return $query;
285 146
        }
286
287 146
        return $query;
288 146
    }
289
290 146
    /**
291
     * Compile the query orders to an array.
292 146
     *
293
     * @param IlluminateBuilder $query
294
     * @param array<mixed>   $orders
295
     *
296
     * @return array<mixed>
297
     */
298
    protected function compileOrdersToFlatArray(IlluminateBuilder $query, $orders)
299
    {
300 146
        $flatOrders = [];
301
302 146
        foreach ($orders as $order) {
303 1
            if (!isset($order['type']) || $order['type'] != 'Raw') {
304 1
                $order['column'] = $this->normalizeColumn($query, $order['column']);
305
            }
306
307
            $flatOrders[] = $order['column'];
308 146
309
            if (isset($order['direction'])) {
310
                $flatOrders[] = $order['direction'];
311
            }
312
        }
313
314
        return $flatOrders;
315
    }
316
317
    /**
318
     * Compile the "offset" portions of the query.
319 3
     * We are handling this first by saving the offset which will be used by the FluentAQL's limit function.
320
     *
321 3
     * @param IlluminateBuilder $query
322 3
     * @param int     $offset
323 3
     *
324
     * @return IlluminateBuilder
325 3
     */
326
    protected function compileOffset(IlluminateBuilder $query, $offset)
327
    {
328
        $this->offset = (int) $offset;
329
330
        return $query;
331
    }
332
333
    /**
334
     * Compile the "limit" portions of the query.
335
     *
336
     * @param int     $limit
337
     */
338
    protected function compileLimit(IlluminateBuilder $query, $limit): string
339 3
    {
340
        if ($this->offset !== null) {
341 3
            return 'LIMIT ' . (int) $this->offset . ', ' . (int) $limit;
342
        }
343 3
        return 'LIMIT ' . (int) $limit;
344 3
    }
345 2
346
347
    /**
348 3
     * Compile an update statement into SQL.
349
     *
350 3
     * @param IlluminateBuilder $query
351 2
     * @param array<mixed>   $values
352
     *
353
     * @return IlluminateBuilder
354
     */
355 3
    public function compileUpdate(IlluminateBuilder $query, array $values)
356
    {
357
358
        $table = $this->prefixTable($query->from);
359
        $tableAlias = $this->generateTableAlias($table);
360
361
        $query->aqb = $query->aqb->for($tableAlias, $table);
362
363
        //Fixme: joins?
364
        $query = $this->compileWheres($query);
365
366
        $query->aqb = $query->aqb->update($tableAlias, $values, $table);
0 ignored issues
show
Bug introduced by
The property aqb does not exist on string.
Loading history...
367 4
368
        return $query;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query returns the type string which is incompatible with the documented return type Illuminate\Database\Query\Builder.
Loading history...
369 4
    }
370
371 4
    /**
372
     * Compile an "upsert" statement into SQL.
373
     *
374
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
375
     *
376
     * @param IlluminateBuilder $query
377
     * @param array<mixed> $values
378
     * @param array<mixed> $uniqueBy
379
     * @param array<mixed> $update
380
     * @return string
381
     */
382 72
    public function compileUpsert(IlluminateBuilder $query, array $values, array $uniqueBy, array $update)
383
    {
384 72
        // Convert id to _key
385 4
        foreach ($values as $key => $value) {
386
            $values[$key] = $this->convertIdToKey($value);
387 4
        }
388
389 68
        foreach ($uniqueBy as $key => $value) {
390
            $uniqueBy[$key] = $this->convertIdToKey($value);
391 68
        }
392
393
        foreach ($update as $key => $value) {
394
            $update[$key] = $this->convertIdToKey($value);
395
        }
396
397
        /** @phpstan-ignore-next-line */
398
        return DB::aqb()
399
            ->let('docs', $values)
400
            ->for('doc', 'docs')
401
            ->insert('doc', $query->from)
402
            ->options([
403 23
                "overwriteMode" => "update",
404
                "mergeObjects" => false,
405
            ])->get();
406 23
    }
407 23
408
    /**
409 23
     * Compile a delete statement into SQL.
410
     *
411
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
412 23
     * @SuppressWarnings(PHPMD.CamelCaseVariableName)
413
     *
414 23
     * @param IlluminateBuilder $query
415
     * @param null    $id
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $id is correct as it would always require null to be passed?
Loading history...
416 23
     *
417
     * @return IlluminateBuilder
418
     */
419
    public function compileDelete(IlluminateBuilder $query, $id = null)
420
    {
421
        $table = $this->prefixTable($query->from);
422
        $tableAlias = $this->generateTableAlias($table);
423
424
425
        if (!is_null($id)) {
0 ignored issues
show
introduced by
The condition is_null($id) is always true.
Loading history...
426
            $query->aqb = $query->aqb->remove((string) $id, $table);
427
428
            return $query;
429
        }
430 1
431
        $query->aqb = $query->aqb->for($tableAlias, $table);
432
433 1
        //Fixme: joins?
434 1
        $query = $this->compileWheres($query);
435
436
        $query->aqb = $query->aqb->remove($tableAlias, $table);
0 ignored issues
show
Bug introduced by
The property aqb does not exist on string.
Loading history...
437 1
438 1
        return $query;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query returns the type string which is incompatible with the documented return type Illuminate\Database\Query\Builder.
Loading history...
439
    }
440
441 1
    /**
442 1
     * Compile the random statement into SQL.
443
     *
444
     * @param  string  $seed
445
     * @return string
446 1
     */
447 1
    public function compileRandom($seed): string
448 1
    {
449 1
        return 'RAND()';
450 1
    }
451 1
452
    /**
453 1
     * @param IlluminateBuilder $query
454
     * @return IlluminateBuilder
455
     */
456
    public function compileSearch(IlluminateBuilder $query): IlluminateBuilder
457
    {
458
        $query->aqb = $query->aqb->search($query->search['predicates']);
459
460
        if (isset($query->search['options'])) {
461
            $query->aqb = $query->aqb->options($query->search['options']);
462
        }
463
464
        return $query;
465
    }
466
467 12
    /**
468
     * Get the value of a raw expression.
469 12
     *
470 12
     * @param  \Illuminate\Database\Query\Expression  $expression
471
     * @return string
472
     */
473 12
    public function getValue($expression)
474 1
    {
475
        return $expression->getValue();
476 1
    }
477
478
    /**
479 12
     * Get the grammar specific bit operators.
480
     *
481
     * @return array<mixed>
482 12
     */
483
    public function getBitwiseOperators()
484 12
    {
485
        return $this->bitwiseOperators;
486 12
    }
487
}
488