diff --git a/src/Database/Driver.php b/src/Database/Driver.php index a6f03ff59..b1d742afd 100644 --- a/src/Database/Driver.php +++ b/src/Database/Driver.php @@ -75,25 +75,25 @@ function applyLimit(string &$sql, ?int $limit, ?int $offset): void; /********************* reflection ****************d*g**/ /** - * Returns list of tables as tuples [(string) name, (bool) view, [(string) fullName]] + * @return Reflection\Table[] */ function getTables(): array; /** * Returns metadata for all columns in a table. - * As tuples [(string) name, (string) table, (string) nativetype, (int) size, (bool) nullable, (mixed) default, (bool) autoincrement, (bool) primary, (array) vendor]] + * @return Reflection\Column[] */ function getColumns(string $table): array; /** * Returns metadata for all indexes in a table. - * As tuples [(string) name, (string[]) columns, (bool) unique, (bool) primary] + * @return Reflection\Index[] */ function getIndexes(string $table): array; /** * Returns metadata for all foreign keys in a table. - * As tuples [(string) name, (string) local, (string) table, (string) foreign] + * @return Reflection\ForeignKey[] */ function getForeignKeys(string $table): array; diff --git a/src/Database/Drivers/MsSqlDriver.php b/src/Database/Drivers/MsSqlDriver.php index 538503237..13142cf8d 100644 --- a/src/Database/Drivers/MsSqlDriver.php +++ b/src/Database/Drivers/MsSqlDriver.php @@ -65,15 +65,10 @@ public function applyLimit(string &$sql, ?int $limit, ?int $offset): void public function getTables(): array { - $tables = []; - foreach ($this->pdo->query('SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES') as $row) { - $tables[] = [ - 'name' => $row['TABLE_SCHEMA'] . '.' . $row['TABLE_NAME'], - 'view' => ($row['TABLE_TYPE'] ?? null) === 'VIEW', - ]; - } - - return $tables; + return $this->pdo->query('SELECT TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE FROM INFORMATION_SCHEMA.TABLES')->fetchAll( + \PDO::FETCH_FUNC, + fn($schema, $name, $type) => new Nette\Database\Reflection\Table($schema . '.' . $name, $type === 'VIEW'), + ); } @@ -99,18 +94,17 @@ public function getColumns(string $table): array X; foreach ($this->pdo->query($query, \PDO::FETCH_ASSOC) as $row) { - $columns[] = [ - 'name' => $row['COLUMN_NAME'], - 'table' => $table, - 'nativetype' => $row['DATA_TYPE'], - 'size' => $row['CHARACTER_MAXIMUM_LENGTH'] ?? ($row['NUMERIC_PRECISION'] ?? null), - 'unsigned' => false, - 'nullable' => $row['IS_NULLABLE'] === 'YES', - 'default' => $row['COLUMN_DEFAULT'], - 'autoincrement' => $row['DOMAIN_NAME'] === 'COUNTER', - 'primary' => $row['COLUMN_NAME'] === 'ID', - 'vendor' => $row, - ]; + $columns[] = new Nette\Database\Reflection\Column( + name: $row['COLUMN_NAME'], + table: $table, + nativeType: $row['DATA_TYPE'], + size: $row['CHARACTER_MAXIMUM_LENGTH'] ?? $row['NUMERIC_PRECISION'] ?? null, + nullable: $row['IS_NULLABLE'] === 'YES', + default: $row['COLUMN_DEFAULT'], + autoIncrement: $row['DOMAIN_NAME'] === 'COUNTER', + primary: $row['COLUMN_NAME'] === 'ID', + vendor: $row, + ); } return $columns; @@ -148,7 +142,7 @@ public function getIndexes(string $table): array $indexes[$id]['columns'][$row['id_column'] - 1] = $row['name_column']; } - return array_values($indexes); + return array_map(fn($data) => new Nette\Database\Reflection\Index(...$data), array_values($indexes)); } @@ -184,12 +178,12 @@ public function getForeignKeys(string $table): array foreach ($this->pdo->query($query) as $row) { $id = $row['fk_name']; $keys[$id]['name'] = $id; - $keys[$id]['local'][] = $row['column']; - $keys[$id]['table'] = $table_schema . '.' . $row['referenced_table']; - $keys[$id]['foreign'][] = $row['referenced_column']; + $keys[$id]['columns'][] = $row['column']; + $keys[$id]['targetTable'] = $table_schema . '.' . $row['referenced_table']; + $keys[$id]['targetColumns'][] = $row['referenced_column']; } - return array_values($keys); + return array_map(fn($data) => new Nette\Database\Reflection\ForeignKey(...$data), array_values($keys)); } diff --git a/src/Database/Drivers/MySqlDriver.php b/src/Database/Drivers/MySqlDriver.php index 34127aaae..2615b24bc 100644 --- a/src/Database/Drivers/MySqlDriver.php +++ b/src/Database/Drivers/MySqlDriver.php @@ -118,15 +118,10 @@ public function applyLimit(string &$sql, ?int $limit, ?int $offset): void public function getTables(): array { - $tables = []; - foreach ($this->pdo->query('SHOW FULL TABLES') as $row) { - $tables[] = [ - 'name' => $row[0], - 'view' => ($row[1] ?? null) === 'VIEW', - ]; - } - - return $tables; + return $this->pdo->query('SHOW FULL TABLES')->fetchAll( + \PDO::FETCH_FUNC, + fn($name, $type) => new Nette\Database\Reflection\Table($name, $type === 'VIEW'), + ); } @@ -135,17 +130,17 @@ public function getColumns(string $table): array $columns = []; foreach ($this->pdo->query('SHOW FULL COLUMNS FROM ' . $this->delimite($table), \PDO::FETCH_ASSOC) as $row) { $type = explode('(', $row['Type']); - $columns[] = [ - 'name' => $row['Field'], - 'table' => $table, - 'nativetype' => $type[0], - 'size' => isset($type[1]) ? (int) $type[1] : null, - 'nullable' => $row['Null'] === 'YES', - 'default' => $row['Default'], - 'autoincrement' => $row['Extra'] === 'auto_increment', - 'primary' => $row['Key'] === 'PRI', - 'vendor' => $row, - ]; + $columns[] = new Nette\Database\Reflection\Column( + name: $row['Field'], + table: $table, + nativeType: $type[0], + size: isset($type[1]) ? (int) $type[1] : null, + nullable: $row['Null'] === 'YES', + default: $row['Default'], + autoIncrement: $row['Extra'] === 'auto_increment', + primary: $row['Key'] === 'PRI', + vendor: $row, + ); } return $columns; @@ -163,7 +158,7 @@ public function getIndexes(string $table): array $indexes[$id]['columns'][$row['Seq_in_index'] - 1] = $row['Column_name']; } - return array_values($indexes); + return array_map(fn($data) => new Nette\Database\Reflection\Index(...$data), array_values($indexes)); } @@ -179,12 +174,12 @@ public function getForeignKeys(string $table): array X) as $row) { $id = $row['CONSTRAINT_NAME']; $keys[$id]['name'] = $id; - $keys[$id]['local'][] = $row['COLUMN_NAME']; - $keys[$id]['table'] = $row['REFERENCED_TABLE_NAME']; - $keys[$id]['foreign'][] = $row['REFERENCED_COLUMN_NAME']; + $keys[$id]['columns'][] = $row['COLUMN_NAME']; + $keys[$id]['targetTable'] = $row['REFERENCED_TABLE_NAME']; + $keys[$id]['targetColumns'][] = $row['REFERENCED_COLUMN_NAME']; } - return array_values($keys); + return array_map(fn($data) => new Nette\Database\Reflection\ForeignKey(...$data), array_values($keys)); } diff --git a/src/Database/Drivers/PgSqlDriver.php b/src/Database/Drivers/PgSqlDriver.php index c4c66fd13..79596f066 100644 --- a/src/Database/Drivers/PgSqlDriver.php +++ b/src/Database/Drivers/PgSqlDriver.php @@ -95,9 +95,9 @@ public function getTables(): array { return $this->pdo->query(<<<'X' SELECT DISTINCT ON (c.relname) - c.relname::varchar AS name, - c.relkind IN ('v', 'm') AS view, - n.nspname::varchar || '.' || c.relname::varchar AS "fullName" + c.relname::varchar, + c.relkind IN ('v', 'm'), + n.nspname::varchar || '.' || c.relname::varchar FROM pg_catalog.pg_class AS c JOIN pg_catalog.pg_namespace AS n ON n.oid = c.relnamespace @@ -106,7 +106,10 @@ public function getTables(): array AND n.nspname = ANY (pg_catalog.current_schemas(FALSE)) ORDER BY c.relname - X)->fetchAll(\PDO::FETCH_ASSOC); + X)->fetchAll( + \PDO::FETCH_FUNC, + fn($name, $view, $full) => new Nette\Database\Reflection\Table($name, $view, $full), + ); } @@ -117,11 +120,11 @@ public function getColumns(string $table): array SELECT a.attname::varchar AS name, c.relname::varchar AS table, - t.typname AS nativetype, + t.typname AS "nativeType", CASE WHEN a.atttypmod = -1 THEN NULL ELSE a.atttypmod -4 END AS size, NOT (a.attnotnull OR t.typtype = 'd' AND t.typnotnull) AS nullable, pg_catalog.pg_get_expr(ad.adbin, 'pg_catalog.pg_attrdef'::regclass)::varchar AS default, - coalesce(co.contype = 'p' AND (seq.relname IS NOT NULL OR strpos(pg_catalog.pg_get_expr(ad.adbin, ad.adrelid), 'nextval') = 1), FALSE) AS autoincrement, + coalesce(co.contype = 'p' AND (seq.relname IS NOT NULL OR strpos(pg_catalog.pg_get_expr(ad.adbin, ad.adrelid), 'nextval') = 1), FALSE) AS "autoIncrement", coalesce(co.contype = 'p', FALSE) AS primary, coalesce(seq.relname, substring(pg_catalog.pg_get_expr(ad.adbin, 'pg_catalog.pg_attrdef'::regclass) from 'nextval[(]''"?([^''"]+)')) AS sequence FROM @@ -139,11 +142,11 @@ public function getColumns(string $table): array AND NOT a.attisdropped ORDER BY a.attnum - X, \PDO::FETCH_ASSOC) as $column) { - $column['vendor'] = $column; - unset($column['sequence']); - - $columns[] = $column; + X, \PDO::FETCH_ASSOC) as $row + ) { + $row['vendor'] = $row; + unset($row['sequence']); + $columns[] = new Nette\Database\Reflection\Column(...$row); } return $columns; @@ -175,7 +178,7 @@ public function getIndexes(string $table): array $indexes[$id]['columns'][] = $row['column']; } - return array_values($indexes); + return array_map(fn($data) => new Nette\Database\Reflection\Index(...$data), array_values($indexes)); } @@ -203,12 +206,12 @@ public function getForeignKeys(string $table): array X) as $row) { $id = $row['name']; $keys[$id]['name'] = $id; - $keys[$id]['local'][] = $row['local']; - $keys[$id]['table'] = $row['table']; - $keys[$id]['foreign'][] = $row['foreign']; + $keys[$id]['columns'][] = $row['local']; + $keys[$id]['targetTable'] = $row['table']; + $keys[$id]['targetColumns'][] = $row['foreign']; } - return array_values($keys); + return array_map(fn($data) => new Nette\Database\Reflection\ForeignKey(...$data), array_values($keys)); } diff --git a/src/Database/Drivers/SqliteDriver.php b/src/Database/Drivers/SqliteDriver.php index 58c581bfc..7469b3c47 100644 --- a/src/Database/Drivers/SqliteDriver.php +++ b/src/Database/Drivers/SqliteDriver.php @@ -111,9 +111,8 @@ public function applyLimit(string &$sql, ?int $limit, ?int $offset): void public function getTables(): array { - $tables = []; - foreach ($this->pdo->query(<<<'X' - SELECT name, type = 'view' as view + return $this->pdo->query(<<<'X' + SELECT name, type = 'view' FROM sqlite_master WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%' UNION ALL @@ -121,14 +120,10 @@ public function getTables(): array FROM sqlite_temp_master WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%' ORDER BY name - X) as $row) { - $tables[] = [ - 'name' => $row['name'], - 'view' => (bool) $row['view'], - ]; - } - - return $tables; + X)->fetchAll( + \PDO::FETCH_FUNC, + fn($name, $view) => new Nette\Database\Reflection\Table($name, (bool) $view), + ); } @@ -149,17 +144,17 @@ public function getColumns(string $table): array $column = $row['name']; $pattern = "/(\"$column\"|`$column`|\\[$column\\]|$column)\\s+[^,]+\\s+PRIMARY\\s+KEY\\s+AUTOINCREMENT/Ui"; $type = explode('(', $row['type']); - $columns[] = [ - 'name' => $column, - 'table' => $table, - 'nativetype' => strtoupper($type[0]), - 'size' => isset($type[1]) ? (int) $type[1] : null, - 'nullable' => !$row['notnull'], - 'default' => $row['dflt_value'], - 'autoincrement' => $meta && preg_match($pattern, (string) $meta['sql']), - 'primary' => $row['pk'] > 0, - 'vendor' => $row, - ]; + $columns[] = new Nette\Database\Reflection\Column( + name: $column, + table: $table, + nativeType: $type[0], + size: isset($type[1]) ? (int) $type[1] : null, + nullable: !$row['notnull'], + default: $row['dflt_value'], + autoIncrement: $meta && preg_match($pattern, (string) $meta['sql']), + primary: $row['pk'] > 0, + vendor: $row, + ); } return $columns; @@ -186,8 +181,8 @@ public function getIndexes(string $table): array foreach ($indexes as $index => $values) { $column = $indexes[$index]['columns'][0]; foreach ($columns as $info) { - if ($column === $info['name']) { - $indexes[$index]['primary'] = (bool) $info['primary']; + if ($column === $info->name) { + $indexes[$index]['primary'] = $info->primary; break; } } @@ -207,7 +202,7 @@ public function getIndexes(string $table): array } } - return array_values($indexes); + return array_map(fn($data) => new Nette\Database\Reflection\Index(...$data), array_values($indexes)); } @@ -216,16 +211,16 @@ public function getForeignKeys(string $table): array $keys = []; foreach ($this->pdo->query("PRAGMA foreign_key_list({$this->delimite($table)})") as $row) { $id = $row['id']; - $keys[$id]['name'] = $id; - $keys[$id]['local'][] = $row['from']; - $keys[$id]['table'] = $row['table']; - $keys[$id]['foreign'][] = $row['to']; - if ($keys[$id]['foreign'][0] == null) { - $keys[$id]['foreign'] = []; + $keys[$id]['name'] = (string) $id; + $keys[$id]['columns'][] = $row['from']; + $keys[$id]['targetTable'] = $row['table']; + $keys[$id]['targetColumns'][] = $row['to']; + if ($keys[$id]['targetColumns'][0] == null) { + $keys[$id]['targetColumns'] = []; } } - return array_values($keys); + return array_map(fn($data) => new Nette\Database\Reflection\ForeignKey(...$data), array_values($keys)); } diff --git a/src/Database/Drivers/SqlsrvDriver.php b/src/Database/Drivers/SqlsrvDriver.php index 77fad9b13..19bc68c45 100644 --- a/src/Database/Drivers/SqlsrvDriver.php +++ b/src/Database/Drivers/SqlsrvDriver.php @@ -92,26 +92,21 @@ public function applyLimit(string &$sql, ?int $limit, ?int $offset): void public function getTables(): array { - $tables = []; - foreach ($this->pdo->query(<<<'X' + return $this->pdo->query(<<<'X' SELECT name, CASE type WHEN 'U' THEN 0 WHEN 'V' THEN 1 - END AS [view] + END FROM sys.objects WHERE type IN ('U', 'V') - X) as $row) { - $tables[] = [ - 'name' => $row['name'], - 'view' => (bool) $row['view'], - ]; - } - - return $tables; + X)->fetchAll( + \PDO::FETCH_FUNC, + fn($name, $view) => new Nette\Database\Reflection\Table($name, (bool) $view), + ); } @@ -122,11 +117,11 @@ public function getColumns(string $table): array SELECT c.name AS name, o.name AS [table], - t.name AS nativetype, + t.name AS nativeType, NULL AS size, c.is_nullable AS nullable, OBJECT_DEFINITION(c.default_object_id) AS [default], - c.is_identity AS autoincrement, + c.is_identity AS autoIncrement, CASE WHEN i.index_id IS NULL THEN 0 ELSE 1 @@ -143,10 +138,10 @@ public function getColumns(string $table): array X, \PDO::FETCH_ASSOC) as $row) { $row['vendor'] = $row; $row['nullable'] = (bool) $row['nullable']; - $row['autoincrement'] = (bool) $row['autoincrement']; + $row['autoIncrement'] = (bool) $row['autoIncrement']; $row['primary'] = (bool) $row['primary']; - $columns[] = $row; + $columns[] = new Nette\Database\Reflection\Column(...$row); } return $columns; @@ -183,7 +178,7 @@ public function getIndexes(string $table): array $indexes[$id]['columns'][] = $row['column']; } - return array_values($indexes); + return array_map(fn($data) => new Nette\Database\Reflection\Index(...$data), array_values($indexes)); } @@ -209,12 +204,12 @@ public function getForeignKeys(string $table): array X, \PDO::FETCH_ASSOC) as $row) { $id = $row['name']; $keys[$id]['name'] = $id; - $keys[$id]['local'][] = $row['local']; - $keys[$id]['table'] = $row['table']; - $keys[$id]['foreign'][] = $row['column']; + $keys[$id]['columns'][] = $row['local']; + $keys[$id]['targetTable'] = $row['table']; + $keys[$id]['targetColumns'][] = $row['column']; } - return array_values($keys); + return array_map(fn($data) => new Nette\Database\Reflection\ForeignKey(...$data), array_values($keys)); } diff --git a/src/Database/Reflection/Column.php b/src/Database/Reflection/Column.php new file mode 100644 index 000000000..540c1de1e --- /dev/null +++ b/src/Database/Reflection/Column.php @@ -0,0 +1,30 @@ +connection = $connection; - $this->cache = new Nette\Caching\Cache($cacheStorage, 'Nette.Database.Structure.' . md5($this->connection->getDsn())); + $this->cache = new Nette\Caching\Cache($cacheStorage, 'Nette.Database.Structure4.' . md5($this->connection->getDsn())); } + /** @return Reflection\Table[] */ public function getTables(): array { $this->needStructure(); @@ -40,6 +41,7 @@ public function getTables(): array } + /** @return Reflection\Column[] */ public function getColumns(string $table): array { $this->needStructure(); @@ -71,8 +73,8 @@ public function getPrimaryAutoincrementKey(string $table): ?string if (is_array($primaryKey)) { $keys = array_flip($primaryKey); foreach ($this->getColumns($table) as $column) { - if (isset($keys[$column['name']]) && $column['autoincrement']) { - return $column['name']; + if (isset($keys[$column->name]) && $column->autoIncrement) { + return $column->name; } } @@ -81,8 +83,8 @@ public function getPrimaryAutoincrementKey(string $table): ?string // Search for autoincrement key from simple primary key foreach ($this->getColumns($table) as $column) { - if ($column['name'] === $primaryKey) { - return $column['autoincrement'] ? $column['name'] : null; + if ($column->name === $primaryKey) { + return $column->autoIncrement ? $column->name : null; } } @@ -106,8 +108,8 @@ public function getPrimaryKeySequence(string $table): ?string // Search for sequence from simple primary key foreach ($this->structure['columns'][$table] as $columnMeta) { - if ($columnMeta['name'] === $autoincrementPrimaryKeyName) { - return $columnMeta['vendor']['sequence'] ?? null; + if ($columnMeta->name === $autoincrementPrimaryKeyName) { + return $columnMeta->vendor['sequence'] ?? null; } } @@ -183,25 +185,25 @@ protected function loadStructure(): array $structure = []; $structure['tables'] = $driver->getTables(); - foreach ($structure['tables'] as $tablePair) { - if (isset($tablePair['fullName'])) { - $table = $tablePair['fullName']; - $structure['aliases'][strtolower($tablePair['name'])] = strtolower($table); + foreach ($structure['tables'] as $table) { + if (isset($table->fullName)) { + $tableName = $table->fullName; + $structure['aliases'][strtolower($table->name)] = strtolower($tableName); } else { - $table = $tablePair['name']; + $tableName = $table->name; } - $structure['columns'][strtolower($table)] = $columns = $driver->getColumns($table); + $structure['columns'][strtolower($tableName)] = $columns = $driver->getColumns($tableName); - if (!$tablePair['view']) { - $structure['primary'][strtolower($table)] = $this->analyzePrimaryKey($columns); - $this->analyzeForeignKeys($structure, $table); + if (!$table->view) { + $structure['primary'][strtolower($tableName)] = $this->analyzePrimaryKey($columns); + $this->analyzeForeignKeys($structure, $tableName); } } if (isset($structure['hasMany'])) { - foreach ($structure['hasMany'] as &$table) { - uksort($table, fn($a, $b): int => strlen($a) <=> strlen($b)); + foreach ($structure['hasMany'] as &$tableName) { + uksort($tableName, fn($a, $b): int => strlen($a) <=> strlen($b)); } } @@ -211,12 +213,13 @@ protected function loadStructure(): array } + /** @param Reflection\Column[] $columns */ protected function analyzePrimaryKey(array $columns) { $primary = []; foreach ($columns as $column) { - if ($column['primary']) { - $primary[] = $column['name']; + if ($column->primary) { + $primary[] = $column->name; } } @@ -236,11 +239,11 @@ protected function analyzeForeignKeys(array &$structure, string $table): void $foreignKeys = $this->connection->getDriver()->getForeignKeys($table); - usort($foreignKeys, fn($a, $b): int => count($b['local']) <=> count($a['local'])); + usort($foreignKeys, fn($a, $b): int => count($b->columns) <=> count($a->columns)); - foreach ($foreignKeys as $row) { - $structure['belongsTo'][$lowerTable][$row['local'][0]] = $row['table']; - $structure['hasMany'][strtolower($row['table'])][$table][] = $row['local'][0]; + foreach ($foreignKeys as $key) { + $structure['belongsTo'][$lowerTable][$key->columns[0]] = $key->targetTable; + $structure['hasMany'][strtolower($key->targetTable)][$table][] = $key->columns[0]; } if (isset($structure['belongsTo'][$lowerTable])) { diff --git a/src/Database/Table/SqlBuilder.php b/src/Database/Table/SqlBuilder.php index f9875832c..e9040baa1 100644 --- a/src/Database/Table/SqlBuilder.php +++ b/src/Database/Table/SqlBuilder.php @@ -854,7 +854,7 @@ private function getConditionHash($condition, array $parameters): string private function getCachedTableList(): array { if (!$this->cacheTableList) { - $this->cacheTableList = array_flip(array_map(fn(array $pair): string => $pair['fullName'] ?? $pair['name'], $this->structure->getTables())); + $this->cacheTableList = array_flip(array_map(fn($pair): string => $pair->fullName ?? $pair->name, $this->structure->getTables())); } return $this->cacheTableList; diff --git a/tests/Database/Explorer/SqlBuilder.parseJoins().phpt b/tests/Database/Explorer/SqlBuilder.parseJoins().phpt index d437e231b..2127e1cfa 100644 --- a/tests/Database/Explorer/SqlBuilder.parseJoins().phpt +++ b/tests/Database/Explorer/SqlBuilder.parseJoins().phpt @@ -43,7 +43,7 @@ $join = $sqlBuilder->buildQueryJoins($joins); Assert::same('WHERE priorit.id IS NULL', $query); $tables = $connection->getDriver()->getTables(); -if (!in_array($tables[0]['name'], ['npriorities', 'ntopics', 'nusers', 'nusers_ntopics', 'nusers_ntopics_alt'], true)) { +if (!in_array($tables[0]->name, ['npriorities', 'ntopics', 'nusers', 'nusers_ntopics', 'nusers_ntopics_alt'], true)) { if ($driver->isSupported(Driver::SupportSchema)) { Assert::same( 'LEFT JOIN public.nUsers_nTopics nusers_ntopics ON nUsers.nUserId = nusers_ntopics.nUserId ' . diff --git a/tests/Database/Explorer/bugs/view.bug.phpt b/tests/Database/Explorer/bugs/view.bug.phpt index 18f18259d..0ce78920a 100644 --- a/tests/Database/Explorer/bugs/view.bug.phpt +++ b/tests/Database/Explorer/bugs/view.bug.phpt @@ -22,7 +22,7 @@ test('', function () use ($explorer) { test('', function () use ($connection) { $driver = $connection->getDriver(); $columns = $driver->getColumns('books_view'); - $columnsNames = array_map(fn($item) => $item['name'], $columns); + $columnsNames = array_map(fn($item) => $item->name, $columns); Assert::same(['id', 'author_id', 'translator_id', 'title', 'next_volume'], $columnsNames); }); diff --git a/tests/Database/Reflection.phpt b/tests/Database/Reflection.phpt index 78c6d4623..40ed2a61a 100644 --- a/tests/Database/Reflection.phpt +++ b/tests/Database/Reflection.phpt @@ -8,6 +8,9 @@ declare(strict_types=1); use Nette\Database\Driver; +use Nette\Database\Reflection\Column; +use Nette\Database\Reflection\Index; +use Nette\Database\Reflection\Table; use Tester\Assert; require __DIR__ . '/connect.inc.php'; // create $connection @@ -17,74 +20,73 @@ Nette\Database\Helpers::loadFromFile($connection, __DIR__ . "/files/{$driverName $driver = $connection->getDriver(); $tables = $driver->getTables(); -$tables = array_filter($tables, fn($t) => in_array($t['name'], ['author', 'book', 'book_tag', 'tag'], true)); -usort($tables, fn($a, $b) => strcmp($a['name'], $b['name'])); +$tables = array_filter($tables, fn($t) => in_array($t->name, ['author', 'book', 'book_tag', 'tag'], true)); +usort($tables, fn($a, $b) => strcmp($a->name, $b->name)); if ($driver->isSupported(Driver::SupportSchema)) { - Assert::same( + Assert::equal( [ - ['name' => 'author', 'view' => false, 'fullName' => 'public.author'], - ['name' => 'book', 'view' => false, 'fullName' => 'public.book'], - ['name' => 'book_tag', 'view' => false, 'fullName' => 'public.book_tag'], - ['name' => 'tag', 'view' => false, 'fullName' => 'public.tag'], + new Table(name: 'author', view: false, fullName: 'public.author'), + new Table(name: 'book', view: false, fullName: 'public.book'), + new Table(name: 'book_tag', view: false, fullName: 'public.book_tag'), + new Table(name: 'tag', view: false, fullName: 'public.tag'), ], $tables, ); } else { - Assert::same([ - ['name' => 'author', 'view' => false], - ['name' => 'book', 'view' => false], - ['name' => 'book_tag', 'view' => false], - ['name' => 'tag', 'view' => false], + Assert::equal([ + new Table(name: 'author', view: false), + new Table(name: 'book', view: false), + new Table(name: 'book_tag', view: false), + new Table(name: 'tag', view: false), ], $tables); } $columns = $driver->getColumns('author'); array_walk($columns, function (&$item) { - Assert::type('array', $item['vendor']); - unset($item['vendor']); + $item->vendor = []; }); $expectedColumns = [ [ 'name' => 'id', 'table' => 'author', - 'nativetype' => 'int', + 'nativeType' => 'int', 'size' => 11, 'nullable' => false, 'default' => null, - 'autoincrement' => true, + 'autoIncrement' => true, 'primary' => true, ], [ 'name' => 'name', 'table' => 'author', - 'nativetype' => 'varchar', + 'nativeType' => 'varchar', 'size' => 30, 'nullable' => false, 'default' => null, - 'autoincrement' => false, + 'autoIncrement' => false, 'primary' => false, ], [ 'name' => 'web', 'table' => 'author', - 'nativetype' => 'varchar', + 'nativeType' => 'varchar', 'size' => 100, 'nullable' => false, 'default' => null, - 'autoincrement' => false, + 'autoIncrement' => false, 'primary' => false, ], [ 'name' => 'born', 'table' => 'author', - 'nativetype' => 'date', + 'nativeType' => 'date', 'size' => null, 'nullable' => true, 'default' => null, - 'autoincrement' => false, + 'autoIncrement' => false, 'primary' => false, ], ]; @@ -97,18 +99,18 @@ switch ($driverName) { } break; case 'pgsql': - $expectedColumns[0]['nativetype'] = 'int4'; + $expectedColumns[0]['nativeType'] = 'int4'; $expectedColumns[0]['default'] = "nextval('author_id_seq'::regclass)"; $expectedColumns[0]['size'] = null; break; case 'sqlite': - $expectedColumns[0]['nativetype'] = 'INTEGER'; + $expectedColumns[0]['nativeType'] = 'INTEGER'; $expectedColumns[0]['size'] = null; - $expectedColumns[1]['nativetype'] = 'TEXT'; + $expectedColumns[1]['nativeType'] = 'TEXT'; $expectedColumns[1]['size'] = null; - $expectedColumns[2]['nativetype'] = 'TEXT'; + $expectedColumns[2]['nativeType'] = 'TEXT'; $expectedColumns[2]['size'] = null; - $expectedColumns[3]['nativetype'] = 'DATE'; + $expectedColumns[3]['nativeType'] = 'DATE'; break; case 'sqlsrv': $expectedColumns[0]['size'] = null; @@ -119,69 +121,70 @@ switch ($driverName) { Assert::fail("Unsupported driver $driverName"); } -Assert::same($expectedColumns, $columns); +$expectedColumns = array_map(fn($data) => new Column(...$data), $expectedColumns); +Assert::equal($expectedColumns, $columns); $indexes = $driver->getIndexes('book_tag'); switch ($driverName) { case 'pgsql': - Assert::same([ - [ - 'name' => 'book_tag_pkey', - 'unique' => true, - 'primary' => true, - 'columns' => [ + Assert::equal([ + new Index( + name: 'book_tag_pkey', + unique: true, + primary: true, + columns: [ 'book_id', 'tag_id', ], - ], + ), ], $indexes); break; case 'sqlite': - Assert::same([ - [ - 'name' => 'sqlite_autoindex_book_tag_1', - 'unique' => true, - 'primary' => true, - 'columns' => [ + Assert::equal([ + new Index( + name: 'sqlite_autoindex_book_tag_1', + unique: true, + primary: true, + columns: [ 'book_id', 'tag_id', ], - ], + ), ], $indexes); break; case 'sqlsrv': - Assert::same([ - [ - 'name' => 'PK_book_tag', - 'unique' => true, - 'primary' => true, - 'columns' => [ + Assert::equal([ + new Index( + name: 'PK_book_tag', + unique: true, + primary: true, + columns: [ 'book_id', 'tag_id', ], - ], + ), ], $indexes); break; case 'mysql': - Assert::same([ - [ - 'name' => 'PRIMARY', - 'unique' => true, - 'primary' => true, - 'columns' => [ + Assert::equal([ + new Index( + name: 'PRIMARY', + unique: true, + primary: true, + columns: [ 'book_id', 'tag_id', ], - ], - [ - 'name' => 'book_tag_tag', - 'unique' => false, - 'primary' => false, - 'columns' => [ + ), + new Index( + name: 'book_tag_tag', + unique: false, + primary: false, + columns: [ 'tag_id', ], - ], + ), ], $indexes); break; default: diff --git a/tests/Database/Reflection.postgre.10.phpt b/tests/Database/Reflection.postgre.10.phpt index b2b0cd3f9..b11263765 100644 --- a/tests/Database/Reflection.postgre.10.phpt +++ b/tests/Database/Reflection.postgre.10.phpt @@ -7,6 +7,9 @@ declare(strict_types=1); +use Nette\Database\Reflection\Column; +use Nette\Database\Reflection\Index; +use Nette\Database\Reflection\Table; use Tester\Assert; use Tester\Environment; @@ -21,10 +24,10 @@ if (version_compare($ver, '10') < 0) { function shortInfo(array $columns): array { - return array_map(fn(array $col): array => [ - 'name' => $col['name'], - 'autoincrement' => $col['autoincrement'], - 'sequence' => $col['vendor']['sequence'], + return array_map(fn(Column $col): array => [ + 'name' => $col->name, + 'autoincrement' => $col->autoIncrement, + 'sequence' => $col->vendor['sequence'], ], $columns); } @@ -114,9 +117,9 @@ test('Materialized view columns', function () use ($connection) { $connection->query('SET search_path TO reflection_10'); - Assert::same([ - ['name' => 'source', 'view' => false, 'fullName' => 'reflection_10.source'], - ['name' => 'source_mt', 'view' => true, 'fullName' => 'reflection_10.source_mt'], + Assert::equal([ + new Table(name: 'source', view: false, fullName: 'reflection_10.source'), + new Table(name: 'source_mt', view: true, fullName: 'reflection_10.source_mt'), ], $driver->getTables()); Assert::same( @@ -143,18 +146,18 @@ test('Partitioned table', function () use ($connection) { $connection->query('SET search_path TO reflection_10'); - Assert::same([ - ['name' => 'part_1', 'view' => false, 'fullName' => 'reflection_10.part_1'], - ['name' => 'parted', 'view' => false, 'fullName' => 'reflection_10.parted'], + Assert::equal([ + new Table(name: 'part_1', view: false, fullName: 'reflection_10.part_1'), + new Table(name: 'parted', view: false, fullName: 'reflection_10.parted'), ], $driver->getTables()); Assert::same(['id', 'value'], array_column($driver->getColumns('parted'), 'name')); Assert::same(['id', 'value'], array_column($driver->getColumns('part_1'), 'name')); - Assert::same([[ - 'name' => 'parted_pkey', - 'unique' => true, - 'primary' => true, - 'columns' => ['id'], - ]], $driver->getIndexes('parted')); + Assert::equal([new Index( + name: 'parted_pkey', + unique: true, + primary: true, + columns: ['id'], + )], $driver->getIndexes('parted')); }); diff --git a/tests/Database/Reflection.postgre.phpt b/tests/Database/Reflection.postgre.phpt index ab58272e5..187e916ad 100644 --- a/tests/Database/Reflection.postgre.phpt +++ b/tests/Database/Reflection.postgre.phpt @@ -7,6 +7,7 @@ declare(strict_types=1); +use Nette\Database\Reflection\ForeignKey; use Tester\Assert; require __DIR__ . '/connect.inc.php'; // create $connection @@ -61,12 +62,12 @@ test('Tables in schema', function () use ($connection) { Assert::same(['one_id'], names($driver->getColumns('one.master'))); Assert::same(['one_master_pkey'], names($driver->getIndexes('one.master'))); $foreign = $driver->getForeignKeys('one.slave'); - Assert::same([ - 'name' => 'one_slave_fk', - 'local' => ['one_id'], - 'table' => 'one.master', - 'foreign' => ['one_id'], - ], (array) $foreign[0]); + Assert::equal(new ForeignKey( + name: 'one_slave_fk', + columns: ['one_id'], + targetTable: 'one.master', + targetColumns: ['one_id'], + ), $foreign[0]); // Limit foreign keys for current schemas only diff --git a/tests/Database/Structure.phpt b/tests/Database/Structure.phpt index 10a94c995..38a7a6b57 100644 --- a/tests/Database/Structure.phpt +++ b/tests/Database/Structure.phpt @@ -7,6 +7,9 @@ declare(strict_types=1); use Mockery\MockInterface; +use Nette\Database\Reflection\Column; +use Nette\Database\Reflection\ForeignKey; +use Nette\Database\Reflection\Table; use Nette\Database\Structure; use Tester\Assert; use Tester\TestCase; @@ -49,42 +52,42 @@ class StructureTestCase extends TestCase $this->connection->shouldReceive('getDsn')->once()->andReturn(''); $this->connection->shouldReceive('getDriver')->once()->andReturn($this->driver); $this->driver->shouldReceive('getTables')->once()->andReturn([ - ['name' => 'authors', 'view' => false], - ['name' => 'Books', 'view' => false], - ['name' => 'tags', 'view' => false], - ['name' => 'books_x_tags', 'view' => false], - ['name' => 'books_view', 'view' => true], + new Table(name: 'authors', view: false), + new Table(name: 'Books', view: false), + new Table(name: 'tags', view: false), + new Table(name: 'books_x_tags', view: false), + new Table(name: 'books_view', view: true), ]); $this->driver->shouldReceive('getColumns')->with('authors')->once()->andReturn([ - ['name' => 'id', 'primary' => true, 'autoincrement' => true, 'vendor' => ['sequence' => '"public"."authors_id_seq"']], - ['name' => 'name', 'primary' => false, 'autoincrement' => false, 'vendor' => []], + new Column(name: 'id', primary: true, autoIncrement: true, vendor: ['sequence' => '"public"."authors_id_seq"']), + new Column(name: 'name', primary: false, autoIncrement: false, vendor: []), ]); $this->driver->shouldReceive('getColumns')->with('Books')->once()->andReturn([ - ['name' => 'id', 'primary' => true, 'autoincrement' => true, 'vendor' => ['sequence' => '"public"."Books_id_seq"']], - ['name' => 'title', 'primary' => false, 'autoincrement' => false, 'vendor' => []], + new Column(name: 'id', primary: true, autoIncrement: true, vendor: ['sequence' => '"public"."Books_id_seq"']), + new Column(name: 'title', primary: false, autoIncrement: false, vendor: []), ]); $this->driver->shouldReceive('getColumns')->with('tags')->once()->andReturn([ - ['name' => 'id', 'primary' => true, 'autoincrement' => false, 'vendor' => []], - ['name' => 'name', 'primary' => false, 'autoincrement' => false, 'vendor' => []], + new Column(name: 'id', primary: true, autoIncrement: false, vendor: []), + new Column(name: 'name', primary: false, autoIncrement: false, vendor: []), ]); $this->driver->shouldReceive('getColumns')->with('books_x_tags')->once()->andReturn([ - ['name' => 'book_id', 'primary' => true, 'autoincrement' => false, 'vendor' => []], - ['name' => 'tag_id', 'primary' => true, 'autoincrement' => false, 'vendor' => []], + new Column(name: 'book_id', primary: true, autoIncrement: false, vendor: []), + new Column(name: 'tag_id', primary: true, autoIncrement: false, vendor: []), ]); $this->driver->shouldReceive('getColumns')->with('books_view')->once()->andReturn([ - ['name' => 'id', 'primary' => false, 'autoincrement' => false, 'vendor' => []], - ['name' => 'title', 'primary' => false, 'autoincrement' => false, 'vendor' => []], + new Column(name: 'id', primary: false, autoIncrement: false, vendor: []), + new Column(name: 'title', primary: false, autoIncrement: false, vendor: []), ]); $this->connection->shouldReceive('getDriver')->times(4)->andReturn($this->driver); $this->driver->shouldReceive('getForeignKeys')->with('authors')->once()->andReturn([]); $this->driver->shouldReceive('getForeignKeys')->with('Books')->once()->andReturn([ - ['local' => ['author_id'], 'table' => 'authors', 'foreign' => ['id'], 'name' => 'authors_fk1'], - ['local' => ['translator_id'], 'table' => 'authors', 'foreign' => ['id'], 'name' => 'authors_fk2'], + new ForeignKey(columns: ['author_id'], targetTable: 'authors', targetColumns: ['id'], name: 'authors_fk1'), + new ForeignKey(columns: ['translator_id'], targetTable: 'authors', targetColumns: ['id'], name: 'authors_fk2'), ]); $this->driver->shouldReceive('getForeignKeys')->with('tags')->once()->andReturn([]); $this->driver->shouldReceive('getForeignKeys')->with('books_x_tags')->once()->andReturn([ - ['local' => ['book_id'], 'table' => 'Books', 'foreign' => ['id'], 'name' => 'books_x_tags_fk1'], - ['local' => ['tag_id'], 'table' => 'tags', 'foreign' => ['id'], 'name' => 'books_x_tags_fk2'], + new ForeignKey(columns: ['book_id'], targetTable: 'Books', targetColumns: ['id'], name: 'books_x_tags_fk1'), + new ForeignKey(columns: ['tag_id'], targetTable: 'tags', targetColumns: ['id'], name: 'books_x_tags_fk2'), ]); $this->structure = new StructureMock($this->connection, $this->storage); @@ -93,12 +96,12 @@ class StructureTestCase extends TestCase public function testGetTables() { - Assert::same([ - ['name' => 'authors', 'view' => false], - ['name' => 'Books', 'view' => false], - ['name' => 'tags', 'view' => false], - ['name' => 'books_x_tags', 'view' => false], - ['name' => 'books_view', 'view' => true], + Assert::equal([ + new Table(name: 'authors', view: false), + new Table(name: 'Books', view: false), + new Table(name: 'tags', view: false), + new Table(name: 'books_x_tags', view: false), + new Table(name: 'books_view', view: true), ], $this->structure->getTables()); } @@ -106,12 +109,12 @@ class StructureTestCase extends TestCase public function testGetColumns() { $columns = [ - ['name' => 'id', 'primary' => true, 'autoincrement' => false, 'vendor' => []], - ['name' => 'name', 'primary' => false, 'autoincrement' => false, 'vendor' => []], + new Column(name: 'id', primary: true, autoIncrement: false, vendor: []), + new Column(name: 'name', primary: false, autoIncrement: false, vendor: []), ]; - Assert::same($columns, $this->structure->getColumns('tags')); - Assert::same($columns, $this->structure->getColumns('Tags')); + Assert::equal($columns, $this->structure->getColumns('tags')); + Assert::equal($columns, $this->structure->getColumns('Tags')); $structure = $this->structure; Assert::exception( diff --git a/tests/Database/Structure.schemas.phpt b/tests/Database/Structure.schemas.phpt index 5c9cabe46..077a18875 100644 --- a/tests/Database/Structure.schemas.phpt +++ b/tests/Database/Structure.schemas.phpt @@ -7,6 +7,9 @@ declare(strict_types=1); use Mockery\MockInterface; +use Nette\Database\Reflection\Column; +use Nette\Database\Reflection\ForeignKey; +use Nette\Database\Reflection\Table; use Nette\Database\Structure; use Tester\Assert; use Tester\TestCase; @@ -49,23 +52,23 @@ class StructureSchemasTestCase extends TestCase $this->connection->shouldReceive('getDsn')->once()->andReturn(''); $this->connection->shouldReceive('getDriver')->once()->andReturn($this->driver); $this->driver->shouldReceive('getTables')->once()->andReturn([ - ['name' => 'authors', 'view' => false, 'fullName' => 'authors.authors'], - ['name' => 'books', 'view' => false, 'fullName' => 'books.books'], + new Table(name: 'authors', view: false, fullName: 'authors.authors'), + new Table(name: 'books', view: false, fullName: 'books.books'), ]); $this->driver->shouldReceive('getColumns')->with('authors.authors')->once()->andReturn([ - ['name' => 'id', 'primary' => true, 'vendor' => ['sequence' => '"authors"."authors_id_seq"']], - ['name' => 'name', 'primary' => false, 'vendor' => []], + new Column(name: 'id', primary: true, vendor: ['sequence' => '"authors"."authors_id_seq"']), + new Column(name: 'name', primary: false, vendor: []), ]); $this->driver->shouldReceive('getColumns')->with('books.books')->once()->andReturn([ - ['name' => 'id', 'primary' => true, 'vendor' => ['sequence' => '"books"."books_id_seq"']], - ['name' => 'title', 'primary' => false, 'vendor' => []], + new Column(name: 'id', primary: true, vendor: ['sequence' => '"books"."books_id_seq"']), + new Column(name: 'title', primary: false, vendor: []), ]); $this->connection->shouldReceive('getDriver')->times(2)->andReturn($this->driver); $this->driver->shouldReceive('getForeignKeys')->with('authors.authors')->once()->andReturn([]); $this->driver->shouldReceive('getForeignKeys')->with('books.books')->once()->andReturn([ - ['local' => ['author_id'], 'table' => 'authors.authors', 'foreign' => ['id'], 'name' => 'authors_authors_fk1'], - ['local' => ['translator_id'], 'table' => 'authors.authors', 'foreign' => ['id'], 'name' => 'authors_authors_fk2'], + new ForeignKey(columns: ['author_id'], targetTable: 'authors.authors', targetColumns: ['id'], name: 'authors_authors_fk1'), + new ForeignKey(columns: ['translator_id'], targetTable: 'authors.authors', targetColumns: ['id'], name: 'authors_authors_fk2'), ]); $this->structure = new StructureMock($this->connection, $this->storage);