Passed
Push — next ( ff9bff...02eaaa )
by Bas
03:36
created

Grammar::compileUpdate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 2
dl 0
loc 14
ccs 7
cts 7
cp 1
crap 1
rs 10
c 0
b 0
f 0
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\HasAliases;
14
use LaravelFreelancerNL\FluentAQL\Exceptions\BindException as BindException;
15
use LaravelFreelancerNL\FluentAQL\Expressions\FunctionExpression;
16
use LaravelFreelancerNL\FluentAQL\Grammar as FluentAqlGrammar;
17
18
/*
19
 * Provides AQL syntax functions
20
 */
21
22
class Grammar extends FluentAqlGrammar
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: $aggregate, $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;
28
    use CompilesWhereClauses;
29
    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...
30
    use Macroable;
31
32
    public $name;
33
34
    /**
35
     * The grammar table prefix.
36
     *
37
     * @var string
38
     */
39
    protected $tablePrefix = '';
40
41
    /**
42
     * The grammar table prefix.
43
     *
44
     * @var null|int
45
     */
46
    protected $offset = null;
47
48
    /**
49
     * The components that make up a select clause.
50
     *
51
     * @var array
52
     */
53
    protected $selectComponents = [
54
        'from',
55
        'variables',
56
        'joins',
57
        'wheres',
58
        'groups',
59
        'aggregate',
60
        'havings',
61
        'orders',
62
        'offset',
63
        'limit',
64
        'columns',
65
    ];
66
67
    protected $operatorTranslations = [
68
        '='          => '==',
69
        '<>'         => '!=',
70
        '<=>'        => '==',
71
        'rlike'      => '=~',
72
        'not rlike'  => '!~',
73
        'regexp'     => '=~',
74
        'not regexp' => '!~',
75
    ];
76
77
    protected $whereTypeOperators = [
78
        'In'    => 'IN',
79
        'NotIn' => 'NOT IN',
80
    ];
81
82
    /**
83
     * Get the format for database stored dates.
84
     *
85
     * @return string
86
     */
87 120
    public function getDateFormat()
88
    {
89 120
        return 'Y-m-d\TH:i:s.v\Z';
90
    }
91
92
    /**
93
     * Get the grammar specific operators.
94
     *
95
     * @return array
96
     */
97 12
    public function getOperators()
98
    {
99 12
        return $this->comparisonOperators;
100
    }
101
102 145
    protected function prefixTable($table)
103
    {
104 145
        return $this->tablePrefix . $table;
105
    }
106
107
    /**
108
     * Compile an insert statement into AQL.
109
     *
110
     * @param Builder $builder
111
     * @param array   $values
112
     *
113
     * @throws BindException
114
     *
115
     * @return Builder
116
     */
117 120
    public function compileInsert(Builder $builder, array $values)
118
    {
119 120
        if (Arr::isAssoc($values)) {
120 1
            $values = [$values];
121
        }
122 120
        $table = $this->prefixTable($builder->from);
123
124 120
        if (empty($values)) {
125
            $builder->aqb = $builder->aqb->insert('{}', $table);
126
127
            return $builder;
128
        }
129
130 120
        $builder->aqb = $builder->aqb->let('values', $values)
131 120
            ->for('value', 'values')
132 120
            ->insert('value', $table)
133 120
            ->return('NEW._id');
134
135 120
        return $builder;
136
    }
137
138
    /**
139
     * Compile an insert and get ID statement into SQL.
140
     *
141
     * @param array<mixed> $values
142
     */
143 10
    public function compileInsertGetId(Builder $builder, $values, $sequence = "_id"): Builder
144
    {
145 10
        if (Arr::isAssoc($values)) {
146 10
            $values = [$values];
147
        }
148 10
        $table = $this->prefixTable($builder->from);
149
150 10
        if (empty($values)) {
151
            $builder->aqb = $builder->aqb->insert('{}', $table)
152
                ->return('NEW.' . $sequence);
153
154
            return $builder;
155
        }
156
157 10
        $builder->aqb = $builder->aqb->let('values', $values)
158 10
            ->for('value', 'values')
159 10
            ->insert('value', $table)
160 10
            ->return('NEW.' . $sequence);
161
162 10
        return $builder;
163
    }
164
165
    /**
166
     * Compile an insert statement into AQL.
167
     *
168
     * @param Builder $builder
169
     * @param array<mixed> $values
170
     * @return Builder
171
     */
172 2
    public function compileInsertOrIgnore(Builder $builder, array $values)
