Skip to content

Commit b4e6e65

Browse files
Merge pull request #181 from LaravelFreelancerNL/131-configure-default-key-options
131 configure default key options
2 parents bea07ea + b18361a commit b4e6e65

File tree

12 files changed

+295
-96
lines changed

12 files changed

+295
-96
lines changed

TestSetup/Database/Migrations/2019_11_15_000000_create_taggables_table.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@ public function up()
1616
{
1717
Schema::create('taggables', function (Blueprint $collection) {
1818
//
19-
});
19+
}, [
20+
'keyOptions' => [
21+
'type' => 'padded',
22+
],
23+
]);
2024
}
2125

2226
/**

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
"require": {
2525
"php": "^8.2",
2626
"ext-json": "*",
27-
"composer/composer": "^2.7.0",
28-
"laravel-freelancer-nl/arangodb-php-client": "^2.7.0",
27+
"composer/composer": "^2.8.0",
28+
"laravel-freelancer-nl/arangodb-php-client": "^2.8.0",
2929
"laravel-freelancer-nl/fluentaql": "^2.0",
3030
"laravel/framework": "^11.0",
3131
"spatie/laravel-data": "^4.4.0",

config/arangodb.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,22 @@
55
return [
66
'datetime_format' => 'Y-m-d\TH:i:s.vp',
77
'schema' => [
8+
/*
9+
* @see https://docs.arangodb.com/stable/develop/http-api/collections/#create-a-collection_body_keyOptions_allowUserKeys
10+
*/
811
'keyOptions' => [
912
'allowUserKeys' => true,
1013
'type' => 'traditional',
1114
],
15+
'key_handling' => [
16+
'prioritize_configured_key_type' => false,
17+
'use_traditional_over_autoincrement' => true,
18+
],
19+
// Key type prioritization takes place in the following order:
20+
// 1: table config within the migration file (this always takes priority)
21+
// 2: The id column methods such as id() and ...Increments() methods in the migration file
22+
// 3: The configured key type above.
23+
// The order of 2 and 3 can be swapped; in which case the configured key takes priority over column methods.
24+
// These settings are merged, individual keyOptions can be overridden in this way.
1225
],
1326
];

