Skip to content

Commit

Permalink
Added Hyperf\Database\Schema\Schema::getForeignKeys(). (#7059)
Browse files Browse the repository at this point in the history

Co-authored-by: 李铭昕 <[email protected]>
  • Loading branch information
zds-s and limingxinleo authored Sep 19, 2024
1 parent f953ae3 commit e6182bd
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 0 deletions.
34 changes: 34 additions & 0 deletions src/Query/Processors/PostgresProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,38 @@ public function processIndexes(array $results): array
];
}, $results);
}

/**
* Process the results of a foreign keys query.
*/
public function processForeignKeys(array $results): array
{
return array_map(function ($result) {
$result = (object) $result;

return [
'name' => $result->name,
'columns' => explode(',', $result->columns),
'foreign_schema' => $result->foreign_schema,
'foreign_table' => $result->foreign_table,
'foreign_columns' => explode(',', $result->foreign_columns),
'on_update' => match (strtolower($result->on_update)) {
'a' => 'no action',
'r' => 'restrict',
'c' => 'cascade',
'n' => 'set null',
'd' => 'set default',
default => null,
},
'on_delete' => match (strtolower($result->on_delete)) {
'a' => 'no action',
'r' => 'restrict',
'c' => 'cascade',
'n' => 'set null',
'd' => 'set default',
default => null,
},
];
}, $results);
}
}
26 changes: 26 additions & 0 deletions src/Schema/Grammars/PostgresGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,32 @@ public function typeMultiLineString(Fluent $column)
return $this->formatPostGisType('multilinestring', $column);
}

/**
* Compile the query to determine the foreign keys.
*/
public function compileForeignKeys(string $schema, string $table): string
{
return sprintf(
'select c.conname as name, '
. "string_agg(la.attname, ',' order by conseq.ord) as columns, "
. 'fn.nspname as foreign_schema, fc.relname as foreign_table, '
. "string_agg(fa.attname, ',' order by conseq.ord) as foreign_columns, "
. 'c.confupdtype as on_update, c.confdeltype as on_delete '
. 'from pg_constraint c '
. 'join pg_class tc on c.conrelid = tc.oid '
. 'join pg_namespace tn on tn.oid = tc.relnamespace '
. 'join pg_class fc on c.confrelid = fc.oid '
. 'join pg_namespace fn on fn.oid = fc.relnamespace '
. 'join lateral unnest(c.conkey) with ordinality as conseq(num, ord) on true '
. 'join pg_attribute la on la.attrelid = c.conrelid and la.attnum = conseq.num '
. 'join pg_attribute fa on fa.attrelid = c.confrelid and fa.attnum = c.confkey[conseq.ord] '
. "where c.contype = 'f' and tc.relname = %s and tn.nspname = %s "
. 'group by c.conname, fn.nspname, fc.relname, c.confupdtype, c.confdeltype',
$this->quoteString($table),
$this->quoteString($schema)
);
}

/**
* Create the column definition for a char type.
*
Expand Down
14 changes: 14 additions & 0 deletions src/Schema/PostgresBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,20 @@ public function getColumnListing($table): array
return $this->connection->getPostProcessor()->processColumnListing($results);
}

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

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

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

/**
* Get the column type listing for a given table.
*/
Expand Down
20 changes: 20 additions & 0 deletions tests/Cases/SchemaBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -217,4 +217,24 @@ public function index(): void
$this->assertTrue(collect($indexes)->contains(fn ($index) => $index['columns'] === ['id'] && $index['primary']));
$this->assertTrue(collect($indexes)->contains('name', 'articles_body_title_fulltext'));
}

public function testGetForeignKeys()
{
Schema::create('users_copy', function (Blueprint $table) {
$table->id();
});

Schema::create('posts_copy', function (Blueprint $table) {
$table->foreignId('user_id')->nullable()->constrained('users_copy')->cascadeOnUpdate()->nullOnDelete();
});

$foreignKeys = Schema::getForeignKeys('posts_copy');

$this->assertCount(1, $foreignKeys);
$this->assertTrue(collect($foreignKeys)->contains(
fn ($foreign) => $foreign['columns'] === ['user_id']
&& $foreign['foreign_table'] === 'users_copy' && $foreign['foreign_columns'] === ['id']
&& $foreign['on_update'] === 'cascade' && $foreign['on_delete'] === 'set null'
));
}
}

0 comments on commit e6182bd

Please sign in to comment.