173
    {
174 2
        if (Arr::isAssoc($values)) {
175 2
            $values = [$values];
176
        }
177 2
        $table = $this->prefixTable($builder->from);
178
179 2
        if (empty($values)) {
180
            $builder->aqb = $builder->aqb->insert('{}', $table);
181
182
            return $builder;
183
        }
184
185 2
        $builder->aqb = $builder->aqb->let('values', $values)
186 2
            ->for('value', 'values')
187 2
            ->insert('value', $table)
188 2
            ->options(["ignoreErrors" => true])
189 2
            ->return('NEW._id');
190
191 2
        return $builder;
192
    }
193
194
195
    /**
196
     * Compile a select query into AQL.
197
     *
198
     * @param Builder $builder
199
     *
200
     * @return Builder
201
     */
202 129
    public function compileSelect(Builder $builder)
203
    {
204
//        if ($builder->unions && $builder->aggregate) {
205
//            return $this->compileUnionAggregate($builder);
206
//        }
207
208
        // To compile the query, we'll spin through each component of the query and
209
        // see if that component exists. If it does we'll just call the compiler
210
        // function for the component which is responsible for making the SQL.
211
212 129
        $builder = $this->compileComponents($builder);
213
214
//        if ($builder->unions) {
215
//            $sql = $this->wrapUnion($sql).' '.$this->compileUnions($builder);
216
//        }
217
218 129
        return $builder;
219
    }
220
221
    /**
222
     * Compile a truncate table statement into SQL.
223
     *
224
     * @param  Builder  $query
225
     * @return array
226
     */
227 1
    public function compileTruncate(Builder $query)
228
    {
229
        /** @phpstan-ignore-next-line */
230 1
        $aqb = DB::aqb();
231 1
        $aqb = $aqb->for('doc', $query->from)->remove('doc', $query->from)->get();
232 1
        return [$aqb->query => []];
233
    }
234
235
    /**
236
     * Compile the components necessary for a select clause.
237
     *
238
     * @param Builder $builder
239
     *
240
     * @return Builder
241
     */
242 129
    protected function compileComponents(Builder $builder)
243
    {
244 129
        foreach ($this->selectComponents as $component) {
245
            // To compile the query, we'll spin through each component of the query and
246
            // see if that component exists. If it does we'll just call the compiler
247
            // function for the component which is responsible for making the SQL.
248
249 129
            if (isset($builder->$component) && !is_null($builder->$component)) {
250 129
                $method = 'compile' . ucfirst($component);
251
252 129
                $builder = $this->$method($builder, $builder->$component);
253
            }
254
        }
255
256 129
        return $builder;
257
    }
258
259
    /**
260
     * Compile the "from" portion of the query -> FOR in AQL.
261
     *
262
     * @param Builder $builder
263
     * @param string  $table
264
     *
265
     * @return Builder
266
     */
267 129
    protected function compileFrom(Builder $builder, $table)
268
    {
269 129
        $table = $this->prefixTable($table);
270 129
        $alias = $this->registerTableAlias($table);
271
272 129
        $builder->aqb = $builder->aqb->for($alias, $table);
273
274 129
        return $builder;
275
    }
276
277
    /**
278
     * @param  Builder  $builder
279
     * @param  array $variables
280
     * @return Builder
281
     */
282 129
    protected function compileVariables(Builder $builder, array $variables)
283
    {
284 129
        if (! empty($variables)) {
285 1
            foreach ($variables as $variable => $data) {
286 1
                $builder->aqb = $builder->aqb->let($variable, $data);
287
            }
288
        }
289
290 129
        return $builder;
291
    }
292
293
    /**
294
     * Compile the "order by" portions of the query.
295
     *
296
     * @param Builder $builder
297
     * @param array   $orders
298
     *
299
     * @return Builder
300
     */
301 2
    protected function compileOrders(Builder $builder, $orders)
302
    {
303 2
        if (!empty($orders)) {
304 2
            $orders = $this->compileOrdersToFlatArray($builder, $orders);
305 2
            $builder->aqb = $builder->aqb->sort(...$orders);
306
307 2
            return $builder;
308
        }
309
310
        return $builder;
311
    }
312
313
    /**
314
     * Compile the query orders to an array.
315
     *
316
     * @param Builder $builder
317
     * @param array   $orders
318
     *
319
     * @return array
320
     */
321 2
    protected function compileOrdersToFlatArray(Builder $builder, $orders)
