Skip to content

Commit f9e4bd4

Browse files
Merge pull request #41 from TheDragonCode/3.x
Fixed bug with transferring UUID and ULID as primary key
2 parents a52471c + 379476b commit f9e4bd4

File tree

12 files changed

+363
-12
lines changed

12 files changed

+363
-12
lines changed

.github/workflows/phpunit.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,14 @@ jobs:
99
strategy:
1010
fail-fast: true
1111
matrix:
12-
php: [ "8.0", "8.1", "8.2" ]
12+
php: [ "8.0", "8.1", "8.2", "8.3" ]
1313
laravel: [ "8.0", "9.0", "10.0" ]
1414
psql: [ "9", "10", "11", "12", "13", "14", "15" ]
1515
exclude:
16+
- laravel: "8.0"
17+
php: "8.3"
18+
- laravel: "9.0"
19+
php: "8.3"
1620
- laravel: "10.0"
1721
php: "8.0"
1822

src/Console/Migrate.php

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -132,16 +132,6 @@ protected function migrateTable(string $table, string $column): void
132132
Log::info('Transferring data from: ' . $table);
133133

134134
$this->builder($this->source(), $table)
135-
->when(
136-
$this->isSkippable($table, $column),
137-
function ($query) use ($table, $column) {
138-
$lastRecord = $this->builder($this->target(), $table)->max($column) ?: 0;
139-
140-
Log::info('last record: ' . $lastRecord);
141-
142-
return $query->where($column, '>', $lastRecord);
143-
}
144-
)
145135
->orderBy($column)
146136
->chunk(1000, function (Collection $items) use ($table) {
147137
$items = Arr::resolve($items);
@@ -159,7 +149,9 @@ protected function isSkippable(string $table, string $column): bool
159149

160150
protected function isNumericColumn(string $table, string $column): bool
161151
{
162-
return $this->getPrimaryKeyType($this->source(), $table, $column) !== 'string';
152+
$type = $this->getPrimaryKeyType($this->source(), $table, $column);
153+
154+
return ! in_array($type, ['string', 'char', 'ulid', 'uuid'], true);
163155
}
164156

165157
protected function tables(): array

tests/Concerns/Database.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
/** @mixin \Tests\Concerns\Connections */
1414
trait Database
1515
{
16+
use HasUuidAndUlid;
1617
use Seeders;
1718

1819
protected $connectors = [
@@ -27,6 +28,10 @@ trait Database
2728

2829
protected $table_baz = 'baz';
2930

31+
protected $table_ulid = 'ulid_table';
32+
33+
protected $table_uuid = 'uuid_table';
34+
3035
protected $choice_target = 'target';
3136

3237
protected $choice_source = 'source';

tests/Concerns/HasUuidAndUlid.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Tests\Concerns;
6+
7+
use Illuminate\Database\Schema\Blueprint;
8+
use Illuminate\Support\Str;
9+
10+
trait HasUuidAndUlid
11+
{
12+
protected function hasUuid()
13+
{
14+
return method_exists(Blueprint::class, 'uuid')
15+
&& method_exists(Str::class, 'uuid');
16+
}
17+
18+
protected function hasUlid()
19+
{
20+
return method_exists(Blueprint::class, 'ulid')
21+
&& method_exists(Str::class, 'ulid');
22+
}
23+
}

tests/Concerns/Migration.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
abstract class Migration extends BaseMigration
1010
{
11+
use HasUuidAndUlid;
12+
1113
protected $table;
1214

1315
public function up()

tests/Concerns/Seeders.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Tests\Concerns;
44

55
use Illuminate\Support\Facades\DB;
6+
use Illuminate\Support\Str;
67

78
trait Seeders
89
{
@@ -11,6 +12,14 @@ protected function fillTables(): void
1112
$this->fillTable($this->table_foo);
1213
$this->fillTable($this->table_bar);
1314
$this->fillTable($this->table_baz);
15+
16+
if ($this->hasUlid()) {
17+
$this->fillUlidTable($this->table_ulid);
18+
}
19+
20+
if ($this->hasUuid()) {
21+
$this->fillUuidTable($this->table_uuid);
22+
}
1423
}
1524

1625
protected function fillTable(string $table): void
@@ -21,4 +30,22 @@ protected function fillTable(string $table): void
2130
['value' => $table . '_3'],
2231
]);
2332
}
33+
34+
protected function fillUlidTable(string $table): void
35+
{
36+
DB::connection($this->source_connection)->table($table)->insert([
37+
['value' => $table . '_1', 'ulid' => (string) Str::ulid()],
38+
['value' => $table . '_2', 'ulid' => (string) Str::ulid()],
39+
['value' => $table . '_3', 'ulid' => (string) Str::ulid()],
40+
]);
41+
}
42+
43+
protected function fillUuidTable(string $table): void
44+
{
45+
DB::connection($this->source_connection)->table($table)->insert([
46+
['value' => $table . '_1', 'uuid' => Str::uuid()->toString()],
47+
['value' => $table . '_2', 'uuid' => Str::uuid()->toString()],
48+
['value' => $table . '_3', 'uuid' => Str::uuid()->toString()],
49+
]);
50+
}
2451
}

tests/Unit/MysqlToMysqlTest.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,70 @@ public function testSame()
230230
);
231231
}
232232

