Skip to content

Commit

Permalink
[10.x] Add hasIndex() and minor Schema enhancements (#49796)
Browse files Browse the repository at this point in the history
* add hasIndex, getIndexListing and getTableListing

* minor schema enhancements

* fix tests

* Update Builder.php

---------

Co-authored-by: Taylor Otwell <[email protected]>
  • Loading branch information
hafezdivandari and taylorotwell authored Jan 24, 2024
1 parent caee0bd commit 8fd5c35
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public function processColumns($results)
'nullable' => $result->nullable === 'YES',
'default' => $result->default,
'auto_increment' => $result->extra === 'auto_increment',
'comment' => $result->comment,
'comment' => $result->comment ?: null,
];
}, $results);
}
Expand Down
59 changes: 59 additions & 0 deletions src/Illuminate/Database/Schema/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,16 @@ public function getTables()
);
}

/**
* Get the names of the tables that belong to the database.
*
* @return array
*/
public function getTableListing()
{
return array_column($this->getTables(), 'name');
}

/**
* Get the views that belong to the database.
*
Expand Down Expand Up @@ -370,6 +380,55 @@ public function getIndexes($table)
);
}

/**
* Get the names of the indexes for a given table.
*
* @param string $table
* @return array
*/
public function getIndexListing($table)
{
return array_column($this->getIndexes($table), 'name');
}

/**
* Determine if the given table has a given index.
*
* @param string $table
* @param string|array $index
* @param string|null $type
* @return bool
*/
public function hasIndex($table, $index, $type = null)
{
$type = is_null($type) ? $type : strtolower($type);

if (is_array($index)) {
sort($index);
}

foreach ($this->getIndexes($table) as $value) {
$typeMatches = is_null($type)
|| ($type === 'primary' && $value['primary'])
|| ($type === 'unique' && $value['unique'])
|| $type === $value['type'];

if ($value['name'] === $index && $typeMatches) {
return true;
}

if (is_array($index)) {
sort($value['columns']);

if ($value['columns'] === $index && $typeMatches) {
return true;
}
}
}

return false;
}

