Passed
Pull Request — master (#38)
by Bas
17:19
created

Grammar::determineReturnValues()   B

Complexity

Conditions 9
Paths 48

Size

Total Lines 28
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

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