docs/key-options.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Key generator options
2+
Tables in ArangoDB can be created using one of the available key generators. You can read up about them
3+
[here](https://docs.arangodb.com/stable/concepts/data-structure/documents/#document-keys)
4+
and [here](https://docs.arangodb.com/stable/develop/http-api/collections/#create-a-collection_body_keyOptions).
5+
6+
The following assumes you have knowledge about ArangoDB keys as can be obtained through the above links.
7+
8+
## Column defined key generators
9+
Laravel has several column methods which can be used to set a primary key. If the given field is equal to:
10+
'id', '_key' or '_id', the key generator will be set according to the mapping below.
11+
12+
If these column methods are not found, or not called on these fields, the configured default generator is used.
13+
You can also ignore the column methods by setting the config value
14+
'arangodb.schema.key_handling.prioritize_configured_key_type' to true.
15+
16+
By default, we map the key methods to the following ArangoDB key generators:
17+
18+
| Laravel column method | ArangoDB key generator |
19+
|:----------------------|:-----------------------|
20+
| autoIncrement() | traditional |
21+
| id() | traditional |
22+
| increments('id') | traditional |
23+
| smallIncrements | traditional |
24+
| bigIncrements | traditional |
25+
| mediumIncrements | traditional |
26+
| uuid(id) | uuid |
27+
| ulid(id) | _n/a_ |
28+
29+
## Traditional vs autoincrement key generators
30+
Even though ArangoDB has an autoincrement key generator we don't use it by default as it is not cluster safe.
31+
The traditional key generator is similar to autoincrement: it is cluster safe although there may be gaps between
32+
the _key increases.
33+
34+
If you want the column methods to set the generator to autoincrement you can override the default behaviour by setting
35+
the config value 'arangodb.schema.key_handling.use_traditional_over_autoincrement' to false.
36+
In which case any given offset in the 'from' method is also used.
37+
38+
## ulid
39+
There is no ulid key generator in ArangoDB. The 'padded' generator may be used if you want
40+
a lexigraphical sort order. You can do so by setting it in the config as the default key, and using configured keys only.
41+
Or by setting it within the migration in the table options.
42+
43+
## Table option key generators
44+
You can set the key options for the table in the migration. This overrides both the default key options and the one defined by column methods.
45+
46+
```
47+
Schema::create('taggables', function (Blueprint $collection) {
48+
//
49+
}, [
50+
'keyOptions' => [
51+
'type' => 'padded',
52+
],
53+
]);
54+
```
55+

src/Connection.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ class Connection extends IlluminateConnection
2727
use ManagesTransactions;
2828
use RunsQueries;
2929

30-
protected ?ArangoClient $arangoClient = null;
30+
/**
31+
* @var ArangoClient|null
32+
*/
33+
protected $arangoClient;
3134

3235
/**
3336
* The ArangoDB driver name.

src/Schema/Blueprint.php

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@
99
use Illuminate\Support\Fluent;
1010
use Illuminate\Support\Traits\Macroable;
1111
use LaravelFreelancerNL\Aranguent\Connection;
12-
use LaravelFreelancerNL\Aranguent\Schema\Concerns\Columns;
13-
use LaravelFreelancerNL\Aranguent\Schema\Concerns\Indexes;
14-
use LaravelFreelancerNL\Aranguent\Schema\Concerns\Tables;
12+
use LaravelFreelancerNL\Aranguent\Schema\Concerns\ColumnCommands;
13+
use LaravelFreelancerNL\Aranguent\Schema\Concerns\IndexCommands;
14+
use LaravelFreelancerNL\Aranguent\Schema\Concerns\TableCommands;
1515

1616
/**
1717
* Class Blueprint.
@@ -28,9 +28,9 @@
2828
class Blueprint
2929
{
3030
use Macroable;
31-
use Tables;
32-
use Columns;
33-
use Indexes;
31+
use TableCommands;
32+
use ColumnCommands;
33+
use IndexCommands;
3434

3535
/**
3636
* The connection that is used by the blueprint.
@@ -282,28 +282,16 @@ public function __call($method, $args = [])
282282
}
283283
}
284284

285-
$autoIncrementMethods = ['increments', 'autoIncrement'];
286-
if (in_array($method, $autoIncrementMethods)) {
287-
$this->setKeyGenerator('autoincrement');
288-
}
289-
290-
if ($method === 'uuid') {
291-
$this->setKeyGenerator('uuid');
285+
$keyMethods = ['autoIncrement', 'bigIncrements', 'increments', 'mediumIncrements', 'tinyIncrements', 'uuid'];
286+
if (in_array($method, $keyMethods)) {
287+
$this->handleKeyCommands($method, $args);
292288
}
293289

294290
$this->ignoreMethod($method);
295291

296292
return $this;
297293
}
298294

299-
protected function setKeyGenerator(string $generator = 'traditional'): void
300-
{
301-
$column = end($this->columns);
302-
if ($column === '_key' || $column === 'id') {
303-
$this->keyGenerator = $generator;
304-
}
305-
}
306-
307295
protected function ignoreMethod(string $method)
308296
{
309297
$info = [];
@@ -318,4 +306,26 @@ public function renameIdField(mixed $fields)
318306
return $value === 'id' ? '_key' : $value;
319307
}, $fields);
320308
}
309+
310+
/**
311+
* @param mixed[] $options
312+
* @return mixed[]
313+
*/
314+
protected function setKeyOptions($tableOptions)
315+
{
316+
$configuredKeyOptions = config('arangodb.schema.keyOptions');
317+
318+
$columnOptions = [];
319+
$columnOptions['type'] = $this->keyGenerator;
320+
321+
$mergedKeyOptions = (config('arangodb.schema.key_handling.prioritize_configured_key_type'))
322+
? array_merge($columnOptions, $configuredKeyOptions, $tableOptions)
323+
: array_merge($configuredKeyOptions, $columnOptions, $tableOptions);
324+
325+
if ($mergedKeyOptions['type'] === 'autoincrement' && $this->incrementOffset !== 0) {
326+
$mergedKeyOptions['offset'] = $this->incrementOffset;
327+
}
328+
329+
return $mergedKeyOptions;
330+
}
321331
}

src/Schema/Concerns/Columns.php renamed to src/Schema/Concerns/ColumnCommands.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use Illuminate\Support\Fluent;
88

9-
trait Columns
9+
trait ColumnCommands
1010
{
1111
/**
1212
* Indicate that the given attributes should be renamed.

src/Schema/Concerns/Indexes.php renamed to src/Schema/Concerns/IndexCommands.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use ArangoClient\Exceptions\ArangoException;
66
use Illuminate\Support\Fluent;
77

8-
trait Indexes
8+
trait IndexCommands
99
{
1010
use HandlesIndexNaming;
1111

src/Schema/Concerns/Tables.php renamed to src/Schema/Concerns/TableCommands.php

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use Illuminate\Support\Fluent;
88

9-
trait Tables
9+
trait TableCommands
1010
{
1111
/**
1212
* Indicate that the table needs to be created.
@@ -17,35 +17,55 @@ trait Tables
1717
public function create($options = [])
1818
{
1919
$parameters = [];
20-
$parameters['options'] = array_merge(
21-
[
22-
'keyOptions' => config('arangodb.schema.keyOptions'),
23-
],
24-
$options,
25-
);
20+
$parameters['options'] = $options;
2621
$parameters['explanation'] = "Create '{$this->table}' table.";
2722
$parameters['handler'] = 'table';
2823

2924
return $this->addCommand('create', $parameters);
3025
}
3126

32-
public function executeCreateCommand($command)
27+
/**
28+
* @param string $command
29+
* @param mixed[] $args
30+
* @return void
31+
*/
32+
public function handleKeyCommands($command, $args)
3333
{
34-
if ($this->connection->pretending()) {
35-
$this->connection->logQuery('/* ' . $command->explanation . " */\n", []);
34+
$acceptedKeyFields = ['id', '_id', '_key'];
35+
36+
$columns = ($command === 'autoIncrement') ? end($this->columns) : $args;
37+
$columns = (is_array($columns)) ? $columns : [$columns];
3638

39+
if (count($columns) !== 1 || ! in_array($columns[0], $acceptedKeyFields)) {
3740
return;
3841
}
39-
$options = $command->options;
4042

41-
if ($this->keyGenerator !== 'traditional') {
42-
$options['keyOptions']['type'] = $this->keyGenerator;
43+
if ($command === 'uuid') {
44+
$this->keyGenerator = 'uuid';
45+
46+
return;
4347
}
4448

45-
if ($this->keyGenerator === 'autoincrement' && $this->incrementOffset !== 0) {
46-
$options['keyOptions']['offset'] = $this->incrementOffset;
49+
if (config('arangodb.schema.key_handling.use_traditional_over_autoincrement') === false) {
50+
$this->keyGenerator = 'autoincrement';
51+
52+
return;
4753
}
4854

55+
$this->keyGenerator = 'traditional';
56+
}
57+
58+
public function executeCreateCommand($command)
59+
{
60+
if ($this->connection->pretending()) {
61+
$this->connection->logQuery('/* ' . $command->explanation . " */\n", []);
62+
63+
return;
64+
}
65+
66+
$options = $command->options;
67+
$options['keyOptions'] = $this->setKeyOptions($options['keyOptions'] ?? []);
68+
4969
if (!$this->schemaManager->hasCollection($this->table)) {
5070
$this->schemaManager->createCollection($this->table, $options);
5171
}

tests/Console/ShowModelCommandTest.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,21 @@
2424
->expectsOutputToContain('computed')
2525
->assertSuccessful();
2626
});
27+
28+
test('model:show \\TestSetup\\Models\\Child', function () {
29+
$this->artisan('model:show', ['model' => '\\TestSetup\\Models\\Child'])
30+
->expectsOutputToContain('arangodb')
31+
->expectsOutputToContain('children')
32+
->expectsOutputToContain('traditional')
33+
->doesntExpectOutput('computed')
34+
->assertSuccessful();
35+
});
36+
37+
test('model:show \\TestSetup\\Models\\House', function () {
38+
$this->artisan('model:show', ['model' => '\\TestSetup\\Models\\House'])
39+
->expectsOutputToContain('arangodb')
40+
->expectsOutputToContain('houses')
41+
->expectsOutputToContain('traditional')
42+
->doesntExpectOutput('computed')
43+
->assertSuccessful();
44+
});

0 commit comments

Comments
 (0)