Skip to content

Commit

Permalink
Merge pull request #3 from rcrosbourne/feature/add-ulid-column-type
Browse files Browse the repository at this point in the history
Feature/add ulid column type
  • Loading branch information
rcrosbourne authored Dec 9, 2023
2 parents c71357c + d63b441 commit 2226e6a
Show file tree
Hide file tree
Showing 23 changed files with 220 additions and 19 deletions.
4 changes: 2 additions & 2 deletions src/Blueprint.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ public function parse($content, $strip_dashes = true)
);

$content = preg_replace_callback(
'/^(\s+)uuid(: true)?$/mi',
fn ($matches) => $matches[1] . 'id: uuid primary',
'/^(\s+)(ulid|uuid)(: true)?$/mi',
fn ($matches) => $matches[1] . 'id: ' . $matches[2] . ' primary',
$content
);

Expand Down
6 changes: 5 additions & 1 deletion src/Generators/FactoryGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ protected function buildDefinition(Model $model): string
$definition .= sprintf('%s::factory()->create()->%s', $class, $key);
$definition .= ',' . PHP_EOL;
}
} elseif ($column->dataType() === 'id' || ($column->dataType() === 'uuid' && Str::endsWith($column->name(), '_id'))) {
} elseif ($column->dataType() === 'id' || (in_array($column->dataType(), ['uuid', 'ulid']) && Str::endsWith($column->name(), '_id'))) {
$name = Str::beforeLast($column->name(), '_id');
$class = Str::studly($column->attributes()[0] ?? $name);
$reference = $this->fullyQualifyModelReference($class) ?? $model;
Expand Down Expand Up @@ -156,6 +156,10 @@ protected function buildDefinition(Model $model): string
$definition .= str_repeat(self::INDENT, 3) . "'{$column->name()}' => ";
$definition .= 'Str::random(10)';
$definition .= ',' . PHP_EOL;
} elseif ($column->dataType() === 'ulid') {
$definition .= str_repeat(self::INDENT, 3) . "'{$column->name()}' => ";
$definition .= '(string) Str::ulid()';
$definition .= ',' . PHP_EOL;
} else {
$definition .= str_repeat(self::INDENT, 3) . "'{$column->name()}' => ";

Expand Down
27 changes: 13 additions & 14 deletions src/Generators/MigrationGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ protected function buildDefinition(Model $model): string
);
}

