ShowCommand   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 327
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 129
dl 0
loc 327
rs 9.84
c 1
b 0
f 0
wmc 32

12 Methods

Rating   Name   Duplication   Size   Complexity  
A analyzers() 0 6 1
A getDatabaseInfo() 0 9 1
A displayGraphs() 0 17 3
A handle() 0 37 2
A displayAnalyzers() 0 17 3
A display() 0 3 2
A graphs() 0 6 1
A views() 0 12 2
B displayForCli() 0 58 8
A displayViews() 0 17 3
A getFullVersion() 0 7 1
A tables() 0 27 5
1
<?php
2
3
namespace LaravelFreelancerNL\Aranguent\Console;
4
5
use ArangoClient\Exceptions\ArangoException;
6
use Illuminate\Database\ConnectionInterface;
7
use Illuminate\Database\ConnectionResolverInterface;
8
use Illuminate\Database\Console\ShowCommand as IlluminateShowCommand;
9
use Illuminate\Database\Schema\Builder as IlluminateSchemaBuilder;
10
use Illuminate\Support\Arr;
11
use Illuminate\Support\Number;
12
use LaravelFreelancerNL\Aranguent\Connection;
13
use LaravelFreelancerNL\Aranguent\Schema\Builder as SchemaBuilder;
14
15
class ShowCommand extends IlluminateShowCommand
16
{
17
    /**
18
     * The name and signature of the console command.
19
     *
20
     * @var string
21
     */
22
    protected $signature = 'db:show {--database= : The database connection}
23
                {--json : Output the database information as JSON}
24
                {--counts : Show the table row count }
25
                {--views : Show the database views }
26
                {--analyzers : Show the database analyzers (ArangoDB)}
27
                {--graphs : Show the database named graphs (ArangoDB)}
28
                {--system : Show the database system tables (ArangoDB)}
29
                {--types : Show the user defined types (Postgresql)}
30
                {--all : Show tables, analyzers, graphs and views (ArangoDB)}';
31
32
    /**
33
     * The console command description.
34
     *
35
     * @var string
36
     */
37
    protected $description = 'Display information about the given database';
38
39
    /**
40
     * Execute the console command.
41
     *
42
     * @param  \Illuminate\Database\ConnectionResolverInterface  $connections
43
     * @return int
44
     */
45
    public function handle(ConnectionResolverInterface $connections)
46
    {
47
        $connection = $connections->connection($database = $this->input->getOption('database'));
48
49
        assert($connection instanceof Connection);
50
51
        if ($connection->getDriverName() !== 'arangodb') {
52
            return parent::handle($connections);
53
        }
54
55
        $schema = $connection->getSchemaBuilder();
56
57
        $fullVersion = $this->getFullVersion($connection);
58
59
        $data = [
60
            'platform' => [
61
                'config' => $this->getConfigFromDatabase($database),
62
                'server' => $fullVersion->server ?? 'arango',
63
                'license' => $fullVersion->license ?? 'unknown',
64
                'name' => $connection->getDriverTitle(),
65
                'connection' => $connection->getName(),
66
                'version' => $fullVersion->version ?? 'unknown',
67
                'isSystemDatabase' =>  $this->getDatabaseInfo($connection),
68
                'open_connections' => $connection->threadCount(),
69
            ],
70
            'tables' => $this->tables($connection, $schema),
71
        ];
72
73
        $data['views'] = $this->views($connection, $schema);
74
75
        $data['analyzers'] = $this->analyzers($schema);
76
77
        $data['graphs'] = $this->graphs($schema);
78
79
        $this->display($data, $connection);
80
81
        return 0;
82
    }
83
84
    /**
85
     * Render the database information.
86
     *
87
     * @param array<mixed> $data
88
     * @param Connection|null $connection
89
     * @return void
90
     */
91
    protected function display(array $data, ?Connection $connection = null)
92
    {
93
        $this->option('json') ? $this->displayJson($data) : $this->displayForCli($data, $connection);
94
    }
95
96
97
    /**
98
     * Get information regarding the tables within the database.
99
     *
100
     * @param  \Illuminate\Database\ConnectionInterface  $connection
101
     * @param  IlluminateSchemaBuilder $schema
102
     * @return \Illuminate\Support\Collection
103
     */
104
    protected function tables(ConnectionInterface $connection, $schema)
105
    {
106
        assert($connection instanceof Connection);
107
108
        if ($connection->getDriverName() !== 'arangodb') {
109
            return parent::tables($connection, $schema);
110
        }
111
112
        assert($schema instanceof SchemaBuilder);
113
114
        // Get all tables
115
        $tables = collect(
116
            ($this->input->getOption('system')) ? $schema->getAllTables() : $schema->getTables(),
0 ignored issues
show
Bug introduced by
$this->input->getOption(... : $schema->getTables() of type array<mixed,mixed> is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

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

116
            /** @scrutinizer ignore-type */ ($this->input->getOption('system')) ? $schema->getAllTables() : $schema->getTables(),
Loading history...
117
        )->sortBy('name');
118
119
        // Get per table statistics
120
        $tableStats = [];
121
        foreach ($tables as $table) {
122
            $tableStats[] = $schema->getTable($table['name']);
123
        }
124
125
        return collect($tableStats)->map(fn($table) => [
126
            'table' => $table['name'],
127
            'size' => $table['figures']->documentsSize,
128
            'rows' => $this->option('counts')
129
                ? $table['count']
130
                : null,
131
        ]);
132
    }
133
134
    /**
135
     * Get information regarding the views within the database.
136
     *
137
     * @param  \Illuminate\Database\ConnectionInterface  $connection
138
     * @param  \Illuminate\Database\Schema\Builder  $schema
139
     * @return \Illuminate\Support\Collection
140
     */
141
    protected function views(ConnectionInterface $connection, IlluminateSchemaBuilder $schema)
142
    {
143
        assert($connection instanceof Connection);
144
145
        if ($connection->getDriverName() !== 'arangodb') {
146
            return parent::views($connection, $schema);
147
        }
148
149
        return collect($schema->getViews())
150
            ->map(fn($view) => [
151
                'name' => $view['name'],
152
                'type' => $view['type'],
153
            ]);
154
    }
155
156
    /**
157
     * Get information regarding the analyzers within the database.
158
     *
159
     * @param  SchemaBuilder $schema
160
     * @return \Illuminate\Support\Collection
161
     */
162
    protected function analyzers(SchemaBuilder $schema)
163
    {
164
        return collect($schema->getAnalyzers())
0 ignored issues
show
Bug introduced by
$schema->getAnalyzers() of type array<mixed,mixed> is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

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

164
        return collect(/** @scrutinizer ignore-type */ $schema->getAnalyzers())
Loading history...
165
            ->map(fn($analyzer) => [
166
                'name' => $analyzer['name'],
167
                'type' => $analyzer['type'],
168
            ]);
169
    }
170
171
    /**
172
     * Get information regarding the named graphs within the database.
173
     *
174
     * @param SchemaBuilder $schema
175
     * @return \Illuminate\Support\Collection
176
     */
177
    protected function graphs(SchemaBuilder $schema)
178
    {
179
        return collect($schema->getGraphs())
0 ignored issues
show
Bug introduced by
$schema->getGraphs() of type array<mixed,mixed> is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

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

179
        return collect(/** @scrutinizer ignore-type */ $schema->getGraphs())
Loading history...
180
            ->map(fn($graph) => [
181
                'name' => $graph['name'],
182
                'edgeDefinitions' => count($graph['edgeDefinitions']),
183
            ]);
184
    }
185
186
    protected function getFullVersion(Connection $connection): object
187
    {
188
        $client = $connection->getArangoClient();
189
190
        assert($client !== null);
191
192
        return $client->admin()->getVersion();
193
    }
194
195
    /**
196
     * @throws ArangoException
197
     */
198
    protected function getDatabaseInfo(Connection $connection): bool
199
    {
200
        $client = $connection->getArangoClient();
201
202
        assert($client !== null);
203
204
        $info = $client->schema()->getCurrentDatabase();
205
206
        return $info->isSystem;
207
    }
208
209
    /**
210
     * @param mixed $views
211
     * @return void
212
     */
213
    public function displayViews(mixed $views): void
214
    {
215
        if (! $this->input->getOption('views') || $views->isEmpty()) {
216
            return;
217
        }
218
219
        $this->components->twoColumnDetail(
220
            '<fg=green;options=bold>View</>',
221
            '<fg=green;options=bold>Type</>',
222
        );
223
224
        $views->each(fn($view) => $this->components->twoColumnDetail(
225
            $view['name'],
226
            $view['type'],
227
        ));
228
229
        $this->newLine();
230
    }
231
232
    /**
233
     * @param mixed $analyzers
234
     * @return void
235
     */
236
    public function displayAnalyzers(mixed $analyzers): void
237
    {
238
        if (! $this->input->getOption('analyzers') || $analyzers->isEmpty()) {
239
            return;
240
        }
241
242
        $this->components->twoColumnDetail(
243
            '<fg=green;options=bold>Analyzers</>',
244
            '<fg=green;options=bold>Type</>',
245
        );
246
247
        $analyzers->each(fn($analyzer) => $this->components->twoColumnDetail(
248
            $analyzer['name'],
249
            $analyzer['type'],
250
        ));
251
252
        $this->newLine();
253
    }
254
    /**
255
     * @param mixed $graphs
256
     * @return void
257
     */
258
    public function displayGraphs(mixed $graphs): void
259
    {
260
        if (! $this->input->getOption('graphs') || $graphs->isEmpty()) {
261
            return;
262
        }
263
264
        $this->components->twoColumnDetail(
265
            '<fg=green;options=bold>Graphs</>',
266
            '<fg=green;options=bold>Edge Definitions</>',
267
        );
268
269
        $graphs->each(fn($graph) => $this->components->twoColumnDetail(
270
            $graph['name'],
271
            $graph['edgeDefinitions'],
272
        ));
273
274
        $this->newLine();
275
    }
276
277
    /**
278
     * Render the database information formatted for the CLI.
279
     *
280
     * @param array<mixed> $data
281
     * @param Connection|null $connection
282
     * @return void
283
     */
284
    protected function displayForCli(array $data, ?Connection $connection = null)
285
    {
286
        if ($connection && $connection->getDriverName() !== 'arangodb') {
287
            parent::displayForCli($data);
288
            return;
289
        }
290
291
        $platform = $data['platform'];
292
        $tables = $data['tables'];
293
        $analyzers = $data['analyzers'] ?? null;
294
        $views = $data['views'] ?? null;
295
        $graphs = $data['graphs'] ?? null;
296
297
        $this->newLine();
298
299
        $this->components->twoColumnDetail('<fg=green;options=bold>ArangoDB (' . ucfirst($platform['license']) . ' Edition)</>', '<fg=green;options=bold>' . $platform['version'] . '</>');
300
        $this->components->twoColumnDetail('Connection', $platform['connection']);
301
        $this->components->twoColumnDetail('Database', Arr::get($platform['config'], 'database'));
302
        $this->components->twoColumnDetail('Host', Arr::get($platform['config'], 'host'));
303
        $this->components->twoColumnDetail('Port', Arr::get($platform['config'], 'port'));
304
        $this->components->twoColumnDetail('Username', Arr::get($platform['config'], 'username'));
305
        $this->components->twoColumnDetail('URL', Arr::get($platform['config'], 'url') ?? Arr::get($platform['config'], 'endpoint'));
306
        $this->components->twoColumnDetail('Open Connections', $platform['open_connections']);
307
        $this->components->twoColumnDetail('Analyzers', $analyzers->count());
0 ignored issues
show
Bug introduced by
The method count() does not exist on null. ( Ignorable by Annotation )

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

307
        $this->components->twoColumnDetail('Analyzers', $analyzers->/** @scrutinizer ignore-call */ count());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
308
        $this->components->twoColumnDetail('Views', $views->count());
0 ignored issues
show
Bug introduced by
The method count() does not exist on null. ( Ignorable by Annotation )

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

308
        $this->components->twoColumnDetail('Views', $views->/** @scrutinizer ignore-call */ count());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
309
        $this->components->twoColumnDetail('Named Graphs', $graphs->count());
0 ignored issues
show
Bug introduced by
The method count() does not exist on null. ( Ignorable by Annotation )

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

309
        $this->components->twoColumnDetail('Named Graphs', $graphs->/** @scrutinizer ignore-call */ count());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
310
        $this->components->twoColumnDetail('Tables', $tables->count());
311
312
        $tableSizeSum = $tables->sum('size');
313
        if ($tableSizeSum) {
314
            $this->components->twoColumnDetail('Total Size Estimate', Number::fileSize($tableSizeSum, 2));
315
        }
316
317
        $this->newLine();
318
319
        if ($tables->isNotEmpty()) {
320
            $this->components->twoColumnDetail(
321
                '<fg=green;options=bold>Table</>',
322
                'Size Estimate' . ($this->option('counts') ? ' <fg=gray;options=bold>/</> <fg=yellow;options=bold>Rows</>' : ''),
323
            );
324
325
            $tables->each(function ($table) {
326
                $tableSize = is_null($table['size']) ? null : Number::fileSize($table['size'], 2);
327
328
                $this->components->twoColumnDetail(
329
                    $table["table"],
330
                    ($tableSize ?? '—') . ($this->option('counts') ? ' <fg=gray;options=bold>/</> <fg=yellow;options=bold>' . Number::format($table['rows']) . '</>' : ''),
331
                );
332
            });
333
334
            $this->newLine();
335
        }
336
337
        $this->displayViews($views);
338
339
        $this->displayAnalyzers($analyzers);
340
341
        $this->displayGraphs($graphs);
342
    }
343
}
344