Skip to content

Commit

Permalink
Merge pull request #68: deduplicate indexes if FK outer key is PK
Browse files Browse the repository at this point in the history
  • Loading branch information
roxblnfk authored Nov 24, 2023
2 parents 24284c5 + 490efa4 commit 7f2f426
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 5 deletions.
6 changes: 4 additions & 2 deletions src/Generator/ForeignKeys.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ public function run(Registry $registry): Registry
foreach ($registry as $entity) {
foreach ($entity->getForeignKeys() as $fk) {
$target = $registry->getEntity($fk->getTarget());
$targetSchema = $registry->getTableSchema($target);

if (!$registry->getTableSchema($target)->hasIndex($fk->getOuterColumns())) {
$registry->getTableSchema($target)->index($fk->getOuterColumns())->unique();
$pkExists = \array_diff($fk->getOuterColumns(), $targetSchema->getPrimaryKeys()) === [];
if (!$pkExists && !$targetSchema->hasIndex($fk->getOuterColumns())) {
$targetSchema->index($fk->getOuterColumns())->unique();
}

$registry->getTableSchema($entity)
Expand Down
12 changes: 12 additions & 0 deletions tests/Schema/Fixtures/Author.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ public static function defineWithoutPK(): Entity
return $entity;
}

public static function defineWithUser(): Entity
{
$entity = self::define();

$entity->getFields()->set(
'p_user_id',
(new Field())->setType('int(11)')->setColumn('user_id')
);

return $entity;
}

public static function defineCompositePK(): Entity
{
$entity = self::define();
Expand Down
64 changes: 61 additions & 3 deletions tests/Schema/Generator/ForeignKeysTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Cycle\Schema\Tests\Generator;

use Cycle\Schema\Compiler;
use Cycle\Schema\Definition\Field;
use Cycle\Schema\Definition\ForeignKey;
use Cycle\Schema\Generator\ForeignKeys;
use Cycle\Schema\Generator\RenderTables;
Expand All @@ -18,7 +19,7 @@ abstract class ForeignKeysTest extends BaseTest
{
public function testTableSchemaShouldBeModified(): void
{
$author = Author::define();
$author = Author::defineWithUser();
$user = User::define();
$plain = Plain::define();

Expand All @@ -31,7 +32,7 @@ public function testTableSchemaShouldBeModified(): void

$fk = new ForeignKey();
$fk->setTarget('user');
$fk->setInnerColumns(['id']);
$fk->setInnerColumns(['user_id']);
$fk->setOuterColumns(['id']);
$fk->setAction('CASCADE');
$fk->createIndex(true);
Expand All @@ -46,10 +47,67 @@ public function testTableSchemaShouldBeModified(): void

$this->assertStringContainsString('authors', $expectedFk->getTable());
$this->assertStringContainsString('users', $expectedFk->getForeignTable());
$this->assertSame(['id'], $expectedFk->getColumns());
$this->assertSame(['user_id'], $expectedFk->getColumns());
$this->assertSame(['id'], $expectedFk->getForeignKeys());
$this->assertSame('CASCADE', $expectedFk->getDeleteRule());
$this->assertSame('CASCADE', $expectedFk->getUpdateRule());
$this->assertTrue($expectedFk->hasIndex());
}

public function testCreateIndex(): void
{
$author = Author::defineWithUser();
$user = User::define();
$user->getFields()->set('u_other_id', (new Field())->setType('integer')->setColumn('other_id'));
$plain = Plain::define();

$registry = new Registry($this->dbal);
$registry->register($author)->linkTable($author, 'default', 'authors');
$registry->register($user)->linkTable($user, 'default', 'users');
$registry->register($plain)->linkTable($plain, 'default', 'plain');

$this->assertSame([], $registry->getTableSchema($author)->getForeignKeys());

$fk = new ForeignKey();
$fk->setTarget('user');
$fk->setInnerColumns(['user_id']);
$fk->setOuterColumns(['other_id']);
$fk->setAction('CASCADE');
$fk->createIndex(true);

$author->getForeignKeys()->set($fk);

$compiler = new Compiler();
$compiler->compile($registry, [new RenderTables(), new ForeignKeys()]);

$this->assertCount(1, $registry->getTableSchema($user)->getIndexes());
}

public function testShouldNotCreateIndexOnPk(): void
{
$author = Author::defineWithUser();
$user = User::define();
$plain = Plain::define();

$registry = new Registry($this->dbal);
$registry->register($author)->linkTable($author, 'default', 'authors');
$registry->register($user)->linkTable($user, 'default', 'users');
$registry->register($plain)->linkTable($plain, 'default', 'plain');

$this->assertSame([], $registry->getTableSchema($author)->getForeignKeys());

$fk = new ForeignKey();
$fk->setTarget('user');
$fk->setInnerColumns(['user_id']);
$fk->setOuterColumns(['id']);
$fk->setAction('CASCADE');
$fk->createIndex(true);

$author->getForeignKeys()->set($fk);

$compiler = new Compiler();
$compiler->compile($registry, [new RenderTables(), new ForeignKeys()]);

$this->assertEmpty($registry->getTableSchema($user)->getIndexes());
}
}

0 comments on commit 7f2f426

Please sign in to comment.