if (!empty($columnAttributes) && !$this->isIdOrUuid($column->dataType())) {
if (!empty($columnAttributes) && !$this->isIdUlidOrUuid($column->dataType())) {
$column_definition .= ', ';

if (in_array($column->dataType(), ['set', 'enum'])) {
Expand All @@ -221,7 +221,7 @@ protected function buildDefinition(Model $model): string
$column->modifiers()
);

if ($this->isIdOrUuid($column->dataType())) {
if ($this->isIdUlidOrUuid($column->dataType())) {
$column_definition = $foreign;
$foreign = '';
}
Expand All @@ -232,7 +232,7 @@ protected function buildDefinition(Model $model): string
|| (is_array($modifier) && key($modifier) === 'onDelete')
|| (is_array($modifier) && key($modifier) === 'onUpdate')
|| $modifier === 'foreign'
|| ($modifier === 'nullable' && $this->isIdOrUuid($column->dataType()))
|| ($modifier === 'nullable' && $this->isIdUlidOrUuid($column->dataType()))
);
}

Expand Down Expand Up @@ -347,7 +347,7 @@ protected function buildForeignKey(string $column_name, ?string $on, string $typ
$column = Str::afterLast($column_name, '_');
}

if ($this->isIdOrUuid($type) && !empty($attributes)) {
if ($this->isIdUlidOrUuid($type) && !empty($attributes)) {
$table = Str::lower(Str::plural($attributes[0]));
}

Expand All @@ -364,12 +364,12 @@ protected function buildForeignKey(string $column_name, ?string $on, string $typ
$on_update_suffix = self::ON_UPDATE_CLAUSES[$on_update_clause];
}

if ($this->isIdOrUuid($type)) {
if ($type === 'uuid') {
$method = 'foreignUuid';
} else {
$method = 'foreignId';
}
if ($this->isIdUlidOrUuid($type)) {
$method = match ($type) {
'ulid' => 'foreignUlid',
'uuid' => 'foreignUuid',
default => 'foreignId',
};

$prefix = in_array('nullable', $modifiers)
? '$table->' . "{$method}('{$column_name}')->nullable()"
Expand All @@ -381,7 +381,6 @@ protected function buildForeignKey(string $column_name, ?string $on, string $typ
if ($on_update_clause === 'cascade') {
$on_update_suffix = '->cascadeOnUpdate()';
}

if ($column_name === Str::singular($table) . '_' . $column) {
return self::INDENT . "{$prefix}->constrained(){$on_delete_suffix}{$on_update_suffix}";
}
Expand Down Expand Up @@ -469,7 +468,7 @@ private function shouldAddForeignKeyConstraint(\Blueprint\Models\Column $column)
}

return config('blueprint.use_constraints')
&& ($this->isIdOrUuid($column->dataType()) && Str::endsWith($column->name(), '_id'));
&& ($this->isIdUlidOrUuid($column->dataType()) && Str::endsWith($column->name(), '_id'));
}

protected function isNumericDefault(string $type, string $value): bool
Expand All @@ -486,8 +485,8 @@ protected function isNumericDefault(string $type, string $value): bool
->contains(fn ($value) => strtolower($value) === strtolower($type));
}

protected function isIdOrUuid(string $dataType): bool
protected function isIdUlidOrUuid(string $dataType): bool
{
return in_array($dataType, ['id', 'uuid']);
return in_array($dataType, ['id', 'ulid', 'uuid']);
}
}
20 changes: 18 additions & 2 deletions src/Generators/ModelGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ protected function populateStub(string $stub, Model $model): string
$stub = $this->addTraits($model, $stub);
$stub = str_replace('{{ imports }}', $this->buildImports($model), $stub);

dump($stub);
return $stub;
}

Expand All @@ -90,6 +91,16 @@ protected function buildClassPhpDoc(Model $model): string
$phpDoc .= PHP_EOL;
$phpDoc .= ' * @property string|null $' . $column->name() . '_type';
$phpDoc .= PHP_EOL;
} elseif ($column->dataType() === 'ulidMorphs') {
$phpDoc .= ' * @property string $' . $column->name() . '_id';
$phpDoc .= PHP_EOL;
$phpDoc .= ' * @property string $' . $column->name() . '_type';
$phpDoc .= PHP_EOL;
} elseif ($column->dataType() === 'nullableUlidMorphs') {
$phpDoc .= ' * @property string|null $' . $column->name() . '_id';
$phpDoc .= PHP_EOL;
$phpDoc .= ' * @property string|null $' . $column->name() . '_type';
$phpDoc .= PHP_EOL;
} elseif ($column->dataType() === 'uuidMorphs') {
$phpDoc .= ' * @property string $' . $column->name() . '_id';
$phpDoc .= PHP_EOL;
Expand Down Expand Up @@ -272,12 +283,17 @@ protected function buildRelationships(Model $model): string
protected function addTraits(Model $model, $stub): string
{
$traits = ['HasFactory'];

if ($model->usesSoftDeletes()) {
$this->addImport($model, 'Illuminate\\Database\\Eloquent\\SoftDeletes');
$traits[] = 'SoftDeletes';
}


if ($model->usesUlids()) {
$this->addImport($model, 'Illuminate\\Database\\Eloquent\\Concerns\\HasUlids');
$traits[] = 'HasUlids';
}

if ($model->usesUuids()) {
$this->addImport($model, 'Illuminate\\Database\\Eloquent\\Concerns\\HasUuids');
$traits[] = 'HasUuids';
Expand Down
1 change: 1 addition & 0 deletions src/Lexers/ModelLexer.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class ModelLexer implements Lexer
'unsignedmediuminteger' => 'unsignedMediumInteger',
'unsignedsmallinteger' => 'unsignedSmallInteger',
'unsignedtinyinteger' => 'unsignedTinyInteger',
'ulid' => 'ulid',
'uuid' => 'uuid',
'year' => 'year',
];
Expand Down
4 changes: 4 additions & 0 deletions src/Models/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ public function usesPrimaryKey(): bool
return $this->primaryKey !== false;
}

public function usesUlids(): bool
{
return $this->usesPrimaryKey() && $this->columns[$this->primaryKey]->dataType() === 'ulid';
}
public function usesUuids(): bool
{
return $this->usesPrimaryKey() && $this->columns[$this->primaryKey]->dataType() === 'uuid';
Expand Down
16 changes: 16 additions & 0 deletions tests/Feature/BlueprintTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,22 @@ public function it_parses_shorthands(): void
], $this->subject->parse($blueprint));
}

