From 42c9d3fc8e6b2f035fdf62f772b5748612b21fbb Mon Sep 17 00:00:00 2001 From: theparadoxShin Date: Wed, 16 Jul 2025 07:08:51 -0400 Subject: [PATCH 1/3] Ensure foreign key columns create an index by default and add tests for constrained method behavior --- .../Schema/ForeignIdColumnDefinition.php | 6 + .../DatabaseForeignIdColumnDefinitionTest.php | 105 ++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 tests/Database/DatabaseForeignIdColumnDefinitionTest.php diff --git a/src/Illuminate/Database/Schema/ForeignIdColumnDefinition.php b/src/Illuminate/Database/Schema/ForeignIdColumnDefinition.php index c7f66d19bb96..33a6716ed2ed 100644 --- a/src/Illuminate/Database/Schema/ForeignIdColumnDefinition.php +++ b/src/Illuminate/Database/Schema/ForeignIdColumnDefinition.php @@ -39,6 +39,12 @@ public function constrained($table = null, $column = null, $indexName = null) $table ??= $this->table; $column ??= $this->referencesModelColumn ?? 'id'; + // Ensure an index is created for the foreign key column + // This is important for query performance, especially on PostgreSQL + if (! isset($this->index)) { + $this->index = true; + } + return $this->references($column, $indexName)->on($table ?? (new Stringable($this->name))->beforeLast('_'.$column)->plural()); } diff --git a/tests/Database/DatabaseForeignIdColumnDefinitionTest.php b/tests/Database/DatabaseForeignIdColumnDefinitionTest.php new file mode 100644 index 000000000000..5539778a1148 --- /dev/null +++ b/tests/Database/DatabaseForeignIdColumnDefinitionTest.php @@ -0,0 +1,105 @@ +shouldReceive('getSchemaGrammar')->andReturn(new PostgresGrammar($connection)); + $connection->shouldReceive('getTablePrefix')->andReturn(''); + $connection->shouldReceive('getConfig')->with('prefix_indexes')->andReturn(false); + + $blueprint = new Blueprint($connection, 'posts'); + $column = $blueprint->foreignId('user_id'); + $this->assertObjectNotHasProperty('index', $column); + $column->constrained(); + $this->assertTrue($column->index); + } + + public function testConstrainedPreservesExplicitIndexFalse() + { + $connection = m::mock(Connection::class); + $connection->shouldReceive('getSchemaGrammar')->andReturn(new PostgresGrammar($connection)); + $connection->shouldReceive('getTablePrefix')->andReturn(''); + $connection->shouldReceive('getConfig')->with('prefix_indexes')->andReturn(false); + + $blueprint = new Blueprint($connection, 'posts'); + $column = $blueprint->foreignId('user_id'); + $column->index = false; + $column->constrained(); + $this->assertFalse($column->index); + } + + public function testAddFluentIndexesCreatesIndexForForeignId() + { + $connection = m::mock(Connection::class); + $grammar = m::mock(PostgresGrammar::class); + $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); + $connection->shouldReceive('getTablePrefix')->andReturn(''); + $connection->shouldReceive('getConfig')->with('prefix_indexes')->andReturn(false); + $grammar->shouldReceive('getFluentCommands')->andReturn([]); + $grammar->shouldReceive('compileAdd')->andReturn(''); + $grammar->shouldReceive('compileForeign')->andReturn(''); + $grammar->shouldReceive('compileIndex')->andReturn(''); + + $blueprint = new Blueprint($connection, 'posts'); + $blueprint->foreignId('user_id')->constrained(); + $blueprint->toSql(); + $commands = $blueprint->getCommands(); + $indexCommands = array_filter($commands, function ($command) { + return $command->name === 'index' && in_array('user_id', (array) $command->columns); + }); + + $this->assertNotEmpty($indexCommands, 'An index command should be created for the foreign key column'); + } + + public function testConstrainedWithCompositeUniqueStillCreatesIndex() + { + $connection = m::mock(Connection::class); + $grammar = m::mock(PostgresGrammar::class); + $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); + $connection->shouldReceive('getTablePrefix')->andReturn(''); + $connection->shouldReceive('getConfig')->with('prefix_indexes')->andReturn(false); + $grammar->shouldReceive('getFluentCommands')->andReturn([]); + $grammar->shouldReceive('compileAdd')->andReturn(''); + $grammar->shouldReceive('compileForeign')->andReturn(''); + $grammar->shouldReceive('compileUnique')->andReturn(''); + $grammar->shouldReceive('compileIndex')->andReturn(''); + + $blueprint = new Blueprint($connection, 'books'); + $blueprint->id(); + $blueprint->foreignId('author_id')->constrained(); + $blueprint->foreignId('category_id')->constrained(); + $blueprint->string('title'); + $blueprint->unique(['author_id', 'title']); + $blueprint->toSql(); + $commands = $blueprint->getCommands(); + $authorIndexCommands = array_filter($commands, function ($command) { + return $command->name === 'index' && + is_array($command->columns) && + count($command->columns) === 1 && + $command->columns[0] === 'author_id'; + }); + $categoryIndexCommands = array_filter($commands, function ($command) { + return $command->name === 'index' && + is_array($command->columns) && + count($command->columns) === 1 && + $command->columns[0] === 'category_id'; + }); + + $this->assertNotEmpty($authorIndexCommands, 'Index should be created for author_id despite composite unique'); + $this->assertNotEmpty($categoryIndexCommands, 'Index should be created for category_id'); + } +} From b71b5015e0a77f774159aeb0479a0dc05570f9ea Mon Sep 17 00:00:00 2001 From: theparadoxShin Date: Wed, 16 Jul 2025 07:22:44 -0400 Subject: [PATCH 2/3] Fix namespace declaration in DatabaseForeignIdColumnDefinitionTest --- tests/Database/DatabaseForeignIdColumnDefinitionTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Database/DatabaseForeignIdColumnDefinitionTest.php b/tests/Database/DatabaseForeignIdColumnDefinitionTest.php index 5539778a1148..e9fe9b1a4c9c 100644 --- a/tests/Database/DatabaseForeignIdColumnDefinitionTest.php +++ b/tests/Database/DatabaseForeignIdColumnDefinitionTest.php @@ -1,5 +1,5 @@ Date: Wed, 16 Jul 2025 07:32:41 -0400 Subject: [PATCH 3/3] Add missing newline at the beginning of DatabaseForeignIdColumnDefinitionTest.php for styleci/pr passing test --- tests/Database/DatabaseForeignIdColumnDefinitionTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Database/DatabaseForeignIdColumnDefinitionTest.php b/tests/Database/DatabaseForeignIdColumnDefinitionTest.php index e9fe9b1a4c9c..54b57cada427 100644 --- a/tests/Database/DatabaseForeignIdColumnDefinitionTest.php +++ b/tests/Database/DatabaseForeignIdColumnDefinitionTest.php @@ -1,4 +1,5 @@