Skip to content

Commit

Permalink
Merge pull request #41 from TheDragonCode/3.x
Browse files Browse the repository at this point in the history
Fixed bug with transferring UUID and ULID as primary key
  • Loading branch information
andrey-helldar authored Dec 15, 2023
2 parents a52471c + 379476b commit f9e4bd4
Show file tree
Hide file tree
Showing 12 changed files with 363 additions and 12 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/phpunit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ jobs:
strategy:
fail-fast: true
matrix:
php: [ "8.0", "8.1", "8.2" ]
php: [ "8.0", "8.1", "8.2", "8.3" ]
laravel: [ "8.0", "9.0", "10.0" ]
psql: [ "9", "10", "11", "12", "13", "14", "15" ]
exclude:
- laravel: "8.0"
php: "8.3"
- laravel: "9.0"
php: "8.3"
- laravel: "10.0"
php: "8.0"

Expand Down
14 changes: 3 additions & 11 deletions src/Console/Migrate.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,16 +132,6 @@ protected function migrateTable(string $table, string $column): void
Log::info('Transferring data from: ' . $table);

$this->builder($this->source(), $table)
->when(
$this->isSkippable($table, $column),
function ($query) use ($table, $column) {
$lastRecord = $this->builder($this->target(), $table)->max($column) ?: 0;

Log::info('last record: ' . $lastRecord);

return $query->where($column, '>', $lastRecord);
}
)
->orderBy($column)
->chunk(1000, function (Collection $items) use ($table) {
$items = Arr::resolve($items);
Expand All @@ -159,7 +149,9 @@ protected function isSkippable(string $table, string $column): bool

protected function isNumericColumn(string $table, string $column): bool
{
return $this->getPrimaryKeyType($this->source(), $table, $column) !== 'string';
$type = $this->getPrimaryKeyType($this->source(), $table, $column);

return ! in_array($type, ['string', 'char', 'ulid', 'uuid'], true);
}

protected function tables(): array
Expand Down
5 changes: 5 additions & 0 deletions tests/Concerns/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
/** @mixin \Tests\Concerns\Connections */
trait Database
{
use HasUuidAndUlid;
use Seeders;

protected $connectors = [
Expand All @@ -27,6 +28,10 @@ trait Database

protected $table_baz = 'baz';

protected $table_ulid = 'ulid_table';

protected $table_uuid = 'uuid_table';

protected $choice_target = 'target';

protected $choice_source = 'source';
Expand Down
23 changes: 23 additions & 0 deletions tests/Concerns/HasUuidAndUlid.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Tests\Concerns;

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Str;

trait HasUuidAndUlid
{
protected function hasUuid()
{
return method_exists(Blueprint::class, 'uuid')
&& method_exists(Str::class, 'uuid');
}

protected function hasUlid()
{
return method_exists(Blueprint::class, 'ulid')
&& method_exists(Str::class, 'ulid');
}
}
2 changes: 2 additions & 0 deletions tests/Concerns/Migration.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

abstract class Migration extends BaseMigration
{
use HasUuidAndUlid;

protected $table;

public function up()
Expand Down
27 changes: 27 additions & 0 deletions tests/Concerns/Seeders.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Tests\Concerns;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

trait Seeders
{
Expand All @@ -11,6 +12,14 @@ protected function fillTables(): void
$this->fillTable($this->table_foo);
$this->fillTable($this->table_bar);
$this->fillTable($this->table_baz);

if ($this->hasUlid()) {
$this->fillUlidTable($this->table_ulid);
}

if ($this->hasUuid()) {
$this->fillUuidTable($this->table_uuid);
}
}

protected function fillTable(string $table): void
Expand All @@ -21,4 +30,22 @@ protected function fillTable(string $table): void
['value' => $table . '_3'],
]);
}

protected function fillUlidTable(string $table): void
{
DB::connection($this->source_connection)->table($table)->insert([
['value' => $table . '_1', 'ulid' => (string) Str::ulid()],
['value' => $table . '_2', 'ulid' => (string) Str::ulid()],
['value' => $table . '_3', 'ulid' => (string) Str::ulid()],
]);
}

protected function fillUuidTable(string $table): void
{
DB::connection($this->source_connection)->table($table)->insert([
['value' => $table . '_1', 'uuid' => Str::uuid()->toString()],
['value' => $table . '_2', 'uuid' => Str::uuid()->toString()],
['value' => $table . '_3', 'uuid' => Str::uuid()->toString()],
]);
}
}
64 changes: 64 additions & 0 deletions tests/Unit/MysqlToMysqlTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,70 @@ public function testSame()
);
}

public function testUlidKeysAsPrimaryKey()
{
if (! $this->hasUlid()) {
$this->assertTrue(true);

return;
}

$this->artisan('migrate', [
'--database' => $this->source_connection,
'--realpath' => true,
'--path' => __DIR__ . '/../fixtures/primary_keys/2023_12_15_014834_create_ulid_primary_key.php',
])->run();

$this->fillUlidTable($this->table_ulid);

$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_1'], $this->source_connection);
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_2'], $this->source_connection);
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_3'], $this->source_connection);

$this->artisan('db:migrate', [
'--schema-from' => $this->source_connection,
'--schema-to' => $this->target_connection,
])
->expectsConfirmation('Please confirm table list should be retrieved from target connection? (incase if source connection does not support it)', 'no')
->expectsConfirmation('Please confirm whether to truncate target table before transfer?', 'yes')
->expectsConfirmation('Please choose whether to drop target tables before migration?', 'no')
->expectsChoice('Please choose option to run migration on which connection?', $this->choice_source, $this->choices)
->assertExitCode(0)
->run();

$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_1'], $this->target_connection);
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_2'], $this->target_connection);
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_3'], $this->target_connection);
}