#[Test]
public function it_parses_ulid_shorthand(): void
{
$blueprint = $this->fixture('drafts/ulid-shorthand.yaml');

$this->assertEquals([
'models' => [
'Person' => [
'id' => 'ulid primary',
'timestamps' => 'timestamps',
'company_id' => 'ulid',
],
],
], $this->subject->parse($blueprint));
}

#[Test]
public function it_parses_uuid_shorthand(): void
{
Expand Down
3 changes: 3 additions & 0 deletions tests/Feature/Generators/MigrationGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,9 @@ public static function modelTreeDataProvider()
['drafts/optimize.yaml', 'database/migrations/timestamp_create_optimizes_table.php', 'migrations/optimize.php'],
['drafts/model-key-constraints.yaml', 'database/migrations/timestamp_create_orders_table.php', 'migrations/model-key-constraints.php'],
['drafts/disable-auto-columns.yaml', 'database/migrations/timestamp_create_states_table.php', 'migrations/disable-auto-columns.php'],
['drafts/ulid-shorthand.yaml', 'database/migrations/timestamp_create_people_table.php', 'migrations/ulid-shorthand.php'],
['drafts/ulid-shorthand-invalid-relationship.yaml', 'database/migrations/timestamp_create_age_cohorts_table.php', 'migrations/ulid-shorthand-invalid-relationship.php'],
['drafts/ulid-without-relationship.yaml', 'database/migrations/timestamp_create_vats_table.php', 'migrations/ulid-without-relationship.php'],
['drafts/uuid-shorthand.yaml', 'database/migrations/timestamp_create_people_table.php', 'migrations/uuid-shorthand.php'],
['drafts/uuid-shorthand-invalid-relationship.yaml', 'database/migrations/timestamp_create_age_cohorts_table.php', 'migrations/uuid-shorthand-invalid-relationship.php'],
['drafts/uuid-without-relationship.yaml', 'database/migrations/timestamp_create_vats_table.php', 'migrations/uuid-without-relationship.php'],
Expand Down
1 change: 1 addition & 0 deletions tests/Feature/Generators/ModelGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,7 @@ public static function modelTreeDataProvider(): array
['drafts/uuid-shorthand-invalid-relationship.yaml', 'app/Models/AgeCohort.php', 'models/uuid-shorthand-invalid-relationship.php'],
['drafts/model-with-meta.yaml', 'app/Models/Post.php', 'models/model-with-meta.php'],
['drafts/infer-belongsto.yaml', 'app/Models/Conference.php', 'models/infer-belongsto.php'],
['drafts/model-with-ulid-id.yaml', 'app/Models/User.php', 'models/model-with-ulid-trait.php'],
['drafts/model-with-uuid-id.yaml', 'app/Models/User.php', 'models/model-with-uuid-trait.php'],
];
}
Expand Down
3 changes: 3 additions & 0 deletions tests/fixtures/drafts/all-column-types.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ models:
mediumInteger: mediumInteger
mediumText: mediumText
morphs: morphs
ulidMorphs: ulidMorphs
uuidMorphs: uuidMorphs
multiLineString: multiLineString
multiPoint: multiPoint
multiPolygon: multiPolygon
nullableMorphs: nullableMorphs
nullableUlidMorphs: nullableUuidMorphs
nullableUuidMorphs: nullableUuidMorphs
nullableTimestamps: nullableTimestamps
point: point
Expand All @@ -50,5 +52,6 @@ models:
unsignedMediumInteger: unsignedMediumInteger
unsignedSmallInteger: unsignedSmallInteger
unsignedTinyInteger: unsignedTinyInteger
ulid: ulid
uuid: uuid
year: year
2 changes: 2 additions & 0 deletions tests/fixtures/drafts/model-key-constraints.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ models:
sub_id: uuid foreign:subscription
expires_at: timestamp nullable index
meta: json default:'[]'
customer_id: ulid foreign
tran_id: ulid foreign:transaction
5 changes: 5 additions & 0 deletions tests/fixtures/drafts/model-with-ulid-id.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
models:
User:
id: ulid primary
name: string
base_pay: decimal:10,2
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
models:
AgeCohort:
id
timestamps
name: string:100
description: string:500 nullable
min_age: integer nullable
max_age: integer nullable
ulid: ulid unique
5 changes: 5 additions & 0 deletions tests/fixtures/drafts/ulid-shorthand.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
models:
Person:
ulid
company_id: ulid
timestamps
3 changes: 3 additions & 0 deletions tests/fixtures/drafts/ulid-without-relationship.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
models:
Vat:
ulid: ulid
2 changes: 2 additions & 0 deletions tests/fixtures/factories/all-column-types.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public function definition(): array
'mediumText' => $this->faker->text(),
'morphs_id' => $this->faker->randomDigitNotNull(),
'morphs_type' => $this->faker->word(),
'ulidMorphs' => $this->faker->word(),
'uuidMorphs' => $this->faker->word(),
'multiLineString' => $this->faker->word(),
'multiPoint' => $this->faker->word(),
Expand All @@ -68,6 +69,7 @@ public function definition(): array
'unsignedMediumInteger' => $this->faker->randomNumber(),
'unsignedSmallInteger' => $this->faker->randomNumber(),
'unsignedTinyInteger' => $this->faker->randomDigitNotNull(),
'ulid' => (string) Str::ulid(),
'uuid' => $this->faker->uuid(),
'year' => $this->faker->year(),
];
Expand Down
4 changes: 4 additions & 0 deletions tests/fixtures/factories/model-key-constraints.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
use App\Models\Customer;
use App\Models\Order;
use App\Models\Subscription;
use App\Models\Transaction;
use App\Models\User;