233+
public function testUlidKeysAsPrimaryKey()
234+
{
235+
if (! $this->hasUlid()) {
236+
$this->assertTrue(true);
237+
238+
return;
239+
}
240+
241+
$this->artisan('migrate', [
242+
'--database' => $this->source_connection,
243+
'--realpath' => true,
244+
'--path' => __DIR__ . '/../fixtures/primary_keys/2023_12_15_014834_create_ulid_primary_key.php',
245+
])->run();
246+
247+
$this->fillUlidTable($this->table_ulid);
248+
249+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_1'], $this->source_connection);
250+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_2'], $this->source_connection);
251+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_3'], $this->source_connection);
252+
253+
$this->artisan('db:migrate', [
254+
'--schema-from' => $this->source_connection,
255+
'--schema-to' => $this->target_connection,
256+
])
257+
->expectsConfirmation('Please confirm table list should be retrieved from target connection? (incase if source connection does not support it)', 'no')
258+
->expectsConfirmation('Please confirm whether to truncate target table before transfer?', 'yes')
259+
->expectsConfirmation('Please choose whether to drop target tables before migration?', 'no')
260+
->expectsChoice('Please choose option to run migration on which connection?', $this->choice_source, $this->choices)
261+
->assertExitCode(0)
262+
->run();
263+
264+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_1'], $this->target_connection);
265+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_2'], $this->target_connection);
266+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_3'], $this->target_connection);
267+
}
268+
269+
public function testUuidKeysAsPrimaryKey()
270+
{
271+
if (! $this->hasUuid()) {
272+
$this->assertTrue(true);
273+
274+
return;
275+
}
276+
277+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_1'], $this->source_connection);
278+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_2'], $this->source_connection);
279+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_3'], $this->source_connection);
280+
281+
$this->artisan('db:migrate', [
282+
'--schema-from' => $this->source_connection,
283+
'--schema-to' => $this->target_connection,
284+
])
285+
->expectsConfirmation('Please confirm table list should be retrieved from target connection? (incase if source connection does not support it)', 'no')
286+
->expectsConfirmation('Please confirm whether to truncate target table before transfer?', 'yes')
287+
->expectsConfirmation('Please choose whether to drop target tables before migration?', 'no')
288+
->expectsChoice('Please choose option to run migration on which connection?', $this->choice_source, $this->choices)
289+
->assertExitCode(0)
290+
->run();
291+
292+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_1'], $this->target_connection);
293+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_2'], $this->target_connection);
294+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_3'], $this->target_connection);
295+
}
296+
233297
public function testFailed()
234298
{
235299
$this->expectException(InvalidArgumentException::class);

tests/Unit/MysqlToPostgresTest.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,70 @@ public function testSame()
230230
);
231231
}
232232

