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

Connection::getDefaultQueryGrammar()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace LaravelFreelancerNL\Aranguent;
4
5
use ArangoDBClient\Connection as ArangoConnection;
6
use ArangoDBClient\ConnectionOptions as ArangoConnectionOptions;
7
use ArangoDBClient\Exception;
8
use ArangoDBClient\Statement;
9
use Illuminate\Database\Connection as IlluminateConnection;
10
use Iterator;
11
use LaravelFreelancerNL\Aranguent\Concerns\DetectsDeadlocks;
12
use LaravelFreelancerNL\Aranguent\Concerns\DetectsLostConnections;
13
use LaravelFreelancerNL\Aranguent\Concerns\HandlesArangoDb;
14
use LaravelFreelancerNL\Aranguent\Concerns\ManagesTransactions;
15
use LaravelFreelancerNL\Aranguent\Query\Builder as QueryBuilder;
16
use LaravelFreelancerNL\Aranguent\Query\Grammar as QueryGrammar;
17
use LaravelFreelancerNL\Aranguent\Query\Processor;
18
use LaravelFreelancerNL\Aranguent\Schema\Builder as SchemaBuilder;
19
use LaravelFreelancerNL\FluentAQL\QueryBuilder as FluentAQL;
20
21
class Connection extends IlluminateConnection
22
{
23
    use HandlesArangoDb;
24
    use DetectsDeadlocks;
25
    use DetectsLostConnections;
26
    use ManagesTransactions;
0 ignored issues
show
Bug introduced by
The trait LaravelFreelancerNL\Aran...rns\ManagesTransactions requires the property $collections which is not provided by LaravelFreelancerNL\Aranguent\Connection.
Loading history...
27
28
    /**
29
     * {@inheritdoc}
30
     *
31
     * @var array
32
     */
33
    protected $defaultConfig = [
34
        ArangoConnectionOptions::OPTION_ENDPOINT    => 'tcp://localhost:8529',
35
        ArangoConnectionOptions::OPTION_CONNECTION  => 'Keep-Alive',
36
        ArangoConnectionOptions::OPTION_AUTH_USER   => null,
37
        ArangoConnectionOptions::OPTION_AUTH_PASSWD => null,
38
        'tablePrefix'                               => '',
39
    ];
40
41
    protected $config;
42
43
    protected $arangoConnection;
44
45
    protected $reconnector;
46
47
    protected $database;
48
49
    protected $schemaGrammar;
50
51
    protected $queryGrammar;
52
53
    protected $pretending;
54
55
    protected $recordsModified;
56
57
    protected $loggingQueries;
58
59
    protected $queryLog;
60
61
    /**
62
     * The ArangoDB driver name.
63
     *
64
     * @var string
65
     */
66
    protected $driverName = 'arangodb';
67
68
    /**
69
     * Connection constructor.
70
     *
71
     * @param array $config
72
     *
73
     * @throws Exception
74
     */
75
    public function __construct($config = [])
76
    {
77
        $this->config = array_merge($this->defaultConfig, $config);
78
79
        if (isset($this->config['database'])) {
80
            $this->database = $this->config['database'];
81
        }
82
83
        $this->tablePrefix = $this->config['tablePrefix'];
84
85
        // activate and set the database client connection
86
        $this->arangoConnection = new ArangoConnection($this->config);
87
88
        // We need to initialize a query grammar and the query post processors
89
        // which are both very important parts of the database abstractions
90
        // so we initialize these to their default values while starting.
91
        $this->useDefaultQueryGrammar();
92
93
        $this->useDefaultPostProcessor();
94
    }
95
96
    /**
97
     * Get a schema builder instance for the connection.
98
     *
99
     * @return SchemaBuilder
100
     */
101
    public function getSchemaBuilder()
102
    {
103
        if (is_null($this->schemaGrammar)) {
104
            $this->useDefaultSchemaGrammar();
105
        }
106
107
        return new SchemaBuilder($this);
108
    }
109
110
    /**
111
     * Get the default query grammar instance.
112
     *
113
     * @return QueryGrammar
114
     */
115
    protected function getDefaultQueryGrammar()
116
    {
117
        return new QueryGrammar();
118
    }
119
120
    /**
121
     * Get the default post processor instance.
122
     *
123
     * @return Processor
124
     */
125
    protected function getDefaultPostProcessor()
126
    {
127
        return new Processor();
128
    }
129
130
    /**
131
     * Run a select statement against the database and returns a generator.
132
     * ($useReadPdo is a dummy to adhere to the interface).
133
     *
134
     * @param string     $query
135
     * @param array      $bindings
136
     * @param bool       $useReadPdo
137
     * @param array|null $transactionCollections
138
     *
139
     * @throws Exception
140
     *
141
     * @return Iterator|null
142
     */
143
    public function cursor($query, $bindings = [], $useReadPdo = null, $transactionCollections = null)
144
    {
145
        // Usage of a separate DB to read date isn't supported at this time
146
        $useReadPdo = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $useReadPdo is dead and can be removed.
Loading history...
147
148
        return $this->run($query, $bindings, function ($query, $bindings) use ($transactionCollections) {
149
            if ($this->pretending()) {
150
                return [];
151
            }
152
            if ($this->transactionLevel() > 0) {
153
                $this->addQueryToTransaction($query, $bindings, $transactionCollections);
154
155
                return [];
156
            }
157
158
            $statement = $this->newArangoStatement($query, $bindings);
159
160
            return $statement->execute();
161
        });
162
    }
163
164
    /**
165
     * Execute an AQL statement and return the boolean result.
166
     *
167
     * @param string|FluentAQL $query
168
     * @param array            $bindings
169
     * @param array|null       $transactionCollections
170
     *
171
     * @return bool
172
     */
173
    public function statement($query, $bindings = [], $transactionCollections = null)
174
    {
175
        if ($query instanceof FluentAQL) {
176
            $bindings = $query->binds;
177
            $transactionCollections = $query->collections;
178
            $query = $query->query;
179
        }
180
181
        return $this->run($query, $bindings, function ($query, $bindings) use ($transactionCollections) {
182
            if ($this->pretending()) {
183
                return true;
184
            }
185
            if ($this->transactionLevel() > 0) {
186
                $this->addQueryToTransaction($query, $bindings, $transactionCollections);
187
188
                return true;
189
            }
190
191
            $statement = $this->newArangoStatement($query, $bindings);
192
193
            $cursor = $statement->execute();
194
195
            $affectedDocumentCount = $cursor->getWritesExecuted();
196
            $this->recordsHaveBeenModified($changed = $affectedDocumentCount > 0);
197
198
            return $changed;
199
        });
200
    }
201
202
    /**
203
     * Run an AQL statement and get the number of rows affected.
204
     *
205
     * @param string|FluentAQL $query
206
     * @param array            $bindings
207
     * @param array|null       $transactionCollections
208
     *
209
     * @return int
210
     */
211
    public function affectingStatement($query, $bindings = [], $transactionCollections = null)
212
    {
213
        if ($query instanceof FluentAQL) {
214
            $bindings = $query->binds;
215
            $transactionCollections = $query->collections;
216
            $query = $query->query;
217
        }
218
219
        return $this->run($query, $bindings, function ($query, $bindings) use ($transactionCollections) {
220
            if ($this->pretending()) {
221
                return 0;
222
            }
223
            if ($this->transactionLevel() > 0) {
224
                $this->addQueryToTransaction($query, $bindings, $transactionCollections);
225
226
                return 0;
227
            }
228
229
            // For update or delete statements, we want to get the number of rows affected
230
            // by the statement and return that back to the developer. We'll first need
231
            // to execute the statement and get the executed writes from the extra.
232
            $statement = $this->newArangoStatement($query, $bindings);
233
234
            $cursor = $statement->execute();
235
236
            $affectedDocumentCount = $cursor->getWritesExecuted();
237
238
            $this->recordsHaveBeenModified($affectedDocumentCount > 0);
239
240
            return $affectedDocumentCount;
241
        });
242
    }
243
244
    /**
245
     * Run a raw, unprepared query against the connection.
246
     *
247
     * @param string $query
248
     *
249
     * @return bool
250
     */
251
    public function unprepared($query)
252
    {
253
        return $this->run($query, [], function ($query) {
254
            if ($this->pretending()) {
255
                return true;
256
            }
257
            if ($this->transactionLevel() > 0) {
258
                $this->addQueryToTransaction($query);
259
260
                return [];
261
            }
262
263
            $statement = $this->newArangoStatement($query, []);
264
265
            $cursor = $statement->execute();
266
267
            $affectedDocumentCount = $cursor->getWritesExecuted();
268
269
            $change = $affectedDocumentCount > 0;
270
271
            $this->recordsHaveBeenModified($change);
272
273
            return $change;
274
        });
275
    }
276
277
    /**
278
     * Returns the query execution plan. The query will not be executed.
279
     *
280
     * @param string $query
281
     * @param array  $bindings
282
     *
283
     * @throws Exception
284
     *
285
     * @return array
286
     */
287
    public function explain($query, $bindings = [])
288
    {
289
        $statement = $this->newArangoStatement($query, $bindings);
290
291
        return $statement->explain();
292
    }
293
294
    /**
295
     * Run a select statement against the database.
296
     *
297
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
298
     *
299
     * @param string|FluentAQL $query
300
     * @param array            $bindings
301
     * @param bool             $useReadPdo
302
     * @param null|array       $transactionCollections
303
     *
304
     * @return array
305
     */
306
    public function select($query, $bindings = [], $useReadPdo = true, $transactionCollections = null)
307
    {
308
        return $this->execute($query, $bindings, $useReadPdo, $transactionCollections);
309
    }
310
311
    /**
312
     * Run an AQL query against the database and return the results.
313
     *
314
     * @SuppressWarnings(PHPMD.BooleanArgumentFlag)
315
     *
316
     * @param string|FluentAQL $query
317
     * @param array            $bindings
318
     * @param bool             $useReadPdo
319
     * @param null|array       $transactionCollections
320
     *
321
     * @return array
322
     */
323
    public function execute($query, $bindings = [], $useReadPdo = true, $transactionCollections = null)
0 ignored issues
show
Unused Code introduced by
The parameter $transactionCollections is not used and could be removed. ( Ignorable by Annotation )

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

323
    public function execute($query, $bindings = [], $useReadPdo = true, /** @scrutinizer ignore-unused */ $transactionCollections = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $useReadPdo is not used and could be removed. ( Ignorable by Annotation )

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

323
    public function execute($query, $bindings = [], /** @scrutinizer ignore-unused */ $useReadPdo = true, $transactionCollections = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
324
    {
325
        // Usage of a separate DB to read date isn't supported at this time
326
        $useReadPdo = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $useReadPdo is dead and can be removed.
Loading history...
327
328
        if ($query instanceof FluentAQL) {
329
            $bindings = $query->binds;
330
            $transactionCollections = $query->collections;
0 ignored issues
show
Unused Code introduced by
The assignment to $transactionCollections is dead and can be removed.
Loading history...
331
            $query = $query->query;
332
        }
333
334
        return $this->run($query, $bindings, function ($query, $bindings, $transactionCollections = null) {
335
            if ($this->pretending()) {
336
                return [];
337
            }
338
            if ($this->transactionLevel() > 0) {
339
                $this->addQueryToTransaction($query, $bindings, $transactionCollections);
340
341
                return [];
342
            }
343
344
            $statement = $this->newArangoStatement($query, $bindings);
345
            $cursor = $statement->execute();
346
347
            return $cursor->getAll();
348
        });
349
    }
350
351
    /**
352
     * Run an insert statement against the database.
353
     *
354
     * @param string|FluentAQL $query
355
     * @param array            $bindings
356
     * @param array|null       $transactionCollections
357
     *
358
     * @return bool
359
     */
360
    public function insert($query, $bindings = [], $transactionCollections = null)
361
    {
362
        return $this->statement($query, $bindings, $transactionCollections);
363
    }
364
365
    /**
366
     * Run an update statement against the database.
367
     *
368
     * @param string|FluentAQL $query
369
     * @param array            $bindings
370
     * @param array|null       $transactionCollections
371
     *
372
     * @return int
373
     */
374
    public function update($query, $bindings = [], $transactionCollections = null)
375
    {
376
        return $this->affectingStatement($query, $bindings, $transactionCollections);
377
    }
378
379
    /**
380
     * Run a delete statement against the database.
381
     *
382
     * @param string     $query
383
     * @param array      $bindings
384
     * @param array|null $transactionCollections
385
     *
386
     * @return int
387
     */
388
    public function delete($query, $bindings = [], $transactionCollections = null)
389
    {
390
        return $this->affectingStatement($query, $bindings, $transactionCollections);
391
    }
392
393
    /**
394
     * Get a new query builder instance.
395
     *
396
     * @return QueryBuilder
397
     */
398
    public function query()
399
    {
400
        return new QueryBuilder(
401
            $this,
402
            $this->getQueryGrammar(),
0 ignored issues
show
Bug introduced by
$this->getQueryGrammar() of type Illuminate\Database\Query\Grammars\Grammar is incompatible with the type LaravelFreelancerNL\Aranguent\Query\Grammar|null expected by parameter $grammar of LaravelFreelancerNL\Aran...\Builder::__construct(). ( Ignorable by Annotation )

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

402
            /** @scrutinizer ignore-type */ $this->getQueryGrammar(),
Loading history...
403
            $this->getPostProcessor()
404
        );
405
    }
406
407
    /**
408
     * Get the collection prefix for the connection.
409
     *
410
     * @return string
411
     */
412
    public function getTablePrefix()
413
    {
414
        return $this->tablePrefix;
415
    }
416
417
    /**
418
     * Disconnect from the underlying ArangoDB connection.
419
     *
420
     * @return void
421
     */
422
    public function disconnect()
423
    {
424
        $this->transactions = 0;
425
426
        $this->arangoConnection = null;
427
    }
428
429
    /**
430
     * Reconnect to the database if a Arango connection is missing.
431
     *
432
     * @return void
433
     */
434
    protected function reconnectIfMissingConnection()
435
    {
436
        if (is_null($this->arangoConnection)) {
437
            $this->reconnect();
438
        }
439
    }
440
441
    public function getArangoConnection()
442
    {
443
        return $this->arangoConnection;
444
    }
445
446
    /**
447
     * @param $query
448
     * @param $bindings
449
     * @return Statement
450
     * @throws Exception
451
     */
452
    public function newArangoStatement($query, $bindings): Statement
453
    {
454
        $statement = new Statement($this->arangoConnection, ['query' => $query, 'bindVars' => $bindings]);
455
        $statement->setDocumentClass(Document::class);
456
457
        return $statement;
458
    }
459
460
461
    public function setDatabaseName($database)
462
    {
463
        $this->database = $database;
464
        $this->arangoConnection->setDatabase($database);
465
    }
466
467
    public function getDatabaseName()
468
    {
469
        return $this->database;
470
    }
471
}
472