class OrderFactory extends Factory
Expand All @@ -28,6 +30,8 @@ public function definition(): array
'sub_id' => Subscription::factory(),
'expires_at' => $this->faker->dateTime(),
'meta' => '[]',
'customer_id' => Customer::factory(),
'tran_id' => Transaction::factory(),
];
}
}
2 changes: 2 additions & 0 deletions tests/fixtures/migrations/model-key-constraints.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public function up(): void
$table->foreignUuid('sub_id')->constrained('subscriptions');
$table->timestamp('expires_at')->nullable()->index();
$table->json('meta')->default('[]');
$table->foreignUlid('customer_id')->constrained();
$table->foreignUlid('tran_id')->constrained('transactions');
$table->timestamps();
});

Expand Down
32 changes: 32 additions & 0 deletions tests/fixtures/migrations/ulid-shorthand-invalid-relationship.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('age_cohorts', function (Blueprint $table) {
$table->id();
$table->string('name', 100);
$table->string('description', 500)->nullable();
$table->integer('min_age')->nullable();
$table->integer('max_age')->nullable();
$table->ulid('ulid')->unique();
$table->timestamps();
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('age_cohorts');
}
};
28 changes: 28 additions & 0 deletions tests/fixtures/migrations/ulid-shorthand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('people', function (Blueprint $table) {
$table->ulid('id')->primary();
$table->ulid('company_id');
$table->timestamps();
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('people');
}
};
Loading

0 comments on commit 2226e6a

Please sign in to comment.