From 50807dbcb79c863d5cb5da52de929ee9ca508d33 Mon Sep 17 00:00:00 2001 From: Hafez Divandari Date: Mon, 27 Nov 2023 19:47:31 +0330 Subject: [PATCH] [10.x] Get tables and views info (#49020) * add getTables and getViews * fix tests * fix a typo * add more integration tests * add more integration tests * remove redundant schema on mysql * formatting --------- Co-authored-by: Taylor Otwell --- .../Database/Query/Processors/Processor.php | 49 ++++++- src/Illuminate/Database/Schema/Builder.php | 60 ++++++-- .../Database/Schema/Grammars/MySqlGrammar.php | 79 ++++++++--- .../Schema/Grammars/PostgresGrammar.php | 71 +++++++--- .../Schema/Grammars/SQLiteGrammar.php | 83 ++++++++--- .../Schema/Grammars/SqlServerGrammar.php | 73 +++++++--- .../Database/Schema/MySqlBuilder.php | 97 ++++++------- .../Database/Schema/PostgresBuilder.php | 129 ++++++++++-------- .../Database/Schema/SQLiteBuilder.php | 66 +++++---- .../Database/Schema/SqlServerBuilder.php | 4 + src/Illuminate/Support/Facades/Schema.php | 3 +- .../DatabaseMySQLSchemaBuilderTest.php | 7 +- .../Database/DatabasePostgresBuilderTest.php | 38 ++++-- tests/Database/DatabaseSchemaBuilderTest.php | 8 +- .../Postgres/PostgresSchemaBuilderTest.php | 35 +++++ .../Database/SchemaBuilderTest.php | 37 +++++ 16 files changed, 595 insertions(+), 244 deletions(-) diff --git a/src/Illuminate/Database/Query/Processors/Processor.php b/src/Illuminate/Database/Query/Processors/Processor.php index 8fb8b0e7ab48..03f8ea982763 100755 --- a/src/Illuminate/Database/Query/Processors/Processor.php +++ b/src/Illuminate/Database/Query/Processors/Processor.php @@ -37,16 +37,44 @@ public function processInsertGetId(Builder $query, $sql, $values, $sequence = nu } /** - * Process the results of a column listing query. + * Process the results of a tables query. * - * @deprecated Will be removed in a future Laravel version. + * @param array $results + * @return array + */ + public function processTables($results) + { + return array_map(function ($result) { + $result = (object) $result; + + return [ + 'name' => $result->name, + 'schema' => $result->schema ?? null, // PostgreSQL and SQL Server + 'size' => isset($result->size) ? (int) $result->size : null, + 'comment' => $result->comment ?? null, // MySQL and PostgreSQL + 'collation' => $result->collation ?? null, // MySQL only + 'engine' => $result->engine ?? null, // MySQL only + ]; + }, $results); + } + + /** + * Process the results of a views query. * * @param array $results * @return array */ - public function processColumnListing($results) + public function processViews($results) { - return $results; + return array_map(function ($result) { + $result = (object) $result; + + return [ + 'name' => $result->name, + 'schema' => $result->schema ?? null, // PostgreSQL and SQL Server + 'definition' => $result->definition, + ]; + }, $results); } /** @@ -59,4 +87,17 @@ public function processColumns($results) { return $results; } + + /** + * Process the results of a column listing query. + * + * @deprecated Will be removed in a future Laravel version. + * + * @param array $results + * @return array + */ + public function processColumnListing($results) + { + return $results; + } } diff --git a/src/Illuminate/Database/Schema/Builder.php b/src/Illuminate/Database/Schema/Builder.php index 1c1e4ff3c8be..92c5f76884ee 100755 --- a/src/Illuminate/Database/Schema/Builder.php +++ b/src/Illuminate/Database/Schema/Builder.php @@ -159,9 +159,51 @@ public function hasTable($table) { $table = $this->connection->getTablePrefix().$table; - return count($this->connection->selectFromWriteConnection( - $this->grammar->compileTableExists(), [$table] - )) > 0; + foreach ($this->getTables() as $value) { + if (strtolower($table) === strtolower($value['name'])) { + return true; + } + } + + return false; + } + + /** + * Get the tables that belong to the database. + * + * @return array + */ + public function getTables() + { + return $this->connection->getPostProcessor()->processTables( + $this->connection->selectFromWriteConnection($this->grammar->compileTables()) + ); + } + + /** + * Get the views that belong to the database. + * + * @return array + */ + public function getViews() + { + return $this->connection->getPostProcessor()->processViews( + $this->connection->selectFromWriteConnection($this->grammar->compileViews()) + ); + } + + /** + * Get all of the table names for the database. + * + * @deprecated Will be removed in a future Laravel version. + * + * @return array + * + * @throws \LogicException + */ + public function getAllTables() + { + throw new LogicException('This database driver does not support getting all tables.'); } /** @@ -385,18 +427,6 @@ public function dropAllTypes() throw new LogicException('This database driver does not support dropping all types.'); } - /** - * Get all of the table names for the database. - * - * @return array - * - * @throws \LogicException - */ - public function getAllTables() - { - throw new LogicException('This database driver does not support getting all tables.'); - } - /** * Rename a table on the schema. * diff --git a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php index 797a5897ff81..8ec5fb4e3040 100755 --- a/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/MySqlGrammar.php @@ -68,6 +68,8 @@ public function compileDropDatabaseIfExists($name) /** * Compile the query to determine the list of tables. * + * @deprecated Will be removed in a future Laravel version. + * * @return string */ public function compileTableExists() @@ -75,6 +77,63 @@ public function compileTableExists() return "select * from information_schema.tables where table_schema = ? and table_name = ? and table_type = 'BASE TABLE'"; } + /** + * Compile the query to determine the tables. + * + * @param string $database + * @return string + */ + public function compileTables($database) + { + return sprintf( + 'select table_name as `name`, (data_length + index_length) as `size`, ' + .'table_comment as `comment`, engine as `engine`, table_collation as `collation` ' + ."from information_schema.tables where table_schema = %s and table_type = 'BASE TABLE' " + .'order by table_name', + $this->quoteString($database) + ); + } + + /** + * Compile the query to determine the views. + * + * @param string $database + * @return string + */ + public function compileViews($database) + { + return sprintf( + 'select table_name as `name`, view_definition as `definition` ' + .'from information_schema.views where table_schema = %s ' + .'order by table_name', + $this->quoteString($database) + ); + } + + /** + * Compile the SQL needed to retrieve all table names. + * + * @deprecated Will be removed in a future Laravel version. + * + * @return string + */ + public function compileGetAllTables() + { + return 'SHOW FULL TABLES WHERE table_type = \'BASE TABLE\''; + } + + /** + * Compile the SQL needed to retrieve all view names. + * + * @deprecated Will be removed in a future Laravel version. + * + * @return string + */ + public function compileGetAllViews() + { + return 'SHOW FULL TABLES WHERE table_type = \'VIEW\''; + } + /** * Compile the query to determine the list of columns. * @@ -532,26 +591,6 @@ public function compileDropAllViews($views) return 'drop view '.implode(',', $this->wrapArray($views)); } - /** - * Compile the SQL needed to retrieve all table names. - * - * @return string - */ - public function compileGetAllTables() - { - return 'SHOW FULL TABLES WHERE table_type = \'BASE TABLE\''; - } - - /** - * Compile the SQL needed to retrieve all view names. - * - * @return string - */ - public function compileGetAllViews() - { - return 'SHOW FULL TABLES WHERE table_type = \'VIEW\''; - } - /** * Compile the command to enable foreign key constraints. * diff --git a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php index c8f19cac2b3b..061984bdbaed 100755 --- a/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/PostgresGrammar.php @@ -78,6 +78,55 @@ public function compileTableExists() return "select * from information_schema.tables where table_catalog = ? and table_schema = ? and table_name = ? and table_type = 'BASE TABLE'"; } + /** + * Compile the query to determine the tables. + * + * @return string + */ + 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 = 'r' and n.oid = c.relnamespace " + .'order by c.relname'; + } + + /** + * Compile the query to determine the views. + * + * @return string + */ + public function compileViews() + { + return 'select viewname as name, schemaname as schema, definition from pg_views order by viewname'; + } + + /** + * Compile the SQL needed to retrieve all table names. + * + * @deprecated Will be removed in a future Laravel version. + * + * @param string|array $searchPath + * @return string + */ + public function compileGetAllTables($searchPath) + { + return "select tablename, concat('\"', schemaname, '\".\"', tablename, '\"') as qualifiedname from pg_catalog.pg_tables where schemaname in ('".implode("','", (array) $searchPath)."')"; + } + + /** + * Compile the SQL needed to retrieve all view names. + * + * @deprecated Will be removed in a future Laravel version. + * + * @param string|array $searchPath + * @return string + */ + public function compileGetAllViews($searchPath) + { + return "select viewname, concat('\"', schemaname, '\".\"', viewname, '\"') as qualifiedname from pg_catalog.pg_views where schemaname in ('".implode("','", (array) $searchPath)."')"; + } + /** * Compile the query to determine the list of columns. * @@ -398,28 +447,6 @@ public function compileDropAllTypes($types) return 'drop type '.implode(',', $this->escapeNames($types)).' cascade'; } - /** - * Compile the SQL needed to retrieve all table names. - * - * @param string|array $searchPath - * @return string - */ - public function compileGetAllTables($searchPath) - { - return "select tablename, concat('\"', schemaname, '\".\"', tablename, '\"') as qualifiedname from pg_catalog.pg_tables where schemaname in ('".implode("','", (array) $searchPath)."')"; - } - - /** - * Compile the SQL needed to retrieve all view names. - * - * @param string|array $searchPath - * @return string - */ - public function compileGetAllViews($searchPath) - { - return "select viewname, concat('\"', schemaname, '\".\"', viewname, '\"') as qualifiedname from pg_catalog.pg_views where schemaname in ('".implode("','", (array) $searchPath)."')"; - } - /** * Compile the SQL needed to retrieve all type names. * diff --git a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php index 05294f2151e2..02a75eeaf58c 100755 --- a/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SQLiteGrammar.php @@ -29,6 +29,8 @@ class SQLiteGrammar extends Grammar /** * Compile the query to determine if a table exists. * + * @deprecated Will be removed in a future Laravel version. + * * @return string */ public function compileTableExists() @@ -36,6 +38,67 @@ public function compileTableExists() return "select * from sqlite_master where type = 'table' and name = ?"; } + /** + * Compile the query to determine if the dbstat table is available. + * + * @return string + */ + public function compileDbstatExists() + { + return "select exists (select 1 from pragma_compile_options where compile_options = 'ENABLE_DBSTAT_VTAB') as enabled"; + } + + /** + * Compile the query to determine the tables. + * + * @param bool $withSize + * @return string + */ + public function compileTables($withSize = false) + { + return $withSize + ? 'select m.tbl_name as name, sum(s.pgsize) as size from sqlite_master as m ' + .'join dbstat as s on s.name = m.name ' + ."where m.type in ('table', 'index') and m.tbl_name not like 'sqlite_%' " + .'group by m.tbl_name ' + .'order by m.tbl_name' + : "select name from sqlite_master where type = 'table' and name not like 'sqlite_%' order by name"; + } + + /** + * Compile the query to determine the views. + * + * @return string + */ + public function compileViews() + { + return "select name, sql as definition from sqlite_master where type = 'view' order by name"; + } + + /** + * Compile the SQL needed to retrieve all table names. + * + * @deprecated Will be removed in a future Laravel version. + * + * @return string + */ + public function compileGetAllTables() + { + return 'select type, name from sqlite_master where type = \'table\' and name not like \'sqlite_%\''; + } + + /** + * Compile the SQL needed to retrieve all view names. + * + * @deprecated Will be removed in a future Laravel version. + * + * @return string + */ + public function compileGetAllViews() + { + return 'select type, name from sqlite_master where type = \'view\''; + } + /** * Compile the query to determine the list of columns. * @@ -283,26 +346,6 @@ public function compileDropAllViews() return "delete from sqlite_master where type in ('view')"; } - /** - * Compile the SQL needed to retrieve all table names. - * - * @return string - */ - public function compileGetAllTables() - { - return 'select type, name from sqlite_master where type = \'table\' and name not like \'sqlite_%\''; - } - - /** - * Compile the SQL needed to retrieve all view names. - * - * @return string - */ - public function compileGetAllViews() - { - return 'select type, name from sqlite_master where type = \'view\''; - } - /** * Compile the SQL needed to rebuild the database. * diff --git a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php index ab1944a83341..084021aa05c6 100755 --- a/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php +++ b/src/Illuminate/Database/Schema/Grammars/SqlServerGrammar.php @@ -69,6 +69,8 @@ public function compileDropDatabaseIfExists($name) /** * Compile the query to determine if a table exists. * + * @deprecated Will be removed in a future Laravel version. + * * @return string */ public function compileTableExists() @@ -76,6 +78,57 @@ public function compileTableExists() return "select * from sys.sysobjects where id = object_id(?) and xtype in ('U', 'V')"; } + /** + * Compile the query to determine the tables. + * + * @return string + */ + public function compileTables() + { + return 'select t.name as name, SCHEMA_NAME(t.schema_id) as [schema], sum(u.total_pages) * 8 * 1024 as size ' + .'from sys.tables as t ' + .'join sys.partitions as p on p.object_id = t.object_id ' + .'join sys.allocation_units as u on u.container_id = p.hobt_id ' + .'group by t.name, t.schema_id ' + .'order by t.name'; + } + + /** + * Compile the query to determine the views. + * + * @return string + */ + public function compileViews() + { + return 'select name, SCHEMA_NAME(v.schema_id) as [schema], definition from sys.views as v ' + .'inner join sys.sql_modules as m on v.object_id = m.object_id ' + .'order by name'; + } + + /** + * Compile the SQL needed to retrieve all table names. + * + * @deprecated Will be removed in a future Laravel version. + * + * @return string + */ + public function compileGetAllTables() + { + return "select name, type from sys.tables where type = 'U'"; + } + + /** + * Compile the SQL needed to retrieve all view names. + * + * @deprecated Will be removed in a future Laravel version. + * + * @return string + */ + public function compileGetAllViews() + { + return "select name, type from sys.objects where type = 'V'"; + } + /** * Compile the query to determine the list of columns. * @@ -504,26 +557,6 @@ public function compileDropAllViews() EXEC sp_executesql @sql;"; } - /** - * Compile the SQL needed to retrieve all table names. - * - * @return string - */ - public function compileGetAllTables() - { - return "select name, type from sys.tables where type = 'U'"; - } - - /** - * Compile the SQL needed to retrieve all view names. - * - * @return string - */ - public function compileGetAllViews() - { - return "select name, type from sys.objects where type = 'V'"; - } - /** * Create the column definition for a char type. * diff --git a/src/Illuminate/Database/Schema/MySqlBuilder.php b/src/Illuminate/Database/Schema/MySqlBuilder.php index 3fcb73764fbe..1c8c767bd997 100755 --- a/src/Illuminate/Database/Schema/MySqlBuilder.php +++ b/src/Illuminate/Database/Schema/MySqlBuilder.php @@ -31,18 +31,59 @@ public function dropDatabaseIfExists($name) } /** - * Determine if the given table exists. + * Get the tables for the database. * - * @param string $table - * @return bool + * @return array */ - public function hasTable($table) + public function getTables() { - $table = $this->connection->getTablePrefix().$table; + return $this->connection->getPostProcessor()->processTables( + $this->connection->selectFromWriteConnection( + $this->grammar->compileTables($this->connection->getDatabaseName()) + ) + ); + } + + /** + * Get the views for the database. + * + * @return array + */ + public function getViews() + { + return $this->connection->getPostProcessor()->processViews( + $this->connection->selectFromWriteConnection( + $this->grammar->compileViews($this->connection->getDatabaseName()) + ) + ); + } + + /** + * Get all of the table names for the database. + * + * @deprecated Will be removed in a future Laravel version. + * + * @return array + */ + public function getAllTables() + { + return $this->connection->select( + $this->grammar->compileGetAllTables() + ); + } - return count($this->connection->selectFromWriteConnection( - $this->grammar->compileTableExists(), [$this->connection->getDatabaseName(), $table] - )) > 0; + /** + * Get all of the view names for the database. + * + * @deprecated Will be removed in a future Laravel version. + * + * @return array + */ + public function getAllViews() + { + return $this->connection->select( + $this->grammar->compileGetAllViews() + ); } /** @@ -69,13 +110,7 @@ public function getColumns($table) */ public function dropAllTables() { - $tables = []; - - foreach ($this->getAllTables() as $row) { - $row = (array) $row; - - $tables[] = reset($row); - } + $tables = array_column($this->getTables(), 'name'); if (empty($tables)) { return; @@ -97,13 +132,7 @@ public function dropAllTables() */ public function dropAllViews() { - $views = []; - - foreach ($this->getAllViews() as $row) { - $row = (array) $row; - - $views[] = reset($row); - } + $views = array_column($this->getViews(), 'name'); if (empty($views)) { return; @@ -113,28 +142,4 @@ public function dropAllViews() $this->grammar->compileDropAllViews($views) ); } - - /** - * Get all of the table names for the database. - * - * @return array - */ - public function getAllTables() - { - return $this->connection->select( - $this->grammar->compileGetAllTables() - ); - } - - /** - * Get all of the view names for the database. - * - * @return array - */ - public function getAllViews() - { - return $this->connection->select( - $this->grammar->compileGetAllViews() - ); - } } diff --git a/src/Illuminate/Database/Schema/PostgresBuilder.php b/src/Illuminate/Database/Schema/PostgresBuilder.php index 34a75ceb5fd5..2074e3b17cbb 100755 --- a/src/Illuminate/Database/Schema/PostgresBuilder.php +++ b/src/Illuminate/Database/Schema/PostgresBuilder.php @@ -53,6 +53,42 @@ public function hasTable($table) )) > 0; } + /** + * Get all of the table names for the database. + * + * @deprecated Will be removed in a future Laravel version. + * + * @return array + */ + public function getAllTables() + { + return $this->connection->select( + $this->grammar->compileGetAllTables( + $this->parseSearchPath( + $this->connection->getConfig('search_path') ?: $this->connection->getConfig('schema') + ) + ) + ); + } + + /** + * Get all of the view names for the database. + * + * @deprecated Will be removed in a future Laravel version. + * + * @return array + */ + public function getAllViews() + { + return $this->connection->select( + $this->grammar->compileGetAllViews( + $this->parseSearchPath( + $this->connection->getConfig('search_path') ?: $this->connection->getConfig('schema') + ) + ) + ); + } + /** * Drop all tables from the database. * @@ -66,11 +102,14 @@ public function dropAllTables() $this->connection->getConfig('dont_drop') ?? ['spatial_ref_sys'] ); - foreach ($this->getAllTables() as $row) { - $row = (array) $row; + $schemas = $this->grammar->escapeNames($this->getSchemas()); + + foreach ($this->getTables() as $table) { + $qualifiedName = $table['schema'].'.'.$table['name']; - if (empty(array_intersect($this->grammar->escapeNames($row), $excludedTables))) { - $tables[] = $row['qualifiedname'] ?? reset($row); + if (empty(array_intersect($this->grammar->escapeNames([$table['name'], $qualifiedName]), $excludedTables)) + && in_array($this->grammar->escapeNames([$table['schema']])[0], $schemas)) { + $tables[] = $qualifiedName; } } @@ -92,10 +131,12 @@ public function dropAllViews() { $views = []; - foreach ($this->getAllViews() as $row) { - $row = (array) $row; + $schemas = $this->grammar->escapeNames($this->getSchemas()); - $views[] = $row['qualifiedname'] ?? reset($row); + foreach ($this->getViews() as $view) { + if (in_array($this->grammar->escapeNames([$view['schema']])[0], $schemas)) { + $views[] = $view['schema'].'.'.$view['name']; + } } if (empty($views)) { @@ -107,6 +148,18 @@ public function dropAllViews() ); } + /** + * Get all of the type names for the database. + * + * @return array + */ + public function getAllTypes() + { + return $this->connection->select( + $this->grammar->compileGetAllTypes() + ); + } + /** * Drop all types from the database. * @@ -131,50 +184,6 @@ public function dropAllTypes() ); } - /** - * Get all of the table names for the database. - * - * @return array - */ - public function getAllTables() - { - return $this->connection->select( - $this->grammar->compileGetAllTables( - $this->parseSearchPath( - $this->connection->getConfig('search_path') ?: $this->connection->getConfig('schema') - ) - ) - ); - } - - /** - * Get all of the view names for the database. - * - * @return array - */ - public function getAllViews() - { - return $this->connection->select( - $this->grammar->compileGetAllViews( - $this->parseSearchPath( - $this->connection->getConfig('search_path') ?: $this->connection->getConfig('schema') - ) - ) - ); - } - - /** - * Get all of the type names for the database. - * - * @return array - */ - public function getAllTypes() - { - return $this->connection->select( - $this->grammar->compileGetAllTypes() - ); - } - /** * Get the columns for a given table. * @@ -195,17 +204,25 @@ public function getColumns($table) } /** - * Parse the database object reference and extract the database, schema, and table. + * Get the schemas for the connection. * - * @param string $reference * @return array */ - protected function parseSchemaAndTable($reference) + protected function getSchemas() { - $searchPath = $this->parseSearchPath( + return $this->parseSearchPath( $this->connection->getConfig('search_path') ?: $this->connection->getConfig('schema') ?: 'public' ); + } + /** + * Parse the database object reference and extract the database, schema, and table. + * + * @param string $reference + * @return array + */ + protected function parseSchemaAndTable($reference) + { $parts = explode('.', $reference); $database = $this->connection->getConfig('database'); @@ -221,7 +238,7 @@ protected function parseSchemaAndTable($reference) // We will use the default schema unless the schema has been specified in the // query. If the schema has been specified in the query then we can use it // instead of a default schema configured in the connection search path. - $schema = $searchPath[0]; + $schema = $this->getSchemas()[0]; if (count($parts) === 2) { $schema = $parts[0]; diff --git a/src/Illuminate/Database/Schema/SQLiteBuilder.php b/src/Illuminate/Database/Schema/SQLiteBuilder.php index 4e74f92d5802..9e7960ba3a65 100644 --- a/src/Illuminate/Database/Schema/SQLiteBuilder.php +++ b/src/Illuminate/Database/Schema/SQLiteBuilder.php @@ -30,6 +30,48 @@ public function dropDatabaseIfExists($name) : true; } + /** + * Get the tables for the database. + * + * @return array + */ + public function getTables() + { + $withSize = $this->connection->scalar($this->grammar->compileDbstatExists()); + + return $this->connection->getPostProcessor()->processTables( + $this->connection->selectFromWriteConnection($this->grammar->compileTables($withSize)) + ); + } + + /** + * Get all of the table names for the database. + * + * @deprecated Will be removed in a future Laravel version. + * + * @return array + */ + public function getAllTables() + { + return $this->connection->select( + $this->grammar->compileGetAllTables() + ); + } + + /** + * Get all of the view names for the database. + * + * @deprecated Will be removed in a future Laravel version. + * + * @return array + */ + public function getAllViews() + { + return $this->connection->select( + $this->grammar->compileGetAllViews() + ); + } + /** * Drop all tables from the database. * @@ -66,30 +108,6 @@ public function dropAllViews() $this->connection->select($this->grammar->compileRebuild()); } - /** - * Get all of the table names for the database. - * - * @return array - */ - public function getAllTables() - { - return $this->connection->select( - $this->grammar->compileGetAllTables() - ); - } - - /** - * Get all of the view names for the database. - * - * @return array - */ - public function getAllViews() - { - return $this->connection->select( - $this->grammar->compileGetAllViews() - ); - } - /** * Empty the database file. * diff --git a/src/Illuminate/Database/Schema/SqlServerBuilder.php b/src/Illuminate/Database/Schema/SqlServerBuilder.php index c323e126a6d9..e7717534f803 100644 --- a/src/Illuminate/Database/Schema/SqlServerBuilder.php +++ b/src/Illuminate/Database/Schema/SqlServerBuilder.php @@ -55,6 +55,8 @@ public function dropAllViews() /** * Drop all tables from the database. * + * @deprecated Will be removed in a future Laravel version. + * * @return array */ public function getAllTables() @@ -67,6 +69,8 @@ public function getAllTables() /** * Get all of the view names for the database. * + * @deprecated Will be removed in a future Laravel version. + * * @return array */ public function getAllViews() diff --git a/src/Illuminate/Support/Facades/Schema.php b/src/Illuminate/Support/Facades/Schema.php index 4a87bcc25cec..ddece45e6e56 100755 --- a/src/Illuminate/Support/Facades/Schema.php +++ b/src/Illuminate/Support/Facades/Schema.php @@ -11,6 +11,8 @@ * @method static bool createDatabase(string $name) * @method static bool dropDatabaseIfExists(string $name) * @method static bool hasTable(string $table) + * @method static array getTables() + * @method static array getViews() * @method static bool hasColumn(string $table, string $column) * @method static bool hasColumns(string $table, array $columns) * @method static void whenTableHasColumn(string $table, string $column, \Closure $callback) @@ -26,7 +28,6 @@ * @method static void dropAllTables() * @method static void dropAllViews() * @method static void dropAllTypes() - * @method static array getAllTables() * @method static void rename(string $from, string $to) * @method static bool enableForeignKeyConstraints() * @method static bool disableForeignKeyConstraints() diff --git a/tests/Database/DatabaseMySQLSchemaBuilderTest.php b/tests/Database/DatabaseMySQLSchemaBuilderTest.php index 2a89d31957c3..53869e6d5604 100755 --- a/tests/Database/DatabaseMySQLSchemaBuilderTest.php +++ b/tests/Database/DatabaseMySQLSchemaBuilderTest.php @@ -20,12 +20,15 @@ public function testHasTable() { $connection = m::mock(Connection::class); $grammar = m::mock(MySqlGrammar::class); + $processor = m::mock(MySqlProcessor::class); $connection->shouldReceive('getDatabaseName')->andReturn('db'); $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); + $connection->shouldReceive('getPostProcessor')->andReturn($processor); $builder = new MySqlBuilder($connection); - $grammar->shouldReceive('compileTableExists')->once()->andReturn('sql'); + $grammar->shouldReceive('compileTables')->once()->andReturn('sql'); + $processor->shouldReceive('processTables')->once()->andReturn([['name' => 'prefix_table']]); $connection->shouldReceive('getTablePrefix')->once()->andReturn('prefix_'); - $connection->shouldReceive('selectFromWriteConnection')->once()->with('sql', ['db', 'prefix_table'])->andReturn(['prefix_table']); + $connection->shouldReceive('selectFromWriteConnection')->once()->with('sql')->andReturn([['name' => 'prefix_table']]); $this->assertTrue($builder->hasTable('table')); } diff --git a/tests/Database/DatabasePostgresBuilderTest.php b/tests/Database/DatabasePostgresBuilderTest.php index 11c2b9ca41ac..4de2c649ebdd 100644 --- a/tests/Database/DatabasePostgresBuilderTest.php +++ b/tests/Database/DatabasePostgresBuilderTest.php @@ -237,12 +237,16 @@ public function testDropAllTablesWhenSearchPathIsString() $connection->shouldReceive('getConfig')->with('search_path')->andReturn('public'); $connection->shouldReceive('getConfig')->with('dont_drop')->andReturn(['foo']); $grammar = m::mock(PostgresGrammar::class); + $processor = m::mock(PostgresProcessor::class); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); - $grammar->shouldReceive('compileGetAllTables')->with(['public'])->andReturn("select tablename, concat('\"', schemaname, '\".\"', tablename, '\"') as qualifiedname from pg_catalog.pg_tables where schemaname in ('public')"); - $connection->shouldReceive('select')->with("select tablename, concat('\"', schemaname, '\".\"', tablename, '\"') as qualifiedname from pg_catalog.pg_tables where schemaname in ('public')")->andReturn([['tablename' => 'users', 'qualifiedname' => '"public"."users"']]); + $connection->shouldReceive('getPostProcessor')->andReturn($processor); + $grammar->shouldReceive('compileTables')->andReturn('sql'); + $processor->shouldReceive('processTables')->once()->andReturn([['name' => 'users', 'schema' => 'public']]); + $connection->shouldReceive('selectFromWriteConnection')->with('sql')->andReturn([['name' => 'users', 'schema' => 'public']]); + $grammar->shouldReceive('escapeNames')->with(['public'])->andReturn(['"public"']); $grammar->shouldReceive('escapeNames')->with(['foo'])->andReturn(['"foo"']); - $grammar->shouldReceive('escapeNames')->with(['tablename' => 'users', 'qualifiedname' => '"public"."users"'])->andReturn(['tablename' => '"users"', 'qualifiedname' => '"public"."users"']); - $grammar->shouldReceive('compileDropAllTables')->with(['"public"."users"'])->andReturn('drop table "public"."users" cascade'); + $grammar->shouldReceive('escapeNames')->with(['users', 'public.users'])->andReturn(['"users"', '"public"."users"']); + $grammar->shouldReceive('compileDropAllTables')->with(['public.users'])->andReturn('drop table "public"."users" cascade'); $connection->shouldReceive('statement')->with('drop table "public"."users" cascade'); $builder = $this->getBuilder($connection); @@ -256,12 +260,17 @@ public function testDropAllTablesWhenSearchPathIsStringOfMany() $connection->shouldReceive('getConfig')->with('search_path')->andReturn('"$user", public, foo_bar-Baz.Áüõß'); $connection->shouldReceive('getConfig')->with('dont_drop')->andReturn(['foo']); $grammar = m::mock(PostgresGrammar::class); + $processor = m::mock(PostgresProcessor::class); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); - $grammar->shouldReceive('compileGetAllTables')->with(['foouser', 'public', 'foo_bar-Baz.Áüõß'])->andReturn("select tablename, concat('\"', schemaname, '\".\"', tablename, '\"') as qualifiedname from pg_catalog.pg_tables where schemaname in ('foouser','public','foo_bar-Baz.Áüõß')"); - $connection->shouldReceive('select')->with("select tablename, concat('\"', schemaname, '\".\"', tablename, '\"') as qualifiedname from pg_catalog.pg_tables where schemaname in ('foouser','public','foo_bar-Baz.Áüõß')")->andReturn([['tablename' => 'users', 'qualifiedname' => '"foouser"."users"']]); + $connection->shouldReceive('getPostProcessor')->andReturn($processor); + $processor->shouldReceive('processTables')->once()->andReturn([['name' => 'users', 'schema' => 'foouser']]); + $grammar->shouldReceive('compileTables')->andReturn('sql'); + $connection->shouldReceive('selectFromWriteConnection')->with('sql')->andReturn([['name' => 'users', 'schema' => 'foouser']]); + $grammar->shouldReceive('escapeNames')->with(['foouser', 'public', 'foo_bar-Baz.Áüõß'])->andReturn(['"foouser"', '"public"', '"foo_bar-Baz"."Áüõß"']); $grammar->shouldReceive('escapeNames')->with(['foo'])->andReturn(['"foo"']); - $grammar->shouldReceive('escapeNames')->with(['tablename' => 'users', 'qualifiedname' => '"foouser"."users"'])->andReturn(['tablename' => '"users"', 'qualifiedname' => '"foouser"."users"']); - $grammar->shouldReceive('compileDropAllTables')->with(['"foouser"."users"'])->andReturn('drop table "foouser"."users" cascade'); + $grammar->shouldReceive('escapeNames')->with(['foouser'])->andReturn(['"foouser"']); + $grammar->shouldReceive('escapeNames')->with(['users', 'foouser.users'])->andReturn(['"users"', '"foouser"."users"']); + $grammar->shouldReceive('compileDropAllTables')->with(['foouser.users'])->andReturn('drop table "foouser"."users" cascade'); $connection->shouldReceive('statement')->with('drop table "foouser"."users" cascade'); $builder = $this->getBuilder($connection); @@ -280,12 +289,17 @@ public function testDropAllTablesWhenSearchPathIsArrayOfMany() ]); $connection->shouldReceive('getConfig')->with('dont_drop')->andReturn(['foo']); $grammar = m::mock(PostgresGrammar::class); + $processor = m::mock(PostgresProcessor::class); $connection->shouldReceive('getSchemaGrammar')->once()->andReturn($grammar); - $grammar->shouldReceive('compileGetAllTables')->with(['foouser', 'dev', 'test', 'spaced schema'])->andReturn("select tablename, concat('\"', schemaname, '\".\"', tablename, '\"') as qualifiedname from pg_catalog.pg_tables where schemaname in ('foouser','dev','test','spaced schema')"); - $connection->shouldReceive('select')->with("select tablename, concat('\"', schemaname, '\".\"', tablename, '\"') as qualifiedname from pg_catalog.pg_tables where schemaname in ('foouser','dev','test','spaced schema')")->andReturn([['tablename' => 'users', 'qualifiedname' => '"foouser"."users"']]); + $connection->shouldReceive('getPostProcessor')->andReturn($processor); + $processor->shouldReceive('processTables')->once()->andReturn([['name' => 'users', 'schema' => 'foouser']]); + $grammar->shouldReceive('compileTables')->andReturn('sql'); + $connection->shouldReceive('selectFromWriteConnection')->with('sql')->andReturn([['name' => 'users', 'schema' => 'foouser']]); + $grammar->shouldReceive('escapeNames')->with(['foouser', 'dev', 'test', 'spaced schema'])->andReturn(['"foouser"', '"dev"', '"test"', '"spaced schema"']); $grammar->shouldReceive('escapeNames')->with(['foo'])->andReturn(['"foo"']); - $grammar->shouldReceive('escapeNames')->with(['tablename' => 'users', 'qualifiedname' => '"foouser"."users"'])->andReturn(['tablename' => '"users"', 'qualifiedname' => '"foouser"."users"']); - $grammar->shouldReceive('compileDropAllTables')->with(['"foouser"."users"'])->andReturn('drop table "foouser"."users" cascade'); + $grammar->shouldReceive('escapeNames')->with(['users', 'foouser.users'])->andReturn(['"users"', '"foouser"."users"']); + $grammar->shouldReceive('escapeNames')->with(['foouser'])->andReturn(['"foouser"']); + $grammar->shouldReceive('compileDropAllTables')->with(['foouser.users'])->andReturn('drop table "foouser"."users" cascade'); $connection->shouldReceive('statement')->with('drop table "foouser"."users" cascade'); $builder = $this->getBuilder($connection); diff --git a/tests/Database/DatabaseSchemaBuilderTest.php b/tests/Database/DatabaseSchemaBuilderTest.php index 2fdd98e1225b..e2619c667447 100755 --- a/tests/Database/DatabaseSchemaBuilderTest.php +++ b/tests/Database/DatabaseSchemaBuilderTest.php @@ -3,6 +3,7 @@ namespace Illuminate\Tests\Database; use Illuminate\Database\Connection; +use Illuminate\Database\Query\Processors\PostgresProcessor; use Illuminate\Database\Schema\Builder; use LogicException; use Mockery as m; @@ -46,11 +47,14 @@ public function testHasTableCorrectlyCallsGrammar() { $connection = m::mock(Connection::class); $grammar = m::mock(stdClass::class); + $processor = m::mock(PostgresProcessor::class); $connection->shouldReceive('getSchemaGrammar')->andReturn($grammar); + $connection->shouldReceive('getPostProcessor')->andReturn($processor); $builder = new Builder($connection); - $grammar->shouldReceive('compileTableExists')->once()->andReturn('sql'); + $grammar->shouldReceive('compileTables')->once()->andReturn('sql'); + $processor->shouldReceive('processTables')->once()->andReturn([['name' => 'prefix_table']]); $connection->shouldReceive('getTablePrefix')->once()->andReturn('prefix_'); - $connection->shouldReceive('selectFromWriteConnection')->once()->with('sql', ['prefix_table'])->andReturn(['prefix_table']); + $connection->shouldReceive('selectFromWriteConnection')->once()->with('sql')->andReturn([['name' => 'prefix_table']]); $this->assertTrue($builder->hasTable('table')); } diff --git a/tests/Integration/Database/Postgres/PostgresSchemaBuilderTest.php b/tests/Integration/Database/Postgres/PostgresSchemaBuilderTest.php index 8efa387060ca..99240f81b665 100644 --- a/tests/Integration/Database/Postgres/PostgresSchemaBuilderTest.php +++ b/tests/Integration/Database/Postgres/PostgresSchemaBuilderTest.php @@ -130,6 +130,41 @@ public function testAddTableCommentOnExistingTable() $this->assertEquals('This is a new comment', DB::selectOne("select obj_description('public.posts'::regclass, 'pg_class')")->obj_description); } + public function testGetTables() + { + Schema::create('public.table', function (Blueprint $table) { + $table->string('name'); + }); + + Schema::create('private.table', function (Blueprint $table) { + $table->integer('votes'); + }); + + $tables = Schema::getTables(); + + $this->assertNotEmpty(array_filter($tables, function ($table) { + return $table['name'] === 'table' && $table['schema'] === 'public'; + })); + $this->assertNotEmpty(array_filter($tables, function ($table) { + return $table['name'] === 'table' && $table['schema'] === 'private'; + })); + } + + public function testGetViews() + { + DB::statement('create view public.foo (id) as select 1'); + DB::statement('create view private.foo (id) as select 1'); + + $views = Schema::getViews(); + + $this->assertNotEmpty(array_filter($views, function ($view) { + return $view['name'] === 'foo' && $view['schema'] === 'public'; + })); + $this->assertNotEmpty(array_filter($views, function ($view) { + return $view['name'] === 'foo' && $view['schema'] === 'private'; + })); + } + protected function hasView($schema, $table) { return DB::table('information_schema.views') diff --git a/tests/Integration/Database/SchemaBuilderTest.php b/tests/Integration/Database/SchemaBuilderTest.php index 0a13f5812b18..38f2c34d6cc8 100644 --- a/tests/Integration/Database/SchemaBuilderTest.php +++ b/tests/Integration/Database/SchemaBuilderTest.php @@ -137,4 +137,41 @@ public function testChangeTextColumnToTextColumn() $this->assertEquals($expected, $queries); } } + + public function testGetTables() + { + Schema::create('foo', function (Blueprint $table) { + $table->comment('This is a comment'); + $table->increments('id'); + }); + + Schema::create('bar', function (Blueprint $table) { + $table->string('name'); + }); + + Schema::create('baz', function (Blueprint $table) { + $table->integer('votes'); + }); + + $tables = Schema::getTables(); + + $this->assertEmpty(array_diff(['foo', 'bar', 'baz'], array_column($tables, 'name'))); + + if (in_array($this->driver, ['mysql', 'pgsql'])) { + $this->assertNotEmpty(array_filter($tables, function ($table) { + return $table['name'] === 'foo' && $table['comment'] === 'This is a comment'; + })); + } + } + + public function testGetViews() + { + DB::statement('create view foo (id) as select 1'); + DB::statement('create view bar (name) as select 1'); + DB::statement('create view baz (votes) as select 1'); + + $views = Schema::getViews(); + + $this->assertEmpty(array_diff(['foo', 'bar', 'baz'], array_column($views, 'name'))); + } }