/**
* Get the foreign keys for a given table.
*
Expand Down
2 changes: 1 addition & 1 deletion src/Illuminate/Database/Schema/ColumnDefinition.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* @method $this default(mixed $value) Specify a "default" value for the column
* @method $this first() Place the column "first" in the table (MySQL)
* @method $this from(int $startingValue) Set the starting value of an auto-incrementing field (MySQL / PostgreSQL)
* @method $this generatedAs(string|Expression $expression = null) Create a SQL compliant identity column (PostgreSQL)
* @method $this generatedAs(string|\Illuminate\Database\Query\Expression $expression = null) Create a SQL compliant identity column (PostgreSQL)
* @method $this index(string $indexName = null) Add an index
* @method $this invisible() Specify that the column should be invisible to "SELECT *" (MySQL)
* @method $this nullable(bool $value = true) Allow NULL values to be inserted into the column
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public function compileTables()
{
return 'select c.relname as name, n.nspname as schema, pg_total_relation_size(c.oid) as size, '
."obj_description(c.oid, 'pg_class') as comment from pg_class c, pg_namespace n "
."where c.relkind in ('r', 'p') and n.oid = c.relnamespace and n.nspname not in ('pg_catalog', 'information_schema')"
."where c.relkind in ('r', 'p') and n.oid = c.relnamespace and n.nspname not in ('pg_catalog', 'information_schema') "
.'order by c.relname';
}

Expand Down
3 changes: 3 additions & 0 deletions src/Illuminate/Support/Facades/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* @method static bool dropDatabaseIfExists(string $name)
* @method static bool hasTable(string $table)
* @method static bool hasView(string $view)
* @method static bool hasIndex(string $table, string|array $index, string|null $type = null)
* @method static array getTables()
* @method static array getViews()
* @method static array getTypes()
Expand All @@ -20,7 +21,9 @@
* @method static void whenTableHasColumn(string $table, string $column, \Closure $callback)
* @method static void whenTableDoesntHaveColumn(string $table, string $column, \Closure $callback)
* @method static string getColumnType(string $table, string $column, bool $fullDefinition = false)
* @method static array getTableListing()
* @method static array getColumnListing(string $table)
* @method static array getIndexListing(string $table)
* @method static array getColumns(string $table)
* @method static array getIndexes(string $table)
* @method static array getForeignKeys(string $table)
Expand Down
8 changes: 3 additions & 5 deletions tests/Database/DatabaseSQLiteSchemaGrammarTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ public function testRenameIndex()
$table->index(['name', 'email'], 'index1');
});

$indexes = array_column($schema->getIndexes('users'), 'name');
$indexes = $schema->getIndexListing('users');

$this->assertContains('index1', $indexes);
$this->assertNotContains('index2', $indexes);
Expand All @@ -173,10 +173,8 @@ public function testRenameIndex()
$table->renameIndex('index1', 'index2');
});

$indexes = $schema->getIndexes('users');

$this->assertNotContains('index1', array_column($indexes, 'name'));
$this->assertTrue(collect($indexes)->contains(
$this->assertFalse($schema->hasIndex('users', 'index1'));
$this->assertTrue(collect($schema->getIndexes('users'))->contains(
fn ($index) => $index['name'] === 'index2' && $index['columns'] === ['name', 'email']
));
}
Expand Down
10 changes: 2 additions & 8 deletions tests/Database/DatabaseSchemaBuilderIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,7 @@ public function testHasColumnAndIndexWithPrefixIndexDisabled()
$table->string('name')->index();
});

$this->assertContains(
'table1_name_index',
array_column($this->db->connection()->getSchemaBuilder()->getIndexes('table1'), 'name')
);
$this->assertTrue($this->db->connection()->getSchemaBuilder()->hasIndex('table1', 'table1_name_index'));
}

public function testHasColumnAndIndexWithPrefixIndexEnabled()
Expand All @@ -107,10 +104,7 @@ public function testHasColumnAndIndexWithPrefixIndexEnabled()
$table->string('name')->index();
});

$this->assertContains(
'example_table1_name_index',
array_column($this->db->connection()->getSchemaBuilder()->getIndexes('table1'), 'name')
);
$this->assertTrue($this->db->connection()->getSchemaBuilder()->hasIndex('table1', 'example_table1_name_index'));
}

public function testDropColumnWithTablePrefix()
Expand Down
16 changes: 15 additions & 1 deletion tests/Integration/Database/SchemaBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -193,15 +193,20 @@ public function testGetAndDropTypes()
DB::statement("create type enum_foo as enum ('new', 'open', 'closed')");
DB::statement('create type range_foo as range (subtype = float8)');
DB::statement('create domain domain_foo as text');
DB::statement('create type base_foo');
DB::statement("create function foo_in(cstring) returns base_foo language internal immutable strict parallel safe as 'int2in'");
DB::statement("create function foo_out(base_foo) returns cstring language internal immutable strict parallel safe as 'int2out'");
DB::statement('create type base_foo (input = foo_in, output = foo_out)');

$types = Schema::getTypes();

$this->assertCount(11, $types);
$this->assertCount(13, $types);
$this->assertTrue(collect($types)->contains(fn ($type) => $type['name'] === 'pseudo_foo' && $type['type'] === 'pseudo' && ! $type['implicit']));
$this->assertTrue(collect($types)->contains(fn ($type) => $type['name'] === 'comp_foo' && $type['type'] === 'composite' && ! $type['implicit']));
$this->assertTrue(collect($types)->contains(fn ($type) => $type['name'] === 'enum_foo' && $type['type'] === 'enum' && ! $type['implicit']));
$this->assertTrue(collect($types)->contains(fn ($type) => $type['name'] === 'range_foo' && $type['type'] === 'range' && ! $type['implicit']));
$this->assertTrue(collect($types)->contains(fn ($type) => $type['name'] === 'domain_foo' && $type['type'] === 'domain' && ! $type['implicit']));
$this->assertTrue(collect($types)->contains(fn ($type) => $type['name'] === 'base_foo' && $type['type'] === 'base' && ! $type['implicit']));

Schema::dropAllTypes();
$types = Schema::getTypes();
Expand Down Expand Up @@ -256,6 +261,10 @@ public function testGetIndexes()
&& ! $indexes[0]['unique']
&& ! $indexes[0]['primary']
);
$this->assertTrue(Schema::hasIndex('foo', 'my_index'));
$this->assertTrue(Schema::hasIndex('foo', ['bar']));
$this->assertFalse(Schema::hasIndex('foo', 'my_index', 'primary'));
$this->assertFalse(Schema::hasIndex('foo', ['bar'], 'unique'));
}

public function testGetUniqueIndexes()
Expand All @@ -277,6 +286,11 @@ public function testGetUniqueIndexes()
$this->assertTrue(collect($indexes)->contains(
fn ($index) => $index['name'] === 'foo_baz_bar_unique' && $index['columns'] === ['baz', 'bar'] && $index['unique']
));
$this->assertTrue(Schema::hasIndex('foo', 'foo_baz_bar_unique'));
$this->assertTrue(Schema::hasIndex('foo', 'foo_baz_bar_unique', 'unique'));
$this->assertTrue(Schema::hasIndex('foo', ['bar', 'baz']));
$this->assertTrue(Schema::hasIndex('foo', ['bar', 'baz'], 'unique'));
$this->assertFalse(Schema::hasIndex('foo', ['bar', 'baz'], 'primary'));
}

public function testGetIndexesWithCompositeKeys()
Expand Down

0 comments on commit 8fd5c35

Please sign in to comment.