233+
public function testUlidKeysAsPrimaryKey()
234+
{
235+
if (! $this->hasUlid()) {
236+
$this->assertTrue(true);
237+
238+
return;
239+
}
240+
241+
$this->artisan('migrate', [
242+
'--database' => $this->source_connection,
243+
'--realpath' => true,
244+
'--path' => __DIR__ . '/../fixtures/primary_keys/2023_12_15_014834_create_ulid_primary_key.php',
245+
])->run();
246+
247+
$this->fillUlidTable($this->table_ulid);
248+
249+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_1'], $this->source_connection);
250+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_2'], $this->source_connection);
251+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_3'], $this->source_connection);
252+
253+
$this->artisan('db:migrate', [
254+
'--schema-from' => $this->source_connection,
255+
'--schema-to' => $this->target_connection,
256+
])
257+
->expectsConfirmation('Please confirm table list should be retrieved from target connection? (incase if source connection does not support it)', 'no')
258+
->expectsConfirmation('Please confirm whether to truncate target table before transfer?', 'yes')
259+
->expectsConfirmation('Please choose whether to drop target tables before migration?', 'no')
260+
->expectsChoice('Please choose option to run migration on which connection?', $this->choice_source, $this->choices)
261+
->assertExitCode(0)
262+
->run();
263+
264+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_1'], $this->target_connection);
265+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_2'], $this->target_connection);
266+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_3'], $this->target_connection);
267+
}
268+
269+
public function testUuidKeysAsPrimaryKey()
270+
{
271+
if (! $this->hasUuid()) {
272+
$this->assertTrue(true);
273+
274+
return;
275+
}
276+
277+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_1'], $this->source_connection);
278+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_2'], $this->source_connection);
279+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_3'], $this->source_connection);
280+
281+
$this->artisan('db:migrate', [
282+
'--schema-from' => $this->source_connection,
283+
'--schema-to' => $this->target_connection,
284+
])
285+
->expectsConfirmation('Please confirm table list should be retrieved from target connection? (incase if source connection does not support it)', 'no')
286+
->expectsConfirmation('Please confirm whether to truncate target table before transfer?', 'yes')
287+
->expectsConfirmation('Please choose whether to drop target tables before migration?', 'no')
288+
->expectsChoice('Please choose option to run migration on which connection?', $this->choice_source, $this->choices)
289+
->assertExitCode(0)
290+
->run();
291+
292+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_1'], $this->target_connection);
293+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_2'], $this->target_connection);
294+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_3'], $this->target_connection);
295+
}
296+
233297
public function testFailed()
234298
{
235299
$this->expectException(InvalidArgumentException::class);

tests/Unit/PostgresToMysqlTest.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,70 @@ public function testSame()
230230
);
231231
}
232232

233+
public function testUlidKeysAsPrimaryKey()
234+
{
235+
if (! $this->hasUlid()) {
236+
$this->assertTrue(true);
237+
238+
return;
239+
}
240+
241+
$this->artisan('migrate', [
242+
'--database' => $this->source_connection,
243+
'--realpath' => true,
244+
'--path' => __DIR__ . '/../fixtures/primary_keys/2023_12_15_014834_create_ulid_primary_key.php',
245+
])->run();
246+
247+
$this->fillUlidTable($this->table_ulid);
248+
249+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_1'], $this->source_connection);
250+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_2'], $this->source_connection);
251+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_3'], $this->source_connection);
252+
253+
$this->artisan('db:migrate', [
254+
'--schema-from' => $this->source_connection,
255+
'--schema-to' => $this->target_connection,
256+
])
257+
->expectsConfirmation('Please confirm table list should be retrieved from target connection? (incase if source connection does not support it)', 'no')
258+
->expectsConfirmation('Please confirm whether to truncate target table before transfer?', 'yes')
259+
->expectsConfirmation('Please choose whether to drop target tables before migration?', 'no')
260+
->expectsChoice('Please choose option to run migration on which connection?', $this->choice_source, $this->choices)
261+
->assertExitCode(0)
262+
->run();
263+
264+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_1'], $this->target_connection);
265+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_2'], $this->target_connection);
266+
$this->assertDatabaseHas($this->table_ulid, ['value' => $this->table_ulid . '_3'], $this->target_connection);
267+
}
268+
269+
public function testUuidKeysAsPrimaryKey()
270+
{
271+
if (! $this->hasUuid()) {
272+
$this->assertTrue(true);
273+
274+
return;
275+
}
276+
277+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_1'], $this->source_connection);
278+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_2'], $this->source_connection);
279+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_3'], $this->source_connection);
280+
281+
$this->artisan('db:migrate', [
282+
'--schema-from' => $this->source_connection,
283+
'--schema-to' => $this->target_connection,
284+
])
285+
->expectsConfirmation('Please confirm table list should be retrieved from target connection? (incase if source connection does not support it)', 'no')
286+
->expectsConfirmation('Please confirm whether to truncate target table before transfer?', 'yes')
287+
->expectsConfirmation('Please choose whether to drop target tables before migration?', 'no')
288+
->expectsChoice('Please choose option to run migration on which connection?', $this->choice_source, $this->choices)
289+
->assertExitCode(0)
290+
->run();
291+
292+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_1'], $this->target_connection);
293+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_2'], $this->target_connection);
294+
$this->assertDatabaseHas($this->table_uuid, ['value' => $this->table_uuid . '_3'], $this->target_connection);
295+
}
296+
233297
public function testFailed()
234298
{
235299
$this->expectException(InvalidArgumentException::class);

0 commit comments

Comments
 (0)