Passed
Push — dependabot/github_actions/depe... ( d1016c )
by
unknown
11:16
created

Blueprint   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 251
Duplicated Lines 0 %

Test Coverage

Coverage 70.59%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 25
eloc 70
c 1
b 0
f 0
dl 0
loc 251
ccs 48
cts 68
cp 0.7059
rs 10

11 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 2
A executeCommand() 0 8 3
A executeIgnoreCommand() 0 6 2
A compileAqlCommand() 0 8 2
A addCommand() 0 5 1
A executeAqlCommand() 0 3 1
A createCommand() 0 3 1
A executeCollectionCommand() 0 10 3
A build() 0 14 4
A getCommands() 0 3 1
A __call() 0 31 5
1
<?php
2
3
namespace LaravelFreelancerNL\Aranguent\Schema;
4
5
use ArangoClient\Schema\SchemaManager;
6
use Closure;
7
use Illuminate\Database\Connection;
8
use Illuminate\Support\Fluent;
9
use Illuminate\Support\Traits\Macroable;
10
use LaravelFreelancerNL\Aranguent\Schema\Concerns\Columns;
11
use LaravelFreelancerNL\Aranguent\Schema\Concerns\Indexes;
12
use LaravelFreelancerNL\Aranguent\Schema\Concerns\Tables;
13
14
/**
15
 * Class Blueprint.
16
 *
17
 * The Schema blueprint works differently from the standard Illuminate version:
18
 * 1) ArangoDB is schemaless: we don't need to (and can't) create columns
19
 * 2) ArangoDB doesn't allow DB schema actions within AQL nor within a transaction.
20
 *
21
 * This means that:
22
 * 1) We catch column related methods silently for backwards compatibility and ease of migrating between DB types
23
 * 2) We don't need to compile AQL for transactions within the accompanying schema grammar. (for now)
24
 * 3) We can just execute each command on order. We will gather them first for possible future optimisations.
25
 */
