Passed
Push — experiment/id-key-conversion ( cbc737...bb5ee1 )
by Bas
03:11
created

Grammar::compileInsertGetId()   A

Complexity

Conditions 5
Paths 12

Size

Total Lines 29
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 5.1374

Importance

Changes 0
Metric Value
eloc 16
c 0
b 0
f 0
dl 0
loc 29
ccs 14
cts 17
cp 0.8235
rs 9.4222
cc 5
nc 12
nop 3
crap 5.1374
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
     * Get the format for database stored dates.
83
     *
84
     * @return string
85
     */
86 49
    public function getDateFormat()
87
    {
88 49
        return 'Y-m-d\TH:i:s.v\Z';
89
    }
90
91
    /**
92
     * Get the grammar specific operators.
93
     *
94
     * @return array
95
     */
96 12
    public function getOperators()
97
    {
98 12
        return $this->comparisonOperators;
99
    }
100
101 162
    protected function prefixTable($table)
102
    {
103 162
        return $this->tablePrefix . $table;
104
    }
105
106
    /**
107
     * Compile an insert statement into AQL.
108
     *
109
     * @param Builder $builder
110
     * @param array   $values
111
     *
112
     * @throws BindException
113
     *
114
     * @return Builder
115
     */
116 44
    public function compileInsert(Builder $builder, array $values)
117
    {
118 44
        if (Arr::isAssoc($values)) {
119 1
            $values = [$values];
120
        }
121 44
        $table = $this->prefixTable($builder->from);
122
123 44
        if (empty($values)) {
124
            $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

124
            /** @scrutinizer ignore-call */ 
125
            $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...
125
126
            return $builder;
127
        }
128
129
        // Convert id to _key
130 44
        foreach ($values as $key => $value) {
131 44
            $values[$key] = $this->convertIdToKey($value);
132
        }
133
134 44
        $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

134
        $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...
135 44
            ->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

135
            ->/** @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...
136 44
            ->insert('value', $table)
137 44
            ->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

137
            ->/** @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...
138
139 44
        return $builder;
140
    }
141
142
    /**
143
     * Compile an insert and get ID statement into SQL.
144
     *
145
     * @param array<mixed> $values
146
     */
147 10
    public function compileInsertGetId(Builder $builder, $values, $sequence = "_key"): Builder
148
    {
149 10
        if (Arr::isAssoc($values)) {
150 10
            $values = [$values];
151
        }
152 10
        $table = $this->prefixTable($builder->from);
153
154 10
        if (isset($sequence)) {
155 9
            $sequence = $this->convertIdToKey($sequence);
156
        }
157
158 10
        if (empty($values)) {
159
            $builder->aqb = $builder->aqb->insert('{}', $table)
160
                ->return('NEW.' . $sequence);
161
162
            return $builder;
163
        }
164
165
        // Convert id to _key
166 10
        foreach ($values as $key => $value) {
167 10
            $values[$key] = $this->convertIdToKey($value);
168
        }
169
170 10
        $builder->aqb = $builder->aqb->let('values', $values)
171 10
            ->for('value', 'values')
172 10
            ->insert('value', $table)
173 10
            ->return('NEW.' . $sequence);
174
175 10
        return $builder;
176
    }
177
178
    /**
179
     * Compile an insert statement into AQL.
180
     *
181
     * @param Builder $builder
182
     * @param array<mixed> $values
183
     * @return Builder
184
     */
185 98
    public function compileInsertOrIgnore(Builder $builder, array $values)
186
    {
187 98
        if (Arr::isAssoc($values)) {
188 98
            $values = [$values];
189
        }
190 98
        $table = $this->prefixTable($builder->from);
191
192 98
        if (empty($values)) {
193
            $builder->aqb = $builder->aqb->insert('{}', $table);
194
195
            return $builder;
196
        }
197
198
        // Convert id to _key
199 98
        foreach ($values as $key => $value) {
200 98
            $values[$key] = $this->convertIdToKey($value);
201
        }
202
203 98
        $builder->aqb = $builder->aqb->let('values', $values)
204 98
            ->for('value', 'values')
205 98
            ->insert('value', $table)
206 98
            ->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

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

323
            /** @scrutinizer ignore-call */ 
324
            $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...
324
325 3
            return $builder;
326
        }
327
328
        return $builder;
329
    }
