Completed
Push — master ( 89deac...cf3c32 )
by Bas
02:49
created

Grammar::compileUpdate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 7
nc 1
nop 2
dl 0
loc 12
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace LaravelFreelancerNL\Aranguent\Query;
4
5
use Illuminate\Support\Str;
6
use Illuminate\Support\Traits\Macroable;
7
use LaravelFreelancerNL\FluentAQL\Exceptions\BindException as BindException;
8
use LaravelFreelancerNL\FluentAQL\Grammar as FluentAqlGrammar;
9
use LaravelFreelancerNL\FluentAQL\QueryBuilder as FluentAQL;
10
11
/*
12
 * Provides AQL syntax functions
13
 */
14
class Grammar extends FluentAqlGrammar
15
{
16
17
    use Macroable;
0 ignored issues
show
Bug introduced by
The trait Illuminate\Support\Traits\Macroable requires the property $name which is not provided by LaravelFreelancerNL\Aranguent\Query\Grammar.
Loading history...
18
19
    /**
20
     * The grammar table prefix.
21
     *
22
     * @var string
23
     */
24
    protected $tablePrefix = '';
25
26
27
    /**
28
     * The grammar table prefix.
29
     *
30
     * @var null|int
31
     */
32
    protected $offset = null;
33
34
    /**
35
     * The components that make up a select clause.
36
     *
37
     * @var array
38
     */
39
    protected $selectComponents = [
40
        'lock',
41
        'aggregate',
42
        'from',
43
        'joins',
44
        'wheres',
45
        'groups',
46
        'havings',
47
        'orders',
48
        'offset',
49
        'limit',
50
        'columns',
51
    ];
52
53
    /**
54
     * @param Builder $builder
55
     * @param $table
56
     * @param string $postfix
57
     * @return mixed
58
     */
59
    protected function generateTableAlias($builder, $table, $postfix = 'Doc')
60
    {
61
        $builder->registerAlias($table, Str::singular($table).$postfix);
62
        return $builder;
63
    }
64
65
    protected function prefixTable($table)
66
    {
67
        return $this->tablePrefix.$table;
68
    }
69
70
    /**
71
     * Compile an insert statement into AQL.
72
     *
73
     * @param Builder $builder
74
     * @param array $values
75
     * @return string
76
     * @throws BindException
77
     */
78
    public function compileInsert(Builder $builder, array $values)
79
    {
80
        $table = $this->prefixTable($builder->from);
81
82
        if (empty($values)) {
83
            $builder->aqb = $builder->aqb->insert('{}', $table)->get();
84
            return $builder;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $builder returns the type LaravelFreelancerNL\Aranguent\Query\Builder which is incompatible with the documented return type string.
Loading history...
85
        }
86
87
        $builder->aqb = $builder->aqb->let('docs', $builder->aqb->bind($values))
88
            ->for('doc', 'docs')
89
            ->insert('doc', $table)
90
            ->return('NEW._key')
91
            ->get();
92
        return $builder;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $builder returns the type LaravelFreelancerNL\Aranguent\Query\Builder which is incompatible with the documented return type string.
Loading history...
93
    }
94
95
    /**
96
     * Compile an insert and get ID statement into SQL.
97
     *
98
     * @param Builder $builder
99
     * @param array $values
100
     * @return string
101
     * @throws BindException
102
     */
103
    public function compileInsertGetId(Builder $builder, $values)
104
    {
105
        return $this->compileInsert($builder, $values);
106
    }
107
108
    /**
109
     * Compile a select query into AQL.
110
     *
111
     * @param  Builder  $builder
112
     * @return string
113
     */
114
    public function compileSelect(Builder $builder)
115
    {
116
//        if ($builder->unions && $builder->aggregate) {
117
//            return $this->compileUnionAggregate($builder);
118
//        }
119
120
        // To compile the query, we'll spin through each component of the query and
121
        // see if that component exists. If it does we'll just call the compiler
122
        // function for the component which is responsible for making the SQL.
123
124
        $builder = $this->compileComponents($builder);
125
126
127
//        if ($builder->unions) {
128
//            $sql = $this->wrapUnion($sql).' '.$this->compileUnions($builder);
129
//        }
130
131
        $builder->aqb = $builder->aqb->get();
132
        return $builder;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $builder returns the type array which is incompatible with the documented return type string.
Loading history...
133
    }
134
135
    /**
136
     * Compile the components necessary for a select clause.
137
     *
138
     * @param Builder $builder
139
     * @return array
140
     */
141
    protected function compileComponents(Builder $builder)
142
    {
143
        foreach ($this->selectComponents as $component) {
144
            // To compile the query, we'll spin through each component of the query and
145
            // see if that component exists. If it does we'll just call the compiler
146
            // function for the component which is responsible for making the SQL.
147
148
            if (isset($builder->$component) && ! is_null($builder->$component)) {
149
                $method = 'compile'.ucfirst($component);
150
151
                $builder = $this->$method($builder, $builder->$component);
152
            }
153
        }
154
155
        return $builder;
156
    }
157
158
159
    /**
160
     * Compile the "from" portion of the query -> FOR in AQL.
161
     *
162
     * @param Builder $builder
163
     * @param string $table
164
     * @return FluentAQL
165
     */
166
    protected function compileFrom(Builder $builder, $table)
167
    {
168
        $table = $this->prefixTable($table);
169
        $builder = $this->generateTableAlias($builder, $table);
170
        $tableAlias = $builder->getAlias($table);
171
172
        $builder->aqb = $builder->aqb->for($tableAlias, $table);
173
         return $builder;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $builder returns the type LaravelFreelancerNL\Aranguent\Query\Builder which is incompatible with the documented return type LaravelFreelancerNL\FluentAQL\QueryBuilder.
Loading history...
174
    }
175
176
    /**
177
     * Compile the "where" portions of the query.
178
     *
179
     * @param Builder $builder
180
     * @return string
181
     */
182
    protected function compileWheres(Builder $builder)
183
    {
184
        // Each type of where clauses has its own compiler function which is responsible
185
        // for actually creating the where clauses SQL. This helps keep the code nice
186
        // and maintainable since each clause has a very small method that it uses.
187
        if (is_null($builder->wheres)) {
0 ignored issues
show
introduced by
The condition is_null($builder->wheres) is always false.
Loading history...
188
            return $builder;
189
        }
190
191
        if (count($predicates = $this->compileWheresToArray($builder)) > 0) {
192
            $builder->aqb = $builder->aqb->filter($predicates);
0 ignored issues
show
Bug introduced by
$predicates of type array is incompatible with the type string expected by parameter $attribute of LaravelFreelancerNL\Flue...\QueryBuilder::filter(). ( Ignorable by Annotation )

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

192
            $builder->aqb = $builder->aqb->filter(/** @scrutinizer ignore-type */ $predicates);
Loading history...
193
            return $builder;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $builder returns the type LaravelFreelancerNL\Aranguent\Query\Builder which is incompatible with the documented return type string.
Loading history...
194
        }
195
196
        return $builder;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $builder returns the type LaravelFreelancerNL\Aranguent\Query\Builder which is incompatible with the documented return type string.
Loading history...
197
    }
198
199
    /**
200
     * Get an array of all the where clauses for the query.
201
     *
202
     * @param  \Illuminate\Database\Query\Builder  $builder
203
     * @return array
204
     */
205
    protected function compileWheresToArray($builder)
206
    {
207
        $result = collect($builder->wheres)->map(function ($where) use ($builder) {
208
            // ArangoDB uses a double '=' for comparison
209
            if ($where['operator'] == '=') {
210
                $where['operator'] = '==';
211
            }
212
            //Prefix table alias on the column
213
            $where['column'] = $this->prefixAlias($builder, $builder->from, $where['column'] );
214
215
            return [
216
                $where['column'],
217
                $where['operator'],
218
                $where['value'],
219
                $where['boolean']
220
            ];
221
        })->all();
222
        return $result;
223
    }
224
225
    /**
226
     * Compile the "order by" portions of the query.
227
     *
228
     * @param Builder $builder
229
     * @param array $orders
230
     * @return string
231
     */
232
    protected function compileOrders(Builder $builder, $orders)
233
    {
234
        if (! empty($orders)) {
235
            $builder->aqb = $builder->aqb->sort($this->compileOrdersToArray($builder, $orders));
236
            return $builder;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $builder returns the type LaravelFreelancerNL\Aranguent\Query\Builder which is incompatible with the documented return type string.
Loading history...
237
        }
238
239
        return $builder;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $builder returns the type LaravelFreelancerNL\Aranguent\Query\Builder which is incompatible with the documented return type string.
Loading history...
240
    }
241
242
    /**
243
     * Compile the query orders to an array.
244
     *
245
     * @param  Builder  $builder
246
     * @param  array  $orders
247
     * @return FluentAQL
248
     */
249
    protected function compileOrdersToArray(Builder $builder, $orders)
250
    {
251
        return array_map(function ($order) {
0 ignored issues
show
Bug Best Practice introduced by
The expression return array_map(functio...{ /* ... */ }, $orders) returns the type array which is incompatible with the documented return type LaravelFreelancerNL\FluentAQL\QueryBuilder.
Loading history...
252
            return $order['sql'] ?? $this->prefixTable($order['column']).' '.$order['direction'];
253
        }, $orders);
254
    }
255
256
    /**
257
     * Compile the "offset" portions of the query.
258
     * We are handling this first by saving the offset which will be used by the FluentAQL's limit function
259
     *
260
     * @param Builder $builder
261
     * @param int $offset
262
     * @return string
263
     */
264
    protected function compileOffset(Builder $builder, $offset)
265
    {
266
        $this->offset = (int) $offset;
267
268
        return $builder;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $builder returns the type LaravelFreelancerNL\Aranguent\Query\Builder which is incompatible with the documented return type string.
Loading history...
269
    }
270
271
    /**
272
     * Compile the "limit" portions of the query.
273
     *
274
     * @param Builder $builder
275
     * @param int $limit
276
     * @return string
277
     */
278
    protected function compileLimit(Builder $builder, $limit)
279
    {
280
        if ($this->offset !== null) {
281
            $builder->aqb = $builder->aqb->limit((int)$this->offset, (int)$limit);
282
            return $builder;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $builder returns the type LaravelFreelancerNL\Aranguent\Query\Builder which is incompatible with the documented return type string.
Loading history...
283
        }
284
        $builder->aqb = $builder->aqb->limit((int) $limit);
285
        return $builder;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $builder returns the type LaravelFreelancerNL\Aranguent\Query\Builder which is incompatible with the documented return type string.
Loading history...
286
    }
287
288
289
    /**
290
     * Compile the "RETURN" portion of the query.
291
     *
292
     * @param Builder $builder
293
     * @param array $columns
294
     * @return Builder
295
     */
296
    protected function compileColumns(Builder $builder, array $columns) : Builder
297
    {
298
        // If the query is actually performing an aggregating select, we will let that
299
        // compiler handle the building of the select clauses, as it will need some
300
        // more syntax that is best handled by that function to keep things neat.
301
//        if (! is_null($builder->aggregate)) {
302
//            return;
303
//        }
304
305
        $values = [];
306
307
        $doc = $builder->getAlias($builder->from);
308
        foreach ($columns as $column) {
309
            if ($column != null && $column != '*') {
310
                $values[$column] = $doc.'.'.$column;
311
            }
312
        }
313
        if (empty($values)) {
314
            $values = $doc;
315
        }
316
        $builder->aqb = $builder->aqb->return($values, (boolean) $builder->distinct);
317
        return $builder;
318
    }
319
320
    /**
321
     * Compile an update statement into SQL.
322
     *
323
     * @param Builder $builder
324
     * @param array $values
325
     * @return string
326
     */
327
    public function compileUpdate(Builder $builder, array $values)
328
    {
329
        $table = $this->prefixTable($builder->from);
330
        $builder = $this->generateTableAlias($builder, $table);
331
        $tableAlias = $builder->getAlias($table);
332
        $builder->aqb = $builder->aqb->for($tableAlias, $table);
333
334
        //Fixme: joins?
335
        $builder = $this->compileWheres($builder);
336
337
        $builder->aqb = $builder->aqb->update($tableAlias, $values, $table)->get();
0 ignored issues
show
Bug introduced by
The property aqb does not exist on string.
Loading history...
338
        return $builder;
339
    }
340
341
    /**
342
     * Compile a delete statement into SQL.
343
     *
344
     * @param Builder $builder
345
     * @param null $_key
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $_key is correct as it would always require null to be passed?
Loading history...
346
     * @return string
347
     */
348
    public function compileDelete(Builder $builder, $_key = null)
349
    {
350
        $table = $this->prefixTable($builder->from);
351
        $builder = $this->generateTableAlias($builder, $table);
352
        $tableAlias = $builder->getAlias($table);
353
354
        if (! is_null($_key)) {
0 ignored issues
show
introduced by
The condition is_null($_key) is always true.
Loading history...
355
            $builder->aqb = $builder->aqb->remove((string) $_key, $table)->get();
356
            return $builder;
357
        }
358
359
        $builder->aqb = $builder->aqb->for($tableAlias, $table);
360
361
        //Fixme: joins?
362
        $builder = $this->compileWheres($builder);
363
364
        $builder->aqb = $builder->aqb->remove($tableAlias, $table)->get();
0 ignored issues
show
Bug introduced by
The property aqb does not exist on string.
Loading history...
365
366
        return $builder;
367
    }
368
369
    protected function prefixAlias(Builder $builder, string $target, string $value) : string
370
    {
371
        return $builder->getAlias($target).'.'.$value;
372
    }
373
}
374