public function testUuidKeysAsPrimaryKey()
{
if (! $this->hasUuid()) {
$this->assertTrue(true);

return;
}

$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_1'], $this->source_connection);
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_2'], $this->source_connection);
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_3'], $this->source_connection);

$this->artisan('db:migrate', [
'--schema-from' => $this->source_connection,
'--schema-to' => $this->target_connection,
])
->expectsConfirmation('Please confirm table list should be retrieved from target connection? (incase if source connection does not support it)', 'no')
->expectsConfirmation('Please confirm whether to truncate target table before transfer?', 'yes')
->expectsConfirmation('Please choose whether to drop target tables before migration?', 'no')
->expectsChoice('Please choose option to run migration on which connection?', $this->choice_source, $this->choices)
->assertExitCode(0)
->run();

$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_1'], $this->target_connection);
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_2'], $this->target_connection);
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_3'], $this->target_connection);
}

public function testFailed()
{
$this->expectException(InvalidArgumentException::class);
Expand Down
64 changes: 64 additions & 0 deletions tests/Unit/MysqlToPostgresTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,70 @@ public function testSame()
);
}

public function testUlidKeysAsPrimaryKey()
{
if (! $this->hasUlid()) {
$this->assertTrue(true);

return;
}

$this->artisan('migrate', [
'--database' => $this->source_connection,
'--realpath' => true,
'--path' => __DIR__ . '/../fixtures/primary_keys/2023_12_15_014834_create_ulid_primary_key.php',
])->run();

$this->fillUlidTable($this->table_ulid);

$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_1'], $this->source_connection);
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_2'], $this->source_connection);
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_3'], $this->source_connection);

$this->artisan('db:migrate', [
'--schema-from' => $this->source_connection,
'--schema-to' => $this->target_connection,
])
->expectsConfirmation('Please confirm table list should be retrieved from target connection? (incase if source connection does not support it)', 'no')
->expectsConfirmation('Please confirm whether to truncate target table before transfer?', 'yes')
->expectsConfirmation('Please choose whether to drop target tables before migration?', 'no')
->expectsChoice('Please choose option to run migration on which connection?', $this->choice_source, $this->choices)
->assertExitCode(0)
->run();

$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_1'], $this->target_connection);
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_2'], $this->target_connection);
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_3'], $this->target_connection);
}

public function testUuidKeysAsPrimaryKey()
{
if (! $this->hasUuid()) {
$this->assertTrue(true);

return;
}

$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_1'], $this->source_connection);
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_2'], $this->source_connection);
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_3'], $this->source_connection);

$this->artisan('db:migrate', [
'--schema-from' => $this->source_connection,
'--schema-to' => $this->target_connection,
])
->expectsConfirmation('Please confirm table list should be retrieved from target connection? (incase if source connection does not support it)', 'no')
->expectsConfirmation('Please confirm whether to truncate target table before transfer?', 'yes')
->expectsConfirmation('Please choose whether to drop target tables before migration?', 'no')
->expectsChoice('Please choose option to run migration on which connection?', $this->choice_source, $this->choices)
->assertExitCode(0)
->run();

$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_1'], $this->target_connection);
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_2'], $this->target_connection);
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_3'], $this->target_connection);
}

public function testFailed()
{
$this->expectException(InvalidArgumentException::class);
Expand Down
64 changes: 64 additions & 0 deletions tests/Unit/PostgresToMysqlTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,70 @@ public function testSame()
);
}

public function testUlidKeysAsPrimaryKey()
{
if (! $this->hasUlid()) {
$this->assertTrue(true);

return;
}

$this->artisan('migrate', [
'--database' => $this->source_connection,
'--realpath' => true,
'--path' => __DIR__ . '/../fixtures/primary_keys/2023_12_15_014834_create_ulid_primary_key.php',
])->run();

$this->fillUlidTable($this->table_ulid);

$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_1'], $this->source_connection);
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_2'], $this->source_connection);
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_3'], $this->source_connection);

$this->artisan('db:migrate', [
'--schema-from' => $this->source_connection,
'--schema-to' => $this->target_connection,
])
->expectsConfirmation('Please confirm table list should be retrieved from target connection? (incase if source connection does not support it)', 'no')
->expectsConfirmation('Please confirm whether to truncate target table before transfer?', 'yes')
->expectsConfirmation('Please choose whether to drop target tables before migration?', 'no')
->expectsChoice('Please choose option to run migration on which connection?', $this->choice_source, $this->choices)
->assertExitCode(0)
->run();

$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_1'], $this->target_connection);
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_2'], $this->target_connection);
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_3'], $this->target_connection);
}

public function testUuidKeysAsPrimaryKey()
{
if (! $this->hasUuid()) {
$this->assertTrue(true);

return;
}

$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_1'], $this->source_connection);
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_2'], $this->source_connection);
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_3'], $this->source_connection);

$this->artisan('db:migrate', [
'--schema-from' => $this->source_connection,
'--schema-to' => $this->target_connection,
])
->expectsConfirmation('Please confirm table list should be retrieved from target connection? (incase if source connection does not support it)', 'no')
->expectsConfirmation('Please confirm whether to truncate target table before transfer?', 'yes')
->expectsConfirmation('Please choose whether to drop target tables before migration?', 'no')
->expectsChoice('Please choose option to run migration on which connection?', $this->choice_source, $this->choices)
->assertExitCode(0)
->run();

$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_1'], $this->target_connection);
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_2'], $this->target_connection);
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_3'], $this->target_connection);
}

public function testFailed()
{
$this->expectException(InvalidArgumentException::class);
Expand Down
Loading

0 comments on commit f9e4bd4

Please sign in to comment.