Skip to content

Commit

Permalink
[10.x] Get foreign keys of a table (#49264)
Browse files Browse the repository at this point in the history
* get foreign keys

* fix tests

* fix tests

* fix tests

* fix tests
  • Loading branch information
hafezdivandari authored Dec 11, 2023
1 parent 2039e83 commit 7907bfb
Show file tree
Hide file tree
Showing 14 changed files with 316 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/Illuminate/Database/Query/Processors/MySqlProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,27 @@ public function processIndexes($results)
];
}, $results);
}

/**
* Process the results of a foreign keys query.
*
* @param array $results
* @return array
*/
public function processForeignKeys($results)
{
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' => strtolower($result->on_update),
'on_delete' => strtolower($result->on_delete),
];
}, $results);
}
}
37 changes: 37 additions & 0 deletions src/Illuminate/Database/Query/Processors/PostgresProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,41 @@ public function processIndexes($results)
];
}, $results);
}

/**
* Process the results of a foreign keys query.
*
* @param array $results
* @return array
*/
public function processForeignKeys($results)
{
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);
}
}
11 changes: 11 additions & 0 deletions src/Illuminate/Database/Query/Processors/Processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ public function processIndexes($results)
return $results;
}

/**
* Process the results of a foreign keys query.
*
* @param array $results
* @return array
*/
public function processForeignKeys($results)
{
return $results;
}

/**
* Process the results of a column listing query.
*
Expand Down
23 changes: 23 additions & 0 deletions src/Illuminate/Database/Query/Processors/SQLiteProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,27 @@ public function processIndexes($results)

return $indexes;
}

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

return [
'name' => null,
'columns' => explode(',', $result->columns),
'foreign_schema' => null,
'foreign_table' => $result->foreign_table,
'foreign_columns' => explode(',', $result->foreign_columns),
'on_update' => strtolower($result->on_update),
'on_delete' => strtolower($result->on_delete),
];
}, $results);
}
}
23 changes: 23 additions & 0 deletions src/Illuminate/Database/Query/Processors/SqlServerProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,27 @@ public function processIndexes($results)
];
}, $results);
}

/**
* Process the results of a foreign keys query.
*
* @param array $results
* @return array
*/
public function processForeignKeys($results)
{
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' => strtolower(str_replace('_', ' ', $result->on_update)),
'on_delete' => strtolower(str_replace('_', ' ', $result->on_delete)),
];
}, $results);
}
}
15 changes: 15 additions & 0 deletions src/Illuminate/Database/Schema/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,21 @@ public function getIndexes($table)
);
}

/**
* Get the foreign keys for a given table.
*
* @param string $table
* @return array
*/
public function getForeignKeys($table)
{
$table = $this->connection->getTablePrefix().$table;

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

/**
* Modify a table on the schema.
*
Expand Down
26 changes: 26 additions & 0 deletions src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,32 @@ public function compileIndexes($database, $table)
);
}

/**
* Compile the query to determine the foreign keys.
*
* @param string $database
* @param string $table
* @return string
*/
public function compileForeignKeys($database, $table)
{
return sprintf(
'select kc.constraint_name as `name`, '
.'group_concat(kc.column_name order by kc.ordinal_position) as `columns`, '
.'kc.referenced_table_schema as `foreign_schema`, '
.'kc.referenced_table_name as `foreign_table`, '
.'group_concat(kc.referenced_column_name order by kc.ordinal_position) as `foreign_columns`, '
.'rc.update_rule as `on_update`, '
.'rc.delete_rule as `on_delete` '
.'from information_schema.key_column_usage kc join information_schema.referential_constraints rc '
.'on kc.constraint_schema = rc.constraint_schema and kc.constraint_name = rc.constraint_name '
.'where kc.table_schema = %s and kc.table_name = %s and kc.referenced_table_name is not null '
.'group by kc.constraint_name, kc.referenced_table_schema, kc.referenced_table_name, rc.update_rule, rc.delete_rule',
$this->quoteString($database),
$this->quoteString($table)
);
}

/**
* Compile a create table command.
*
Expand Down
30 changes: 30 additions & 0 deletions src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,36 @@ public function compileIndexes($schema, $table)
);
}

/**
* Compile the query to determine the foreign keys.
*
* @param string $schema
* @param string $table
* @return string
*/
public function compileForeignKeys($schema, $table)
{
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)
);
}