322
    {
323 2
        $flatOrders = [];
324
325 2
        foreach ($orders as $order) {
326 2
            if (!isset($order['type']) || $order['type'] != 'Raw') {
327 1
                $order['column'] = $this->normalizeColumn($builder, $order['column']);
328
            }
329
330 2
            $flatOrders[] = $order['column'];
331
332 2
            if (isset($order['direction'])) {
333 1
                $flatOrders[] = $order['direction'];
334
            }
335
        }
336
337 2
        return $flatOrders;
338
    }
339
340
    /**
341
     * Compile the "offset" portions of the query.
342
     * We are handling this first by saving the offset which will be used by the FluentAQL's limit function.
343
     *
344
     * @param Builder $builder
345
     * @param int     $offset
346
     *
347
     * @return Builder
348
     */
349 2
    protected function compileOffset(Builder $builder, $offset)
350
    {
351 2
        $this->offset = (int) $offset;
352
353 2
        return $builder;
354
    }
355
356
    /**
357
     * Compile the "limit" portions of the query.
358
     *
359
     * @param Builder $builder
360
     * @param int     $limit
361
     *
362
     * @return Builder
363
     */
364 70
    protected function compileLimit(Builder $builder, $limit)
365
    {
366 70
        if ($this->offset !== null) {
367 2
            $builder->aqb = $builder->aqb->limit((int) $this->offset, (int) $limit);
368
369 2
            return $builder;
370
        }
371 68
        $builder->aqb = $builder->aqb->limit((int) $limit);
372
373 68
        return $builder;
374
    }
375
376
377
    /**
378
     * Compile an update statement into SQL.
379
     *
380
     * @param Builder $builder
381
     * @param array   $values
382
     *
383
     * @return Builder
384
     */
385 23
    public function compileUpdate(Builder $builder, array $values)
386
    {
387
388 23
        $table = $this->prefixTable($builder->from);
389 23
        $tableAlias = $this->generateTableAlias($table);
390
391 23
        $builder->aqb = $builder->aqb->for($tableAlias, $table);
392
393
        //Fixme: joins?
394 23
        $builder = $this->compileWheres($builder);
395
396 23
        $builder->aqb = $builder->aqb->update($tableAlias, $values, $table);
397
398 23
        return $builder;
399
    }
400
401
    /**
402
     * Compile an "upsert" statement into SQL.
403
     *
404
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
405
     *
406
     * @param Builder $query
407
     * @param array $values
408
     * @param array $uniqueBy
409
     * @param array $update
410
     * @return string
411
     */
412 1
    public function compileUpsert(Builder $query, array $values, array $uniqueBy, array $update)
413
    {
414
        /** @phpstan-ignore-next-line */
415 1
        return DB::aqb()
416 1
            ->let('docs', $values)
417 1
            ->for('doc', 'docs')
418 1
            ->insert('doc', $query->from)
419 1
            ->options([
420 1
                "overwriteMode" => "update",
421
                "mergeObjects" => false,
422 1
            ])->get();
423
    }
424
425
    /**
426
     * Compile a delete statement into SQL.
427
     *
428
     * @SuppressWarnings(PHPMD.CamelCaseParameterName)
429
     * @SuppressWarnings(PHPMD.CamelCaseVariableName)
430
     *
431
     * @param Builder $builder
432
     * @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...
433
     *
434
     * @return Builder
435
     */
436 10
    public function compileDelete(Builder $builder, $id = null)
437
    {
438 10
        $table = $this->prefixTable($builder->from);
439 10
        $tableAlias = $this->generateTableAlias($table);
440
441
442 10
        if (!is_null($id)) {
0 ignored issues
show
introduced by
The condition is_null($id) is always true.
Loading history...
443 1
            $builder->aqb = $builder->aqb->remove((string) $id, $table);
444
445 1
            return $builder;
446
        }
447
448 10
        $builder->aqb = $builder->aqb->for($tableAlias, $table);
449
450
        //Fixme: joins?
451 10
        $builder = $this->compileWheres($builder);
452
453 10
        $builder->aqb = $builder->aqb->remove($tableAlias, $table);
454
455 10
        return $builder;
456
    }
457
458
    /**
459
     * Compile the random statement into SQL.
460
     *
461
     * @param Builder $builder
462
     *
463
     * @return FunctionExpression;
464
     */
465 1
    public function compileRandom(Builder $builder)
466
    {
467 1
        return $builder->aqb->rand();
468
    }
469
470
    /**
471
     * Get the value of a raw expression.
472
     *
473
     * @param  \Illuminate\Database\Query\Expression  $expression
474
     * @return string
475
     */
476 1
    public function getValue($expression)
477
    {
478 1
        return $expression->getValue();
479
    }
480
}
481