330
331
    /**
332
     * Compile the query orders to an array.
333
     *
334
     * @param Builder $builder
335
     * @param array   $orders
336
     *
337
     * @return array
338
     */
339 3
    protected function compileOrdersToFlatArray(Builder $builder, $orders)
340
    {
341 3
        $flatOrders = [];
342
343 3
        foreach ($orders as $order) {
344 3
            if (!isset($order['type']) || $order['type'] != 'Raw') {
345 2
                $order['column'] = $this->normalizeColumn($builder, $order['column']);
346
            }
347
348 3
            $flatOrders[] = $order['column'];
349
350 3
            if (isset($order['direction'])) {
351 2
                $flatOrders[] = $order['direction'];
352
            }
353
        }
354
355 3
        return $flatOrders;
356
    }
357
358
    /**
359
     * Compile the "offset" portions of the query.
360
     * We are handling this first by saving the offset which will be used by the FluentAQL's limit function.
361
     *
362
     * @param Builder $builder
363
     * @param int     $offset
364
     *
365
     * @return Builder
366
     */
367 4
    protected function compileOffset(Builder $builder, $offset)
368
    {
369 4
        $this->offset = (int) $offset;
370
371 4
        return $builder;
372
    }
373
374
    /**
375
     * Compile the "limit" portions of the query.
376
     *
377
     * @param Builder $builder
378
     * @param int     $limit
379
     *
380
     * @return Builder
381
     */
382 72
    protected function compileLimit(Builder $builder, $limit)
383
    {
384 72
        if ($this->offset !== null) {
385 4
            $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

385
            /** @scrutinizer ignore-call */ 
386
            $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...
386
387 4
            return $builder;
388
        }
389 68
        $builder->aqb = $builder->aqb->limit((int) $limit);
390
391 68
        return $builder;
392
    }
393
394
395
    /**
396
     * Compile an update statement into SQL.
397
     *
398
     * @param Builder $builder
399
     * @param array   $values
400
     *
401
     * @return Builder
402
     */
403 23
    public function compileUpdate(Builder $builder, array $values)
404
    {
405
406 23
        $table = $this->prefixTable($builder->from);
407 23
        $tableAlias = $this->generateTableAlias($table);
408
409 23
        $builder->aqb = $builder->aqb->for($tableAlias, $table);
410
411
        //Fixme: joins?
412 23
        $builder = $this->compileWheres($builder);
413
414 23
        $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

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

484
        /** @scrutinizer ignore-call */ 
485
        $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...
485
486 12
        return $builder;
487
    }
488
489
    /**
490
     * Compile the random statement into SQL.
491
     *
492
     * @param Builder $builder
493
     *
494
     * @return FunctionExpression;
495
     */
496 1
    public function compileRandom(Builder $builder)
497
    {
498 1
        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

498
        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...
499
    }
500
501
    /**
502
     * @param Builder $builder
503
     * @return Builder|\LaravelFreelancerNL\FluentAQL\QueryBuilder|null
504
     */
505 7
    public function compileSearch(Builder $builder): Builder
506
    {
507 7
        $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

507
        /** @scrutinizer ignore-call */ 
508
        $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...
508
509 7
        if (isset($builder->search['options'])) {
510 3
            $builder->aqb = $builder->aqb->options($builder->search['options']);
511
        }
512
513 7
        return $builder;
514
    }
515
516
    /**
517
     * Get the value of a raw expression.
518
     *
519
     * @param  \Illuminate\Database\Query\Expression  $expression
520
     * @return string
521
     */
522 1
    public function getValue($expression)
523
    {
524 1
        return $expression->getValue();
525
    }
526
}
527