/**
* Compile a create table command.
*
Expand Down
17 changes: 17 additions & 0 deletions src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,23 @@ public function compileIndexes($table)
);
}

/**
* Compile the query to determine the foreign keys.
*
* @param string $table
* @return string
*/
public function compileForeignKeys($table)
{
return sprintf(
'select group_concat("from") as columns, "table" as foreign_table, '
.'group_concat("to") as foreign_columns, on_update, on_delete '
.'from (select * from pragma_foreign_key_list(%s) order by id desc, seq) '
.'group by id, "table", on_update, on_delete',
$this->wrap(str_replace('.', '__', $table))
);
}

/**
* Compile a create table command.
*
Expand Down
29 changes: 29 additions & 0 deletions src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,35 @@ public function compileIndexes($table)
);
}

/**
* Compile the query to determine the foreign keys.
*
* @param string $table
* @return string
*/
public function compileForeignKeys($table)
{
return sprintf(
'select fk.name as name, '
."string_agg(lc.name, ',') within group (order by fkc.constraint_column_id) as columns, "
.'fs.name as foreign_schema, ft.name as foreign_table, '
."string_agg(fc.name, ',') within group (order by fkc.constraint_column_id) as foreign_columns, "
.'fk.update_referential_action_desc as on_update, '
.'fk.delete_referential_action_desc as on_delete '
.'from sys.foreign_keys as fk '
.'join sys.foreign_key_columns as fkc on fkc.constraint_object_id = fk.object_id '
.'join sys.tables as lt on lt.object_id = fk.parent_object_id '
.'join sys.schemas as ls on lt.schema_id = ls.schema_id '
.'join sys.columns as lc on fkc.parent_object_id = lc.object_id and fkc.parent_column_id = lc.column_id '
.'join sys.tables as ft on ft.object_id = fk.referenced_object_id '
.'join sys.schemas as fs on ft.schema_id = fs.schema_id '
.'join sys.columns as fc on fkc.referenced_object_id = fc.object_id and fkc.referenced_column_id = fc.column_id '
.'where lt.name = %s and ls.name = SCHEMA_NAME() '
.'group by fk.name, fs.name, ft.name, fk.update_referential_action_desc, fk.delete_referential_action_desc',
$this->quoteString($table)
);
}

/**
* Compile a create table command.
*
Expand Down
17 changes: 17 additions & 0 deletions src/Illuminate/Database/Schema/MySqlBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,23 @@ public function getIndexes($table)
);
}

/**
* Get the foreign keys for a given table.
*
* @param string $table
* @return array
*/
public function getForeignKeys($table)
{
$table = $this->connection->getTablePrefix().$table;

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

/**
* Drop all tables from the database.
*
Expand Down
17 changes: 17 additions & 0 deletions src/Illuminate/Database/Schema/PostgresBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,23 @@ public function getIndexes($table)
);
}

/**
* Get the foreign keys for a given table.
*
* @param string $table
* @return array
*/
public function getForeignKeys($table)
{
[, $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 schemas for the connection.
*
Expand Down
1 change: 1 addition & 0 deletions src/Illuminate/Support/Facades/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* @method static array getColumnListing(string $table)
* @method static array getColumns(string $table)
* @method static array getIndexes(string $table)
* @method static array getForeignKeys(string $table)
* @method static void table(string $table, \Closure $callback)
* @method static void create(string $table, \Closure $callback)
* @method static void drop(string $table)
Expand Down
Loading

0 comments on commit 7907bfb

Please sign in to comment.