Skip to content

Commit

Permalink
Merge pull request #5 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 ec435d5 + 461f4e1 commit 2c71e68
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 6 deletions.
47 changes: 41 additions & 6 deletions src/Generators/MigrationGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public function output(Tree $tree, $overwrite = false): array
if (!empty($model->pivotTables())) {
foreach ($model->pivotTables() as $pivotSegments) {
$pivotTableName = $this->getPivotTableName($pivotSegments);
$tables['pivotTableNames'][$pivotTableName] = $this->populatePivotStub($stub, $pivotSegments);
$tables['pivotTableNames'][$pivotTableName] = $this->populatePivotStub($stub, $pivotSegments, $tree->models());
}
}

Expand Down Expand Up @@ -128,10 +128,10 @@ protected function populateStub(string $stub, Model $model): string
return $stub;
}

protected function populatePivotStub(string $stub, array $segments): string
protected function populatePivotStub(string $stub, array $segments, array $models = []): string
{
$stub = str_replace('{{ table }}', $this->getPivotTableName($segments), $stub);
$stub = str_replace('{{ definition }}', $this->buildPivotTableDefinition($segments), $stub);
$stub = str_replace('{{ definition }}', $this->buildPivotTableDefinition($segments, $models), $stub);

if ($this->hasForeignKeyConstraints) {
$stub = $this->disableForeignKeyConstraints($stub);
Expand Down Expand Up @@ -290,10 +290,9 @@ protected function buildDefinition(Model $model): string
return trim($definition);
}

protected function buildPivotTableDefinition(array $segments): string
protected function buildPivotTableDefinition(array $segments, array $models = []): string
{
$definition = '';

foreach ($segments as $segment) {
$column = Str::before(Str::snake($segment), ':');
$references = 'id';
Expand All @@ -304,13 +303,49 @@ protected function buildPivotTableDefinition(array $segments): string
$this->hasForeignKeyConstraints = true;
$definition .= $this->buildForeignKey($foreign, $on, 'id') . ';' . PHP_EOL;
} else {
$definition .= self::INDENT . '$table->foreignId(\'' . $foreign . '\');' . PHP_EOL;
$definition .= $this->generateForeignKeyDefinition($segment, $foreign, $models);
}
}

return trim($definition);
}

/**
* Generates the foreign key definition for a pivot table.
*
* This function generates the foreign key definition for a pivot table in a migration file.
* It checks if the model exists and its name matches the pivot table segment. If it does,
* it determines the data type of the primary key and appends the appropriate method call
* to the `$definition` string. If the model does not exist or its name does not match the
* pivot table segment, it defaults to appending `$table->foreignId(\'' . $foreignKeyColumnName . '\');`
* to the `$definition` string. The function then returns the `$definition` string.
*
* @param string $pivotTableSegment The segment of the pivot table. e.g 'dive_job' it would be 'Dive' or 'Job'.
* @param string $foreignKeyColumnName The name of the foreign key column. e.g 'dive_id' or 'job_id'.
* @param array $models An array of models. e.g ['Dive' => $diveModel, 'Job' => $jobModel].
* @return string The foreign key definition. e.g '$table->foreignUlid('dive_id');'
*/
protected function generateForeignKeyDefinition(string $pivotTableSegment, string $foreignKeyColumnName, array $models = []): string
{
$definition = self::INDENT;
if (count($models) > 0 && array_key_exists($pivotTableSegment, $models)) {
$model = $models[$pivotTableSegment];
if ($model->name() === $pivotTableSegment) {
$dataType = $model->columns()[$model->primaryKey()]->dataType();
$definition .= match ($dataType) {
'ulid' => '$table->foreignUlid(\'' . $foreignKeyColumnName . '\');',
'uuid' => '$table->foreignUuid(\'' . $foreignKeyColumnName . '\');',
default => '$table->foreignId(\'' . $foreignKeyColumnName . '\');',
};
}
} else {
$definition .= '$table->foreignId(\'' . $foreignKeyColumnName . '\');';
}
$definition .= PHP_EOL;

return $definition;
}

protected function buildPolyTableDefinition(string $parentTable): string
{
$definition = '';
Expand Down
29 changes: 29 additions & 0 deletions tests/Feature/Generators/MigrationGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,35 @@ public function output_creates_constraints_for_unconventional_foreign_reference_
$this->assertEquals(['created' => [$model_migration]], $this->subject->output($tree));
}

#[Test]
public function using_ulids_output_also_creates_pivot_table_migration(): void
{
$this->filesystem->expects('stub')
->with('migration.stub')
->andReturn($this->stub('migration.stub'));

$now = Carbon::now();
Carbon::setTestNow($now);

$journey_model_migration = str_replace('timestamp', $now->copy()->subSeconds(2)->format('Y_m_d_His'), 'database/migrations/timestamp_create_journeys_table.php');
$diary_model_migration = str_replace('timestamp', $now->copy()->subSecond()->format('Y_m_d_His'), 'database/migrations/timestamp_create_diaries_table.php');
$pivot_migration = str_replace('timestamp', $now->format('Y_m_d_His'), 'database/migrations/timestamp_create_diary_journey_table.php');

$this->filesystem->expects('exists')->times(3)->andReturn(false);

$this->filesystem->expects('put')
->with($journey_model_migration, $this->fixture('migrations/belongs-to-many-using-ulids-journey-model.php'));
$this->filesystem->expects('put')
->with($diary_model_migration, $this->fixture('migrations/belongs-to-many-using-ulids-diary-model.php'));
$this->filesystem->expects('put')
->with($pivot_migration, $this->fixture('migrations/belongs-to-many-pivot-using-ulids.php'));

$tokens = $this->blueprint->parse($this->fixture('drafts/belongs-to-many-using-ulids.yaml'));
$tree = $this->blueprint->analyze($tokens);

$this->assertEquals(['created' => [$journey_model_migration, $diary_model_migration, $pivot_migration]], $this->subject->output($tree));
}

#[Test]
public function output_also_creates_pivot_table_migration(): void
{
Expand Down
11 changes: 11 additions & 0 deletions tests/fixtures/drafts/belongs-to-many-using-ulids.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
models:
Journey:
id: ulid primary
name: string
user_id: ulid foreign
relationships:
belongsToMany: Diary
Diary:
id: ulid primary
relationships:
belongsToMany: Journey
31 changes: 31 additions & 0 deletions tests/fixtures/migrations/belongs-to-many-pivot-using-ulids.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?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::disableForeignKeyConstraints();

Schema::create('diary_journey', function (Blueprint $table) {
$table->foreignUlid('diary_id');
$table->foreignUlid('journey_id');
});

Schema::enableForeignKeyConstraints();
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('diary_journey');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?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::disableForeignKeyConstraints();

Schema::create('diaries', function (Blueprint $table) {
$table->ulid('id')->primary();
$table->timestamps();
});

Schema::enableForeignKeyConstraints();
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('diaries');
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?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::disableForeignKeyConstraints();

Schema::create('journeys', function (Blueprint $table) {
$table->ulid('id')->primary();
$table->string('name');
$table->foreignUlid('user_id')->constrained();
$table->timestamps();
});

Schema::enableForeignKeyConstraints();
}

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

0 comments on commit 2c71e68

Please sign in to comment.