Passed
Push — next ( ed4ce4...be2ec6 )
by Bas
12:50
created

Grammar::getBitOperators()   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
eloc 1
c 0
b 0
f 0
dl 0
loc 3
ccs 0
cts 0
cp 0
rs 10
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
namespace LaravelFreelancerNL\Aranguent\Query;
4
5
use Illuminate\Support\Arr;
6
use Illuminate\Support\Facades\DB;
7
use Illuminate\Support\Traits\Macroable;
8
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesAggregates;
9
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesColumns;
10
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesGroups;
11
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesJoins;
12
use LaravelFreelancerNL\Aranguent\Query\Concerns\CompilesWhereClauses;
13
use LaravelFreelancerNL\Aranguent\Query\Concerns\ConvertsIdToKey;
14
use LaravelFreelancerNL\Aranguent\Query\Concerns\HasAliases;
15
use LaravelFreelancerNL\FluentAQL\Exceptions\BindException as BindException;
16
use LaravelFreelancerNL\FluentAQL\Expressions\FunctionExpression;
17
use LaravelFreelancerNL\FluentAQL\Grammar as FluentAqlGrammar;
18
19
class Grammar extends FluentAqlGrammar
20
{
21
    use CompilesAggregates;
22
    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: $aggregate, $groups, $distinct, $from, $joins, $table
Loading history...
23
    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...
24
    use CompilesGroups;
25
    use CompilesWhereClauses;
26
    use ConvertsIdToKey;
27
    use HasAliases;
0 ignored issues
show
introduced by
The trait LaravelFreelancerNL\Aran...ery\Concerns\HasAliases requires some properties which are not provided by LaravelFreelancerNL\Aranguent\Query\Grammar: $variables, $groups, $from
Loading history...
28
    use Macroable;
29
30
    public $name;
31
32
    /**
33
     * The grammar table prefix.
34
     *
35
     * @var string
36
     */
37
    protected $tablePrefix = '';
38
39
    /**
40
     * The grammar table prefix.
41
     *
42
     * @var null|int
43
     */
44
    protected $offset = null;
45
46
    /**
47
     * The components that make up a select clause.
48
     *
49
     * @var array
50
     */
51
    protected $selectComponents = [
52
        'from',
53
        'search',
54
        'variables',
55
        'joins',
56
        'wheres',
57
        'groups',
58
        'aggregate',
59
        'havings',
60
        'orders',
61
        'offset',
62
        'limit',
63
        'columns',
64
    ];
65
66
    protected $operatorTranslations = [
67
        '='          => '==',
68
        '<>'         => '!=',
69
        '<=>'        => '==',
70
        'rlike'      => '=~',
71
        'not rlike'  => '!~',
72
        'regexp'     => '=~',
73
        'not regexp' => '!~',
74
    ];
75
76
    protected $whereTypeOperators = [
77
        'In'    => 'IN',
78
        'NotIn' => 'NOT IN',
79
    ];
80
81
    /**
82
     * The grammar specific bit operators.
83
     *
84
     * @var array
85
     */
86 49
    protected $bitOperators = [];
87
88 49
    /**
89
     * Get the format for database stored dates.
90
     *
91
     * @return string
92
     */
93
    public function getDateFormat()
94
    {
95
        return 'Y-m-d\TH:i:s.v\Z';
96 12
    }
97
98 12
    /**
99
     * Get the grammar specific operators.
100
     *
101 162
     * @return array
102
     */
103 162
    public function getOperators()
104
    {
105
        return $this->comparisonOperators;
106
    }
107
108
    protected function prefixTable($table)
109
    {
110
        return $this->tablePrefix . $table;
111
    }
112
113
    /**
114
     * Compile an insert statement into AQL.
115
     *
116 44
     * @param Builder $builder
117
     * @param array   $values
118 44
     *
119 1
     * @throws BindException
120
     *
121 44
     * @return Builder
122
     */
123 44
    public function compileInsert(Builder $builder, array $values)
124
    {
125
        if (Arr::isAssoc($values)) {
126
            $values = [$values];
127
        }
128
        $table = $this->prefixTable($builder->from);
129
130 44
        if (empty($values)) {
131 44
            $builder->aqb = $builder->aqb->insert('{}', $table);
0 ignored issues
show
Bug introduced by
The method insert() does not exist on LaravelFreelancerNL\Flue...ions\FunctionExpression. ( Ignorable by Annotation )

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

131
            /** @scrutinizer ignore-call */ 
132
            $builder->aqb = $builder->aqb->insert('{}', $table);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
132
133
            return $builder;
134 44
        }
135 44
136 44
        // Convert id to _key
137 44
        foreach ($values as $key => $value) {
138
            $values[$key] = $this->convertIdToKey($value);
139 44
        }
140
141
        $builder->aqb = $builder->aqb->let('values', $values)
0 ignored issues
show
Bug introduced by
The method let() does not exist on LaravelFreelancerNL\Flue...ions\FunctionExpression. ( Ignorable by Annotation )

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

141
        $builder->aqb = $builder->aqb->/** @scrutinizer ignore-call */ let('values', $values)

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
142
            ->for('value', 'values')
0 ignored issues
show
Bug introduced by
The method for() does not exist on LaravelFreelancerNL\Flue...ions\FunctionExpression. ( Ignorable by Annotation )

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

142
            ->/** @scrutinizer ignore-call */ for('value', 'values')

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
143
            ->insert('value', $table)
144
            ->return('NEW._key');
0 ignored issues
show
Bug introduced by
The method return() does not exist on LaravelFreelancerNL\Flue...ions\FunctionExpression. ( Ignorable by Annotation )

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

144
            ->/** @scrutinizer ignore-call */ return('NEW._key');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
145
146
        return $builder;
147 10
    }
148
149 10
    /**
150 10
     * Compile an insert and get ID statement into SQL.
151
     *
152 10
     * @param array<mixed> $values
153
     */
154 10
    public function compileInsertGetId(Builder $builder, $values, $sequence = "_key"): Builder
155 9
    {
156
        if (Arr::isAssoc($values)) {
157
            $values = [$values];
158 10
        }
159
        $table = $this->prefixTable($builder->from);
160
161
        if (isset($sequence)) {
162
            $sequence = $this->convertIdToKey($sequence);
163
        }
164
165
        if (empty($values)) {
166 10
            $builder->aqb = $builder->aqb->insert('{}', $table)
167 10
                ->return('NEW.' . $sequence);
168
169
            return $builder;
170 10
        }
171 10
172 10
        // Convert id to _key
173 10
        foreach ($values as $key => $value) {
174
            $values[$key] = $this->convertIdToKey($value);
175 10
        }
176
177
        $builder->aqb = $builder->aqb->let('values', $values)
178
            ->for('value', 'values')
179
            ->insert('value', $table)
180
            ->return('NEW.' . $sequence);
181
182
        return $builder;
183
    }
184
185 98
    /**
186
     * Compile an insert statement into AQL.
187 98
     *
188 98
     * @param Builder $builder
189
     * @param array<mixed> $values
190 98
     * @return Builder
191
     */
192 98
    public function compileInsertOrIgnore(Builder $builder, array $values)
193
    {
194
        if (Arr::isAssoc($values)) {
195
            $values = [$values];
196
        }
197
        $table = $this->prefixTable($builder->from);
198
199 98
        if (empty($values)) {
200 98
            $builder->aqb = $builder->aqb->insert('{}', $table);
201
202
            return $builder;
203 98
        }
204 98
205 98
        // Convert id to _key
206 98
        foreach ($values as $key => $value) {
207 98
            $values[$key] = $this->convertIdToKey($value);
208
        }
209 98
210
        $builder->aqb = $builder->aqb->let('values', $values)
211
            ->for('value', 'values')
212
            ->insert('value', $table)
213
            ->options(["ignoreErrors" => true])
0 ignored issues
show
Bug introduced by
The method options() does not exist on LaravelFreelancerNL\Flue...ions\FunctionExpression. ( Ignorable by Annotation )

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

213
            ->/** @scrutinizer ignore-call */ options(["ignoreErrors" => true])

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
214
            ->return('NEW._key');
215
216
        return $builder;
217
    }
218
219
220 146
    /**
221
     * Compile a select query into AQL.
222
     *
223
     * @param Builder $builder
224
     *
225
     * @return Builder
226
     */
227
    public function compileSelect(Builder $builder)
228
    {
229
//        if ($builder->unions && $builder->aggregate) {
230 146
//            return $this->compileUnionAggregate($builder);
231
//        }
232
233
        // To compile the query, we'll spin through each component of the query and
234
        // see if that component exists. If it does we'll just call the compiler
235
        // function for the component which is responsible for making the SQL.
236 146
237
        $builder = $this->compileComponents($builder);
238
239
//        if ($builder->unions) {
240
//            $sql = $this->wrapUnion($sql).' '.$this->compileUnions($builder);
241
//        }
242
243
        return $builder;
244
    }
245 1
246
    /**
247
     * Compile a truncate table statement into SQL.
248 1
     *
249 1
     * @param  Builder  $query
250 1
     * @return array
251
     */
252
    public function compileTruncate(Builder $query)
253
    {
254
        /** @phpstan-ignore-next-line */
255
        $aqb = DB::aqb();
256
        $aqb = $aqb->for('doc', $query->from)->remove('doc', $query->from)->get();
257
        return [$aqb->query => []];
258
    }
259
260 146
    /**
261
     * Compile the components necessary for a select clause.
262 146
     *
263
     * @param Builder $builder
264
     *
265
     * @return Builder
266
     */
267 146
    protected function compileComponents(Builder $builder)
268 146
    {
269
        foreach ($this->selectComponents as $component) {
270 146
            // To compile the query, we'll spin through each component of the query and
271
            // see if that component exists. If it does we'll just call the compiler
272
            // function for the component which is responsible for making the SQL.
273
274 146
            if (isset($builder->$component) && !is_null($builder->$component)) {
275
                $method = 'compile' . ucfirst($component);
276
277
                $builder = $this->$method($builder, $builder->$component);
278
            }
279
        }
280
281
        return $builder;
282
    }
283
284
    /**
285 146
     * Compile the "from" portion of the query -> FOR in AQL.
286
     *
287 146
     * @param Builder $builder
288 146
     * @param string  $table
289
     *
290 146
     * @return Builder
291
     */
292 146
    protected function compileFrom(Builder $builder, $table)
293
    {
294
        $table = $this->prefixTable($table);
295
        $alias = $this->registerTableAlias($table);
296
297
        $builder->aqb = $builder->aqb->for($alias, $table);
298
299
        return $builder;
300 146
    }
301
302 146
    /**
303 1
     * @param  Builder  $builder
304 1
     * @param  array $variables
305
     * @return Builder
306
     */
307
    protected function compileVariables(Builder $builder, array $variables)
308 146
    {
309
        if (! empty($variables)) {
310
            foreach ($variables as $variable => $data) {
311
                $builder->aqb = $builder->aqb->let($variable, $data);
312
            }
313
        }
314
315
        return $builder;
316
    }
317
318
    /**
319 3
     * Compile the "order by" portions of the query.
320
     *
321 3
     * @param Builder $builder
322 3
     * @param array   $orders
323 3
     *
324
     * @return Builder
325 3
     */
326
    protected function compileOrders(Builder $builder, $orders)
327
    {
328
        if (!empty($orders)) {
329
            $orders = $this->compileOrdersToFlatArray($builder, $orders);
330
            $builder->aqb = $builder->aqb->sort(...$orders);
0 ignored issues
show
Bug introduced by
The method sort() does not exist on LaravelFreelancerNL\Flue...ions\FunctionExpression. ( Ignorable by Annotation )

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

330
            /** @scrutinizer ignore-call */ 
331
            $builder->aqb = $builder->aqb->sort(...$orders);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
331
332
            return $builder;
333
        }
334
335
        return $builder;
336
    }
337
338
    /**
339 3
     * Compile the query orders to an array.
340
     *
341 3
     * @param Builder $builder
342
     * @param array   $orders
343 3
     *
344 3
     * @return array
345 2
     */
346
    protected function compileOrdersToFlatArray(Builder $builder, $orders)
347
    {
348 3
        $flatOrders = [];
349
350 3
        foreach ($orders as $order) {
351 2
            if (!isset($order['type']) || $order['type'] != 'Raw') {
352
                $order['column'] = $this->normalizeColumn($builder, $order['column']);
353
            }
354
355 3
            $flatOrders[] = $order['column'];
356
357
            if (isset($order['direction'])) {
358
                $flatOrders[] = $order['direction'];
359
            }
360
        }
361
362
        return $flatOrders;
363
    }
364
365
    /**
366
     * Compile the "offset" portions of the query.
367 4
     * We are handling this first by saving the offset which will be used by the FluentAQL's limit function.
368
     *
369 4
     * @param Builder $builder
370
     * @param int     $offset
371 4
     *
372
     * @return Builder
373
     */
374
    protected function compileOffset(Builder $builder, $offset)
375
    {
376
        $this->offset = (int) $offset;
377
378
        return $builder;
379
    }
380
381
    /**
382 72
     * Compile the "limit" portions of the query.
383
     *
384 72
     * @param Builder $builder
385 4
     * @param int     $limit
386
     *
387 4
     * @return Builder
388
     */
389 68
    protected function compileLimit(Builder $builder, $limit)
390
    {
391 68
        if ($this->offset !== null) {
392
            $builder->aqb = $builder->aqb->limit((int) $this->offset, (int) $limit);
0 ignored issues
show
Bug introduced by
The method limit() does not exist on LaravelFreelancerNL\Flue...ions\FunctionExpression. ( Ignorable by Annotation )

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

392
            /** @scrutinizer ignore-call */ 
393
            $builder->aqb = $builder->aqb->limit((int) $this->offset, (int) $limit);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
393
394
            return $builder;
395
        }
396
        $builder->aqb = $builder->aqb->limit((int) $limit);
397
398
        return $builder;
399
    }
400
401
402
    /**
403 23
     * Compile an update statement into SQL.
404
     *
405
     * @param Builder $builder
406 23
     * @param array   $values
407 23
     *
408
     * @return Builder
409 23
     */
410
    public function compileUpdate(Builder $builder, array $values)
411
    {
412 23
413
        $table = $this->prefixTable($builder->from);
414 23
        $tableAlias = $this->generateTableAlias($table);
415
416 23
        $builder->aqb = $builder->aqb->for($tableAlias, $table);
417
418
        //Fixme: joins?
419
        $builder = $this->compileWheres($builder);
420
421
        $builder->aqb = $builder->aqb->update($tableAlias, $values, $table);
0 ignored issues
show
Bug introduced by
The method update() does not exist on LaravelFreelancerNL\Flue...ions\FunctionExpression. ( Ignorable by Annotation )

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

421
        /** @scrutinizer ignore-call */ 
422
        $builder->aqb = $builder->aqb->update($tableAlias, $values, $table);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
422
423
        return $builder;
424
    }
425
426
    /**
427
     * Compile an "upsert" statement into SQL.
428
     *
429
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
430 1
     *
431
     * @param Builder $query
432
     * @param array $values
433 1
     * @param array $uniqueBy
434 1
     * @param array $update
435
     * @return string
436
     */
437 1
    public function compileUpsert(Builder $query, array $values, array $uniqueBy, array $update)
438 1
    {
439
        // Convert id to _key
440
        foreach ($values as $key => $value) {
441 1
            $values[$key] = $this->convertIdToKey($value);
442 1
        }
443
444
        foreach ($uniqueBy as $key => $value) {
445
            $uniqueBy[$key] = $this->convertIdToKey($value);
446 1
        }
447 1
448 1
        foreach ($update as $key => $value) {
449 1
            $update[$key] = $this->convertIdToKey($value);
450 1
        }
451 1
452
        /** @phpstan-ignore-next-line */
453 1
        return DB::aqb()
454
            ->let('docs', $values)
455
            ->for('doc', 'docs')
456
            ->insert('doc', $query->from)
457
            ->options([
458
                "overwriteMode" => "update",
459
                "mergeObjects" => false,
460
            ])->get();
461
    }
462
463
    /**
464
     * Compile a delete statement into SQL.
465
     *
466
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
467 12
     * @SuppressWarnings(PHPMD.CamelCaseVariableName)
468
     *
469 12
     * @param Builder $builder
470 12
     * @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...
471
     *
472
     * @return Builder
473 12
     */
474 1
    public function compileDelete(Builder $builder, $id = null)
475
    {
476 1
        $table = $this->prefixTable($builder->from);
477
        $tableAlias = $this->generateTableAlias($table);
478
479 12
480
        if (!is_null($id)) {
0 ignored issues
show
introduced by
The condition is_null($id) is always true.
Loading history...
481
            $builder->aqb = $builder->aqb->remove((string) $id, $table);
482 12
483
            return $builder;
484 12
        }
485
486 12
        $builder->aqb = $builder->aqb->for($tableAlias, $table);
487
488
        //Fixme: joins?
489
        $builder = $this->compileWheres($builder);
490
491
        $builder->aqb = $builder->aqb->remove($tableAlias, $table);
0 ignored issues
show
Bug introduced by
The method remove() does not exist on LaravelFreelancerNL\Flue...ions\FunctionExpression. ( Ignorable by Annotation )

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

491
        /** @scrutinizer ignore-call */ 
492
        $builder->aqb = $builder->aqb->remove($tableAlias, $table);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
492
493
        return $builder;
494
    }
495
496 1
    /**
497
     * Compile the random statement into SQL.
498 1
     *
499
     * @param Builder $builder
500
     *
501
     * @return FunctionExpression;
502
     */
503
    public function compileRandom(Builder $builder)
504
    {
505 7
        return $builder->aqb->rand();
0 ignored issues
show
Bug introduced by
The method rand() does not exist on LaravelFreelancerNL\Flue...ions\FunctionExpression. ( Ignorable by Annotation )

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

505
        return $builder->aqb->/** @scrutinizer ignore-call */ rand();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
506
    }
507 7
508
    /**
509 7
     * @param Builder $builder
510 3
     * @return Builder
511
     */
512
    public function compileSearch(Builder $builder): Builder
513 7
    {
514
        $builder->aqb = $builder->aqb->search($builder->search['predicates']);
0 ignored issues
show
Bug introduced by
The method search() does not exist on LaravelFreelancerNL\Flue...ions\FunctionExpression. ( Ignorable by Annotation )

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

514
        /** @scrutinizer ignore-call */ 
515
        $builder->aqb = $builder->aqb->search($builder->search['predicates']);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
515
516
        if (isset($builder->search['options'])) {
517
            $builder->aqb = $builder->aqb->options($builder->search['options']);
518
        }
519
520
        return $builder;
521
    }
522 1
523
    /**
524 1
     * Get the value of a raw expression.
525
     *
526
     * @param  \Illuminate\Database\Query\Expression  $expression
527
     * @return string
528
     */
529
    public function getValue($expression)
530
    {
531
        return $expression->getValue();
532
    }
533
534
    /**
535
     * Get the grammar specific bit operators.
536
     *
537
     * @return array
538
     */
539
    public function getBitOperators()
540
    {
541
        return $this->bitOperators;
542
    }
543
}
544