Skip to content

Commit

Permalink
Added methods getIndexes hasIndex and getIndexListing into `Hyp…
Browse files Browse the repository at this point in the history
…erf\Database\Schema\Builder`. (#6883)
  • Loading branch information
zds-s authored Jun 18, 2024
1 parent 8e2242c commit c4515bd
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 0 deletions.
18 changes: 18 additions & 0 deletions src/Query/Processors/PostgresProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,22 @@ public function processListing(array $results): array
return (array) $result;
}, $results);
}

/**
* Process the results of an indexes query.
*/
public function processIndexes(array $results): array
{
return array_map(function ($result) {
$result = (object) $result;

return [
'name' => strtolower($result->name),
'columns' => explode(',', $result->columns),
'type' => strtolower($result->type),
'unique' => (bool) $result->unique,
'primary' => (bool) $result->primary,
];
}, $results);
}
}
22 changes: 22 additions & 0 deletions src/Schema/Grammars/PostgresGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,28 @@ public function compileColumns(): string
return 'select table_schema,table_name,column_name,ordinal_position,column_default,is_nullable,data_type from information_schema.columns where table_schema = ? order by ORDINAL_POSITION';
}

/**
* Compile the query to determine the indexes.
*/
public function compileIndexes(string $schema, string $table): string
{
return sprintf(
"select ic.relname as name, string_agg(a.attname, ',' order by indseq.ord) as columns, "
. 'am.amname as "type", i.indisunique as "unique", i.indisprimary as "primary" '
. 'from pg_index i '
. 'join pg_class tc on tc.oid = i.indrelid '
. 'join pg_namespace tn on tn.oid = tc.relnamespace '
. 'join pg_class ic on ic.oid = i.indexrelid '
. 'join pg_am am on am.oid = ic.relam '
. 'join lateral unnest(i.indkey) with ordinality as indseq(num, ord) on true '
. 'left join pg_attribute a on a.attrelid = i.indrelid and a.attnum = indseq.num '
. 'where tc.relname = %s and tn.nspname = %s '
. 'group by ic.relname, am.amname, i.indisunique, i.indisprimary',
$this->quoteString($table),
$this->quoteString($schema)
);
}

/**
* Compile a create table command.
*/
Expand Down
14 changes: 14 additions & 0 deletions src/Schema/PostgresBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,20 @@ public function getColumnTypeListing($table)
return $processor->processListing($results);
}

/**
* Get the indexes for a given table.
*/
public function getIndexes(string $table): array
{
[$schema, $table] = $this->parseSchemaAndTable($table);

$table = $this->connection->getTablePrefix() . $table;

return $this->connection->getPostProcessor()->processIndexes(
$this->connection->selectFromWriteConnection($this->grammar->compileIndexes($schema, $table))
);
}

/**
* Parse the table name and extract the schema and table.
*
Expand Down
99 changes: 99 additions & 0 deletions tests/Cases/SchemaBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
use PHPUnit\Framework\Attributes\RequiresPhpExtension;
use PHPUnit\Framework\TestCase;

use function Hyperf\Collection\collect;

/**
* @internal
* @coversNothing
Expand Down Expand Up @@ -101,4 +103,101 @@ public function testColumn(): void
$this->assertSame(['id', 'name', 'ranking'], array_column($columns, 'column_name'));
Schema::drop('column_1');
}

public function index(): void
{
Schema::create('users', function (Blueprint $table) {
$table->string('name');
$table->string('email');
});

Schema::table('users', function (Blueprint $table) {
$table->index(['name', 'email'], 'index1');
});

$indexes = Schema::getIndexListing('users');

$this->assertContains('index1', $indexes);
$this->assertNotContains('index2', $indexes);

Schema::table('users', function (Blueprint $table) {
$table->renameIndex('index1', 'index2');
});

$this->assertFalse(Schema::hasIndex('users', 'index1'));
$this->assertTrue(collect(Schema::getIndexes('users'))->contains(
fn ($index) => $index['name'] === 'index2' && $index['columns'] === ['name', 'email']
));
Schema::create('foo', function (Blueprint $table) {
$table->id();
$table->string('bar');
$table->integer('baz');

$table->unique(['baz', 'bar']);
});

$indexes = Schema::getIndexes('foo');

$this->assertCount(2, $indexes);
$this->assertTrue(collect($indexes)->contains(
fn ($index) => $index['columns'] === ['id'] && $index['primary']
));
$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', ['baz', 'bar']));
$this->assertTrue(Schema::hasIndex('foo', ['baz', 'bar'], 'unique'));
$this->assertFalse(Schema::hasIndex('foo', ['baz', 'bar'], 'primary'));
Schema::drop('foo');
Schema::create('foo', function (Blueprint $table) {
$table->string('bar')->index('my_index');
});

$indexes = Schema::getIndexes('foo');

$this->assertCount(1, $indexes);
$this->assertTrue(
$indexes[0]['name'] === 'my_index'
&& $indexes[0]['columns'] === ['bar']
&& ! $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'));
Schema::drop('foo');
Schema::create('foo', function (Blueprint $table) {
$table->unsignedBigInteger('key');
$table->string('bar')->unique();
$table->integer('baz');

$table->primary(['baz', 'key']);
});

$indexes = Schema::getIndexes('foo');

$this->assertCount(2, $indexes);
$this->assertTrue(collect($indexes)->contains(
fn ($index) => $index['columns'] === ['baz', 'key'] && $index['primary']
));
$this->assertTrue(collect($indexes)->contains(
fn ($index) => $index['name'] === 'foo_bar_unique' && $index['columns'] === ['bar'] && $index['unique']
));
Schema::create('articles', function (Blueprint $table) {
$table->id();
$table->string('title', 200);
$table->text('body');

$table->fulltext(['body', 'title']);
});

$indexes = Schema::getIndexes('articles');

$this->assertCount(2, $indexes);
$this->assertTrue(collect($indexes)->contains(fn ($index) => $index['columns'] === ['id'] && $index['primary']));
$this->assertTrue(collect($indexes)->contains('name', 'articles_body_title_fulltext'));
}
}

0 comments on commit c4515bd

Please sign in to comment.