Skip to content

Update according changes in db package #348

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
- Enh #336: Provide `yiisoft/db-implementation` virtual package (@vjik)
- Enh #340: Adapt to `Param` refactoring in `yiisoft/db` package (@vjik)
- Enh #341, #342, #345: Adapt to conditions refactoring in `yiisoft/db` package (@vjik)
- Enh #348: Remove `TableSchema` class and refactor `Schema` class (@Tigrov)

## 1.3.0 March 21, 2024

Expand Down
1 change: 1 addition & 0 deletions src/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Query\QueryInterface;
use Yiisoft\Db\QueryBuilder\AbstractQueryBuilder;
use Yiisoft\Db\Schema\TableSchema;

use function array_keys;
use function array_map;
Expand Down
230 changes: 36 additions & 194 deletions src/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Helper\DbArrayHelper;
use Yiisoft\Db\Schema\Column\ColumnInterface;
use Yiisoft\Db\Schema\SchemaInterface;
use Yiisoft\Db\Schema\TableSchema;
use Yiisoft\Db\Schema\TableSchemaInterface;

use function array_change_key_case;
use function array_column;
use function array_map;
use function implode;
use function in_array;
use function preg_replace;
use function strtolower;
Expand Down Expand Up @@ -59,27 +60,19 @@
*/
final class Schema extends AbstractPdoSchema
{
public function __construct(protected ConnectionInterface $db, SchemaCache $schemaCache, string $defaultSchema)
protected function findConstraints(TableSchemaInterface $table): void
{
$this->defaultSchema = $defaultSchema;
parent::__construct($db, $schemaCache);
$tableName = $this->resolveFullName($table->getName(), $table->getSchemaName());

$table->checks(...$this->getTableMetadata($tableName, SchemaInterface::CHECKS));
$table->foreignKeys(...$this->getTableMetadata($tableName, SchemaInterface::FOREIGN_KEYS));
$table->indexes(...$this->getTableMetadata($tableName, SchemaInterface::INDEXES));
}

protected function resolveTableName(string $name): TableSchemaInterface
public function __construct(protected ConnectionInterface $db, SchemaCache $schemaCache, string $defaultSchema)
{
$resolvedName = new TableSchema();

$parts = $this->db->getQuoter()->getTableNameParts($name);

$resolvedName->name($parts['name']);
$resolvedName->schemaName($parts['schemaName'] ?? $this->defaultSchema);

$resolvedName->fullName(
$resolvedName->getSchemaName() !== $this->defaultSchema ?
implode('.', $parts) : $resolvedName->getName()
);

return $resolvedName;
$this->defaultSchema = $defaultSchema;
parent::__construct($db, $schemaCache);
}

/**
Expand Down Expand Up @@ -109,7 +102,7 @@ protected function findTableComment(TableSchemaInterface $tableSchema): void
SQL;

$comment = $this->db->createCommand($sql, [
':schemaName' => $tableSchema->getSchemaName(),
':schemaName' => $tableSchema->getSchemaName() ?: $this->defaultSchema,
':tableName' => $tableSchema->getName(),
])->queryScalar();

Expand Down Expand Up @@ -216,23 +209,19 @@ protected function loadResultColumn(array $metadata): ColumnInterface|null

protected function loadTableSchema(string $name): TableSchemaInterface|null
{
$table = $this->resolveTableName($name);
$this->findTableComment($table);
$table = new TableSchema(...$this->db->getQuoter()->getTableNameParts($name));

if ($this->findColumns($table)) {
$this->findTableComment($table);
$this->findConstraints($table);
$table->sequenceName($this->getTableSequenceName($table->getName()));

return $table;
}

return null;
}

protected function loadTablePrimaryKey(string $tableName): Index|null
{
/** @var Index|null */
return $this->loadTableConstraints($tableName, self::PRIMARY_KEY);
}

protected function loadTableForeignKeys(string $tableName): array
{
/** @var ForeignKey[] */
Expand Down Expand Up @@ -277,7 +266,7 @@ protected function loadTableIndexes(string $tableName): array
}