26
class Blueprint
27
{
28
    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\Schema\Blueprint.
Loading history...
29
    use Tables;
0 ignored issues
show
introduced by
The trait LaravelFreelancerNL\Aran...\Schema\Concerns\Tables requires some properties which are not provided by LaravelFreelancerNL\Aranguent\Schema\Blueprint: $name, $options, $explanation
Loading history...
30
    use Columns;
31
    use Indexes;
0 ignored issues
show
introduced by
The trait LaravelFreelancerNL\Aran...Schema\Concerns\Indexes requires some properties which are not provided by LaravelFreelancerNL\Aranguent\Schema\Blueprint: $indexOptions, $id, $explanation, $type, $unique, $index
Loading history...
32
33
    /**
34
     * The connection that is used by the blueprint.
35
     *
36
     * @var Connection
37
     */
38
    protected $connection;
39
40
    /**
41
     * The grammar that is used by the blueprint.
42
     *
43
     * @var Grammar
44
     */
45
    protected $grammar;
46
47
    /**
48
     * The table the blueprint describes.
49
     *
50
     * @var string
51
     */
52
    protected $table;
53
54
    /**
55
     * The handler for table manipulation.
56
     */
57
    protected SchemaManager $schemaManager;
58
59
    /**
60
     * The prefix of the table.
61
     *
62
     * @var string
63
     */
64
    protected $prefix;
65
66
    /**
67
     * The commands that should be run for the table.
68
     *
69
     * @var Fluent[]
70
     */
71
    protected $commands = [];
72
73
    /**
74
     * Catching columns to be able to add fluent indexes.
75
     *
76
     * @var array
77
     */
78
    protected $columns = [];
79
80
    /**
81
     * Whether to make the table temporary.
82
     *
83
     * @var bool
84
     */
85
    public $temporary = false;
86
87
    /**
88
     * Detect if _id should autoincrement.
89
     *
90
     * @var bool
91
     */
92
    protected $autoIncrement = false;
93
94
    /**
95
     * Create a new schema blueprint.
96
     *
97
     * Blueprint constructor.
98
     *
99
     * @param  string  $table
100
     * @param  SchemaManager  $schemaManager
101
     * @param  Closure|null  $callback
102
     * @param  string  $prefix
103
     */
104 13
    public function __construct($table, $schemaManager, Closure $callback = null, $prefix = '')
105
    {
106 13
        $this->table = $table;
107
108 13
        $this->schemaManager = $schemaManager;
109
110 13
        $this->prefix = $prefix;
111
112 13
        if (! is_null($callback)) {
113 9
            $callback($this);
114
        }
115
    }
116
117
    /**
118
     * Execute the blueprint against the database.
119
     *
120
     * @param  Connection  $connection
121
     * @param  Grammar  $grammar
122
     * @return void
123
     */
124 13
    public function build(Connection $connection, Grammar $grammar = null)
125
    {
126 13
        $this->connection = $connection;
127
128 13
        if (! isset($grammar)) {
129
            $this->grammar = $connection->getSchemaGrammar();
130
        }
131
132 13
        foreach ($this->commands as $command) {
133 11
            if ($command->handler == 'aql') {
134
                $command = $this->compileAqlCommand($command);
135
            }
136
137 11
            $this->executeCommand($command);
138
        }
139
    }
140
141
    /**
142
     * Generate the compilation method name and call it if method exists in the Grammar object.
143
     */
144
    public function compileAqlCommand(Fluent $command): Fluent
145
    {
146
        $compileMethod = 'compile'.ucfirst($command->name);
147
        if (method_exists($this->grammar, $compileMethod)) {
148
            return $this->grammar->$compileMethod($this->table, $command);
149
        }
150
151
        return $command;
152
    }
153
154
    /**
155
     * Generate the execution method name and call it if the method exists.
156
     */
157 11
    public function executeCommand(Fluent $command)
158
    {
159 11
        $executeNamedMethod = 'execute'.ucfirst($command->name).'Command';
160 11
        $executeHandlerMethod = 'execute'.ucfirst($command->handler).'Command';
161 11
        if (method_exists($this, $executeNamedMethod)) {
162 11
            $this->$executeNamedMethod($command);
163
        } elseif (method_exists($this, $executeHandlerMethod)) {
164
            $this->$executeHandlerMethod($command);
165
        }
166
    }
167
168
    /**
169
     * Execute an AQL statement.
170
     */
171
    public function executeAqlCommand(Fluent $command)
172
    {
173
        $this->connection->statement($command->aqb->query, $command->aqb->binds);
174
    }
175
176
    public function executeCollectionCommand(Fluent $command): void
177
    {
178
        if ($this->connection->pretending()) {
179
            $this->connection->logQuery('/* '.$command->explanation." */\n", []);
180
181
            return;
182
        }
183
184
        if (method_exists($this->schemaManager, $command->method)) {
185
            $this->schemaManager->{$command->method}($command->parameters);
186
        }
187
    }
188
189
    /**
190
     * Solely provides feedback to the developer in pretend mode.
191
     *
192
     * @return null
193
     */
194 4
    public function executeIgnoreCommand(Fluent $command)
195
    {
196 4
        if ($this->connection->pretending()) {
197
            $this->connection->logQuery('/* '.$command->explanation." */\n", []);
198
199
            return;
200
        }
201
    }
202
203
    /**
204
     * Add a new command to the blueprint.
205
     *
206
     * @param  string  $name
207
     * @param  array  $parameters
208
     * @return Fluent
209
     */
210 11
    protected function addCommand($name, array $parameters = [])
211
    {
212 11
        $this->commands[] = $command = $this->createCommand($name, $parameters);
213
214 11
        return $command;
215
    }
216
217
    /**
218
     * Create a new Fluent command.
219
     *
220
     * @param  string  $name
221
     * @param  array  $parameters
222
     * @return Fluent
223
     */
224 11
    protected function createCommand($name, array $parameters = [])
225
    {
226 11
        return new Fluent(array_merge(compact('name'), $parameters));
227
    }
228
229
    /**
230
     * Get the commands on the blueprint.
231
     *
232
     * @return Fluent[]
233
     */
234 3
    public function getCommands()
235
    {
236 3
        return $this->commands;
237
    }
238
239
    /**
240
     * Silently catch unsupported schema methods. Store columns for backwards compatible fluent index creation.
241
     *
242
     * @param  string  $method
243
     * @param  array<mixed>  $args
244
     * @return Blueprint
245
     */
246 4
    public function __call(string $method, array $args = [])
247
    {
248 4
        $columnMethods = [
249 4
            'bigIncrements', 'bigInteger', 'binary', 'boolean', 'char', 'date', 'dateTime', 'dateTimeTz', 'decimal',
250 4
            'double', 'enum', 'engine', 'float', 'foreignId', 'geometry', 'geometryCollection', 'increments', 'integer',
251 4
            'ipAddress', 'json', 'jsonb', 'lineString', 'longText', 'macAddress', 'mediumIncrements', 'mediumInteger',
252 4
            'mediumText', 'morphs', 'uuidMorphs', 'multiLineString', 'multiPoint', 'multiPolygon',
253 4
            'nullableMorphs', 'nullableUuidMorphs', 'nullableTimestamps', 'point', 'polygon', 'rememberToken',
254 4
            'set', 'smallIncrements', 'smallInteger', 'softDeletes', 'softDeletesTz', 'string',
255 4
            'text', 'time', 'timeTz', 'timestamp', 'timestampTz', 'timestamps', 'tinyIncrements', 'tinyInteger',
256 4
            'unsignedBigInteger', 'unsignedDecimal', 'unsignedInteger', 'unsignedMediumInteger', 'unsignedSmallInteger',
257 4
            'unsignedTinyInteger', 'uuid', 'year',
258 4
        ];
259
260 4
        if (in_array($method, $columnMethods)) {
261 4
            if (isset($args[0]) && is_string($args[0])) {
262 4
                $this->columns[] = $args[0];
263
            }
264
        }
265
266 4
        $autoIncrementMethods = ['increments', 'autoIncrement'];
267 4
        if (in_array($method, $autoIncrementMethods)) {
268
            $this->autoIncrement = true;
269
        }
270
271 4
        $info = [];
272 4
        $info['method'] = $method;
273 4
        $info['explanation'] = "'$method' is ignored; Aranguent Schema Blueprint doesn't support it.";
274 4
        $this->addCommand('ignore', $info);
275
276 4
        return $this;
277
    }
278
}
279