Passed
Push — next ( 230762...ff9bff )
by Bas
08:27
created

Grammar::compileTruncate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 6
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
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 103
     */
87
    public function getDateFormat()
88 103
    {
89
        return 'Y-m-d\TH:i:s.v\Z';
90
    }
91
92
    /**
93
     * Get the grammar specific operators.
94
     *
95
     * @return array
96 11
     */
97
    public function getOperators()
98 11
    {
99
        return $this->comparisonOperators;
100
    }
101 128
102
    protected function prefixTable($table)
103 128
    {
104
        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 103
     */
117
    public function compileInsert(Builder $builder, array $values)
118 103
    {
119 1
        if (Arr::isAssoc($values)) {
120
            $values = [$values];
121 103
        }
122
        $table = $this->prefixTable($builder->from);
123 103
124
        if (empty($values)) {
125
            $builder->aqb = $builder->aqb->insert('{}', $table);
126
127
            return $builder;
128
        }
129 103
130 103
        $builder->aqb = $builder->aqb->let('values', $values)
131 103
            ->for('value', 'values')
132 103
            ->insert('value', $table)
133
            ->return('NEW._id');
134 103
135
        return $builder;
136
    }
137
138
    /**
139
     * Compile an insert and get ID statement into SQL.
140
     *
141
     * @param array<mixed> $values
142 8
     */
143
    public function compileInsertGetId(Builder $builder, $values, $sequence = "_id"): Builder
144 8
    {
145 8
        if (Arr::isAssoc($values)) {
146
            $values = [$values];
147 8
        }
148
        $table = $this->prefixTable($builder->from);
149 8
150
        if (empty($values)) {
151
            $builder->aqb = $builder->aqb->insert('{}', $table)
152
                ->return('NEW.' . $sequence);
153
154
            return $builder;
155
        }
156 8
157 8
        $builder->aqb = $builder->aqb->let('values', $values)
158 8
            ->for('value', 'values')
159 8
            ->insert('value', $table)
160
            ->return('NEW.' . $sequence);
161 8
162
        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 2
     */
172
    public function compileInsertOrIgnore(Builder $builder, array $values)
173 2
    {
174 2
        if (Arr::isAssoc($values)) {
175
            $values = [$values];
176 2
        }
177
        $table = $this->prefixTable($builder->from);
178 2
179
        if (empty($values)) {
180
            $builder->aqb = $builder->aqb->insert('{}', $table);
181
182
            return $builder;
183
        }
184 2
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
            ->return('NEW._id');
190 2
191
        return $builder;
192
    }
193
194
195
    /**
196
     * Compile a select query into AQL.
197
     *
198
     * @param Builder $builder
199
     *
200
     * @return Builder
201 113
     */
202
    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 113
212
        $builder = $this->compileComponents($builder);
213
214
//        if ($builder->unions) {
215
//            $sql = $this->wrapUnion($sql).' '.$this->compileUnions($builder);
216
//        }
217 113
218
        return $builder;
219
    }
220
221
    /**
222
     * Compile a truncate table statement into SQL.
223
     *
224
     * @param  Builder  $query
225
     * @return array
226
     */
227 113
    public function compileTruncate(Builder $query)
228
    {
229 113
        /** @phpstan-ignore-next-line */
230
        $aqb = DB::aqb();
231
        $aqb = $aqb->for('doc', $query->from)->remove('doc', $query->from)->get();
232
        return [$aqb->query => []];
233
    }
234 113
235 113
    /**
236
     * Compile the components necessary for a select clause.
237 113
     *
238
     * @param Builder $builder
239
     *
240
     * @return Builder
241 113
     */
242
    protected function compileComponents(Builder $builder)
243
    {
244
        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
            if (isset($builder->$component) && !is_null($builder->$component)) {
250
                $method = 'compile' . ucfirst($component);
251
252 113
                $builder = $this->$method($builder, $builder->$component);
253
            }
254 113
        }
255 113
256
        return $builder;
257 113
    }
258
259 113
    /**
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 113
    protected function compileFrom(Builder $builder, $table)
268
    {
269 113
        $table = $this->prefixTable($table);
270 1
        $alias = $this->registerTableAlias($table);
271 1
272
        $builder->aqb = $builder->aqb->for($alias, $table);
273
274
        return $builder;
275 113
    }
276
277
    /**
278
     * @param  Builder  $builder
279
     * @param  array $variables
280
     * @return Builder
281
     */
282
    protected function compileVariables(Builder $builder, array $variables)
283
    {
284
        if (! empty($variables)) {
285
            foreach ($variables as $variable => $data) {
286 2
                $builder->aqb = $builder->aqb->let($variable, $data);
287
            }
288 2
        }
289 2
290 2
        return $builder;
291
    }