/** @var string[] $columnNames */
$result[] = new Index(
$result[$name] = new Index(
$name,
$columnNames,
(bool) $index[0]['is_unique'],
Expand All @@ -288,12 +277,6 @@ protected function loadTableIndexes(string $tableName): array
return $result;
}

protected function loadTableUniques(string $tableName): array
{
/** @var Index[] */
return $this->loadTableConstraints($tableName, self::UNIQUES);
}

protected function loadTableChecks(string $tableName): array
{
/** @var Check[] */
Expand All @@ -317,7 +300,7 @@ protected function loadTableDefaultValues(string $tableName): array
*/
protected function findColumns(TableSchemaInterface $table): bool
{
$schemaName = $table->getSchemaName();
$schemaName = $table->getSchemaName() ?: $this->defaultSchema;
$tableName = $table->getName();

$sql = <<<SQL
Expand Down Expand Up @@ -468,136 +451,17 @@ private function loadColumn(array $info): ColumnInterface
return $this->db->getColumnFactory()->fromDbType($dbType, $columnInfo);
}

/**
* Finds constraints and fills them into TableSchemaInterface object passed.
*
* @psalm-suppress PossiblyNullArrayOffset
*/
protected function findConstraints(TableSchemaInterface $table): void
{
$sql = <<<SQL
SELECT
/*+ PUSH_PRED(C) PUSH_PRED(D) PUSH_PRED(E) */
D.CONSTRAINT_NAME,
D.CONSTRAINT_TYPE,
C.COLUMN_NAME,
C.POSITION,
D.R_CONSTRAINT_NAME,
E.TABLE_NAME AS TABLE_REF,
F.COLUMN_NAME AS COLUMN_REF,
C.TABLE_NAME
FROM ALL_CONS_COLUMNS C
INNER JOIN ALL_CONSTRAINTS D ON D.OWNER = C.OWNER AND D.CONSTRAINT_NAME = C.CONSTRAINT_NAME
LEFT JOIN ALL_CONSTRAINTS E ON E.OWNER = D.R_OWNER AND E.CONSTRAINT_NAME = D.R_CONSTRAINT_NAME
LEFT JOIN ALL_CONS_COLUMNS F ON F.OWNER = E.OWNER AND F.CONSTRAINT_NAME = E.CONSTRAINT_NAME AND F.POSITION = C.POSITION
WHERE
C.OWNER = :schemaName
AND C.TABLE_NAME = :tableName
ORDER BY D.CONSTRAINT_NAME, C.POSITION
SQL;

/**
* @psalm-var array{
* array{
* constraint_name: string,
* constraint_type: string,
* column_name: string,
* position: string|null,
* r_constraint_name: string|null,
* table_ref: string|null,
* column_ref: string|null,
* table_name: string
* }
* } $rows
*/
$rows = $this->db->createCommand(
$sql,
[':tableName' => $table->getName(), ':schemaName' => $table->getSchemaName()]
)->queryAll();

$constraints = [];

foreach ($rows as $row) {
/** @psalm-var string[] $row */
$row = array_change_key_case($row);

if ($row['constraint_type'] === 'P') {
$table->getColumns()[$row['column_name']]->primaryKey(true);
$table->primaryKey($row['column_name']);

if (empty($table->getSequenceName())) {
$table->sequenceName($this->getTableSequenceName($table->getName()));
}
}

if ($row['constraint_type'] !== 'R') {
/**
* This condition isn't checked in `WHERE` because of an Oracle Bug:
*
* @link https://github.com/yiisoft/yii2/pull/8844
*/
continue;
}

$name = $row['constraint_name'];

if (!isset($constraints[$name])) {
$constraints[$name] = [
'tableName' => $row['table_ref'],
'columns' => [],
];
}

$constraints[$name]['columns'][$row['column_name']] = $row['column_ref'];
}

foreach ($constraints as $index => $constraint) {
$table->foreignKey($index, [$constraint['tableName'], ...$constraint['columns']]);
}
}

public function findUniqueIndexes(TableSchemaInterface $table): array
{
$query = <<<SQL
SELECT
DIC.INDEX_NAME,
DIC.COLUMN_NAME
FROM ALL_INDEXES DI
INNER JOIN ALL_IND_COLUMNS DIC ON DI.TABLE_NAME = DIC.TABLE_NAME AND DI.INDEX_NAME = DIC.INDEX_NAME
WHERE
DI.UNIQUENESS = 'UNIQUE'
AND DIC.TABLE_OWNER = :schemaName
AND DIC.TABLE_NAME = :tableName
ORDER BY DIC.TABLE_NAME, DIC.INDEX_NAME, DIC.COLUMN_POSITION
SQL;
$result = [];

$rows = $this->db->createCommand(
$query,
[':tableName' => $table->getName(), ':schemaName' => $table->getschemaName()]
)->queryAll();

/** @psalm-var array<array{INDEX_NAME: string, COLUMN_NAME: string}> $rows */
foreach ($rows as $row) {
$result[$row['INDEX_NAME']][] = $row['COLUMN_NAME'];
}

return $result;
}

/**
* Loads multiple types of constraints and returns the specified ones.
*
* @param string $tableName The table name.
* @param string $returnType The return type:
* - primaryKey
* - foreignKeys
* - uniques
* - checks
*
* @return Check[]|ForeignKey[]|Index|Index[]|null Constraints.
* @return Check[]|ForeignKey[] Constraints.
*/
private function loadTableConstraints(string $tableName, string $returnType): array|Index|null
private function loadTableConstraints(string $tableName, string $returnType): array
{
$sql = <<<SQL
SELECT
Expand All @@ -616,7 +480,7 @@ private function loadTableConstraints(string $tableName, string $returnType): ar
ON "fuc"."OWNER" = "uc"."R_OWNER" AND "fuc"."CONSTRAINT_NAME" = "uc"."R_CONSTRAINT_NAME"
LEFT JOIN "USER_CONS_COLUMNS" "fuccol"
ON "fuccol"."OWNER" = "fuc"."OWNER" AND "fuccol"."CONSTRAINT_NAME" = "fuc"."CONSTRAINT_NAME" AND "fuccol"."POSITION" = "uccol"."POSITION"
WHERE "uc"."OWNER" = :schemaName AND "uc"."TABLE_NAME" = :tableName
WHERE "uc"."OWNER" = :schemaName AND "uc"."TABLE_NAME" = :tableName AND "uc"."CONSTRAINT_TYPE" IN ('R', 'C')
ORDER BY "uccol"."POSITION" ASC
SQL;

Expand All @@ -630,9 +494,7 @@ private function loadTableConstraints(string $tableName, string $returnType): ar
$constraints = DbArrayHelper::arrange($constraints, ['type', 'name']);

$result = [
self::PRIMARY_KEY => null,
self::FOREIGN_KEYS => [],
self::UNIQUES => [],
self::CHECKS => [],
];

Expand All @@ -642,41 +504,21 @@ private function loadTableConstraints(string $tableName, string $returnType): ar
* @psalm-var ConstraintArray $constraint
*/
foreach ($names as $name => $constraint) {
switch ($type) {
case 'P':
$result[self::PRIMARY_KEY] = new Index(
$name,
array_column($constraint, 'column_name'),
true,
true,
);
break;
case 'R':
$result[self::FOREIGN_KEYS][] = new ForeignKey(
$name,
array_column($constraint, 'column_name'),
$constraint[0]['foreign_table_schema'],
$constraint[0]['foreign_table_name'],
array_column($constraint, 'foreign_column_name'),
$constraint[0]['on_delete'],
null,
);
break;
case 'U':
$result[self::UNIQUES][] = new Index(
$name,
array_column($constraint, 'column_name'),
true,
);
break;
case 'C':
$result[self::CHECKS][] = new Check(
$name,
array_column($constraint, 'column_name'),
$constraint[0]['check_expr'],
);
break;
}
match ($type) {
'R' => $result[self::FOREIGN_KEYS][$name] = new ForeignKey(
$name,
array_column($constraint, 'column_name'),
$constraint[0]['foreign_table_schema'],
$constraint[0]['foreign_table_name'],
array_column($constraint, 'foreign_column_name'),
$constraint[0]['on_delete'],
),
'C' => $result[self::CHECKS][$name] = new Check(
$name,
array_column($constraint, 'column_name'),
$constraint[0]['check_expr'],
),
};
}
}

Expand Down
18 changes: 0 additions & 18 deletions src/TableSchema.php

This file was deleted.

7 changes: 2 additions & 5 deletions tests/CommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -610,15 +610,12 @@ public function testCreateSearchIndex()
$command->createTable($tableName, ['col1' => ColumnBuilder::text()])->execute();
$command->createIndex($tableName, $indexName, ['col1'], IndexType::SEARCH)->execute();

$indexes = $schema->getTableIndexes($tableName);
Assert::setPropertyValue($indexes[1], 'name', '');

$this->assertEquals(
Assert::constraintsEquals(
[
new Index($indexName, ['col1']),
new Index('', [], true),
],
$indexes,
$schema->getTableIndexes($tableName),
);

$db->close();
Expand Down
Loading