292 2
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
    protected function compileOrders(Builder $builder, $orders)
302
    {
303
        if (!empty($orders)) {
304
            $orders = $this->compileOrdersToFlatArray($builder, $orders);
305
            $builder->aqb = $builder->aqb->sort(...$orders);
306 2
307
            return $builder;
308 2
        }
309
310 2
        return $builder;
311 2
    }
312 1
313
    /**
314
     * Compile the query orders to an array.
315 2
     *
316
     * @param Builder $builder
317 2
     * @param array   $orders
318 1
     *
319
     * @return array
320
     */
321
    protected function compileOrdersToFlatArray(Builder $builder, $orders)
322 2
    {
323
        $flatOrders = [];
324
325
        foreach ($orders as $order) {
326
            if (!isset($order['type']) || $order['type'] != 'Raw') {
327
                $order['column'] = $this->normalizeColumn($builder, $order['column']);
328
            }
329
330
            $flatOrders[] = $order['column'];
331
332
            if (isset($order['direction'])) {
333
                $flatOrders[] = $order['direction'];
334 2
            }
335
        }
336 2
337
        return $flatOrders;
338 2
    }
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 56
    protected function compileOffset(Builder $builder, $offset)
350
    {
351 56
        $this->offset = (int) $offset;
352 2
353
        return $builder;
354 2
    }
355
356 54
    /**
357
     * Compile the "limit" portions of the query.
358 54
     *
359
     * @param Builder $builder
360
     * @param int     $limit
361
     *
362
     * @return Builder
363
     */
364
    protected function compileLimit(Builder $builder, $limit)
365
    {
366
        if ($this->offset !== null) {
367
            $builder->aqb = $builder->aqb->limit((int) $this->offset, (int) $limit);
368
369
            return $builder;
370 19
        }
371
        $builder->aqb = $builder->aqb->limit((int) $limit);
372
373 19
        return $builder;
374 19
    }
375
376 19
377
    /**
378
     * Compile an update statement into SQL.
379 19
     *
380
     * @param Builder $builder
381 19
     * @param array   $values
382
     *
383 19
     * @return Builder
384
     */
385
    public function compileUpdate(Builder $builder, array $values)
386
    {
387
388
        $table = $this->prefixTable($builder->from);
389
        $tableAlias = $this->generateTableAlias($table);
390
391
        $builder->aqb = $builder->aqb->for($tableAlias, $table);
392
393
        //Fixme: joins?
394
        $builder = $this->compileWheres($builder);
395
396
        $builder->aqb = $builder->aqb->update($tableAlias, $values, $table);
397 9
398
        return $builder;
399 9
    }
400 9
401
    /**
402
     * Compile an "upsert" statement into SQL.
403 9
     *
404 1
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
405
     *
406 1
     * @param Builder $query
407
     * @param array $values
408
     * @param array $uniqueBy
409 9
     * @param array $update
410
     * @return string
411
     */
412 9
    public function compileUpsert(Builder $query, array $values, array $uniqueBy, array $update)
413
    {
414 9
        /** @phpstan-ignore-next-line */
415
        return DB::aqb()
416 9
            ->let('docs', $values)
417
            ->for('doc', 'docs')
418
            ->insert('doc', $query->from)
419
            ->options([
420
                "overwriteMode" => "update",
421
                "mergeObjects" => false,
422
            ])->get();
423
    }
424
425
    /**
426 1
     * Compile a delete statement into SQL.
427
     *
428 1
     * @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
    public function compileDelete(Builder $builder, $id = null)
437 1
    {
438
        $table = $this->prefixTable($builder->from);
439 1
        $tableAlias = $this->generateTableAlias($table);
440
441
442
        if (!is_null($id)) {
0 ignored issues
show
introduced by
The condition is_null($id) is always true.
Loading history...
443
            $builder->aqb = $builder->aqb->remove((string) $id, $table);
444
445
            return $builder;
446
        }
447
448
        $builder->aqb = $builder->aqb->for($tableAlias, $table);
449
450
        //Fixme: joins?
451
        $builder = $this->compileWheres($builder);
452
453
        $builder->aqb = $builder->aqb->remove($tableAlias, $table);
454
455
        return $builder;
456
    }
457
458
    /**
459
     * Compile the random statement into SQL.
460
     *
461
     * @param Builder $builder
462
     *
463
     * @return FunctionExpression;
464
     */
465
    public function compileRandom(Builder $builder)
466
    {
467
        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
    public function getValue($expression)
477
    {
478
        return $expression->getValue();
479
    }
480
}
481