diff --git a/CHANGELOG.md b/CHANGELOG.md index c61ed9e..032565f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ - New #323: Use `DateTimeColumn` class for datetime column types (@Tigrov) - Enh #324: Refactor `Command::insertWithReturningPks()` method (@Tigrov) - Chg #326: Add alias in `DQLQueryBuilder::selectExists()` method for consistency with other DBMS (@Tigrov) +- Enh #327: Refactor constraints (@Tigrov) ## 1.3.0 March 21, 2024 diff --git a/src/DMLQueryBuilder.php b/src/DMLQueryBuilder.php index b5f8aad..878a91f 100644 --- a/src/DMLQueryBuilder.php +++ b/src/DMLQueryBuilder.php @@ -80,9 +80,9 @@ public function upsert( $quotedTableName = $this->quoter->quoteTableName($table); foreach ($constraints as $constraint) { - $columnNames = (array) $constraint->getColumnNames(); + $columnNames = $constraint->getColumnNames(); $constraintCondition = ['and']; - /** @psalm-var string[] $columnNames */ + foreach ($columnNames as $name) { $quotedName = $this->quoter->quoteColumnName($name); $constraintCondition[] = "$quotedTableName.$quotedName=\"EXCLUDED\".$quotedName"; diff --git a/src/Schema.php b/src/Schema.php index 5b4e9ae..490d3bf 100644 --- a/src/Schema.php +++ b/src/Schema.php @@ -4,18 +4,14 @@ namespace Yiisoft\Db\Oracle; -use Throwable; use Yiisoft\Db\Cache\SchemaCache; use Yiisoft\Db\Connection\ConnectionInterface; use Yiisoft\Db\Constant\ColumnType; use Yiisoft\Db\Constant\ReferentialAction; use Yiisoft\Db\Constraint\CheckConstraint; -use Yiisoft\Db\Constraint\Constraint; use Yiisoft\Db\Constraint\ForeignKeyConstraint; use Yiisoft\Db\Constraint\IndexConstraint; use Yiisoft\Db\Driver\Pdo\AbstractPdoSchema; -use Yiisoft\Db\Exception\Exception; -use Yiisoft\Db\Exception\InvalidConfigException; use Yiisoft\Db\Exception\NotSupportedException; use Yiisoft\Db\Helper\DbArrayHelper; use Yiisoft\Db\Schema\Column\ColumnInterface; @@ -27,7 +23,6 @@ use function array_reverse; use function implode; use function in_array; -use function is_array; use function preg_replace; use function strtolower; @@ -55,9 +50,9 @@ * name: string, * column_name: string, * type: string, - * foreign_table_schema: string|null, - * foreign_table_name: string|null, - * foreign_column_name: string|null, + * foreign_table_schema: string, + * foreign_table_name: string, + * foreign_column_name: string, * on_delete: ReferentialAction::*, * check_expr: string * } @@ -92,11 +87,6 @@ protected function resolveTableName(string $name): TableSchemaInterface /** * @link https://docs.oracle.com/cd/B28359_01/server.111/b28337/tdpsg_user_accounts.htm - * - * @throws Exception - * @throws InvalidConfigException - * @throws NotSupportedException - * @throws Throwable */ protected function findSchemaNames(): array { @@ -107,14 +97,10 @@ protected function findSchemaNames(): array ORDER BY "u"."USERNAME" ASC SQL; + /** @var string[] */ return $this->db->createCommand($sql)->queryColumn(); } - /** - * @throws Exception - * @throws InvalidConfigException - * @throws Throwable - */ protected function findTableComment(TableSchemaInterface $tableSchema): void { $sql = <<comment(is_string($comment) ? $comment : null); } - /** - * @throws Exception - * @throws InvalidConfigException - * @throws Throwable - */ protected function findTableNames(string $schema = ''): array { if ($schema === '') { @@ -156,7 +137,7 @@ protected function findTableNames(string $schema = ''): array $command = $this->db->createCommand($sql); } else { $sql = <<db->createCommand($sql, [':schema' => $schema]); } - $rows = $command->queryAll(); - $names = []; - - /** @psalm-var string[][] $rows */ - foreach ($rows as $row) { - /** @psalm-var string[] $row */ - $row = array_change_key_case($row); - $names[] = $row['table_name']; - } - - return $names; + /** @var string[] */ + return $command->queryColumn(); } /** @@ -245,11 +217,6 @@ protected function loadResultColumn(array $metadata): ColumnInterface|null return $this->db->getColumnFactory()->fromDbType($dbType, $columnInfo); } - /** - * @throws Exception - * @throws InvalidConfigException - * @throws Throwable - */ protected function loadTableSchema(string $name): TableSchemaInterface|null { $table = $this->resolveTableName($name); @@ -263,44 +230,24 @@ protected function loadTableSchema(string $name): TableSchemaInterface|null return null; } - /** - * @throws Exception - * @throws InvalidConfigException - * @throws NotSupportedException - * @throws Throwable - */ - protected function loadTablePrimaryKey(string $tableName): Constraint|null + protected function loadTablePrimaryKey(string $tableName): IndexConstraint|null { - /** @psalm-var mixed $tablePrimaryKey */ - $tablePrimaryKey = $this->loadTableConstraints($tableName, self::PRIMARY_KEY); - return $tablePrimaryKey instanceof Constraint ? $tablePrimaryKey : null; + /** @var IndexConstraint|null */ + return $this->loadTableConstraints($tableName, self::PRIMARY_KEY); } - /** - * @throws Exception - * @throws InvalidConfigException - * @throws NotSupportedException - * @throws Throwable - */ protected function loadTableForeignKeys(string $tableName): array { - /** @psalm-var mixed $tableForeignKeys */ - $tableForeignKeys = $this->loadTableConstraints($tableName, self::FOREIGN_KEYS); - return is_array($tableForeignKeys) ? $tableForeignKeys : []; + /** @var ForeignKeyConstraint[] */ + return $this->loadTableConstraints($tableName, self::FOREIGN_KEYS); } - /** - * @throws Exception - * @throws InvalidConfigException - * @throws NotSupportedException - * @throws Throwable - */ protected function loadTableIndexes(string $tableName): array { $sql = <<primary((bool) $index[0]['index_is_primary']) - ->unique((bool) $index[0]['index_is_unique']) - ->name($name) - ->columnNames($columnNames); + /** @var string[] $columnNames */ + $result[] = new IndexConstraint( + $name, + $columnNames, + (bool) $index[0]['is_unique'], + (bool) $index[0]['is_primary_key'], + ); } return $result; } - /** - * @throws Exception - * @throws InvalidConfigException - * @throws NotSupportedException - * @throws Throwable - */ protected function loadTableUniques(string $tableName): array { - /** @psalm-var mixed $tableUniques */ - $tableUniques = $this->loadTableConstraints($tableName, self::UNIQUES); - return is_array($tableUniques) ? $tableUniques : []; + /** @var IndexConstraint[] */ + return $this->loadTableConstraints($tableName, self::UNIQUES); } - /** - * @throws Exception - * @throws InvalidConfigException - * @throws NotSupportedException - * @throws Throwable - */ protected function loadTableChecks(string $tableName): array { - /** @psalm-var mixed $tableCheck */ - $tableCheck = $this->loadTableConstraints($tableName, self::CHECKS); - return is_array($tableCheck) ? $tableCheck : []; + /** @var CheckConstraint[] */ + return $this->loadTableConstraints($tableName, self::CHECKS); } /** @@ -381,9 +316,6 @@ protected function loadTableDefaultValues(string $tableName): array * * @param TableSchemaInterface $table The table schema. * - * @throws Exception - * @throws Throwable - * * @return bool Whether the table exists. */ protected function findColumns(TableSchemaInterface $table): bool @@ -471,10 +403,6 @@ protected function findColumns(TableSchemaInterface $table): bool /** * Sequence name of table. * - * @throws Exception - * @throws InvalidConfigException - * @throws Throwable - * * @return string|null Whether the sequence exists. * * @internal TableSchemaInterface `$table->getName()` The table schema. @@ -546,10 +474,6 @@ private function loadColumn(array $info): ColumnInterface /** * Finds constraints and fills them into TableSchemaInterface object passed. * - * @throws Exception - * @throws InvalidConfigException - * @throws Throwable - * * @psalm-suppress PossiblyNullArrayOffset */ protected function findConstraints(TableSchemaInterface $table): void @@ -635,26 +559,6 @@ protected function findConstraints(TableSchemaInterface $table): void } } - /** - * Returns all unique indexes for the given table. - * - * Each array element is of the following structure:. - * - * ```php - * [ - * 'IndexName1' => ['col1' [, ...]], - * 'IndexName2' => ['col2' [, ...]], - * ] - * ``` - * - * @param TableSchemaInterface $table The table metadata. - * - * @throws Exception - * @throws InvalidConfigException - * @throws Throwable - * - * @return array All unique indexes for the given table. - */ public function findUniqueIndexes(TableSchemaInterface $table): array { $query = << $constraint) { switch ($type) { case 'P': - $result[self::PRIMARY_KEY] = (new Constraint()) - ->name($name) - ->columnNames(array_column($constraint, 'column_name')); + $result[self::PRIMARY_KEY] = new IndexConstraint( + $name, + array_column($constraint, 'column_name'), + true, + true, + ); break; case 'R': - $result[self::FOREIGN_KEYS][] = (new ForeignKeyConstraint()) - ->name($name) - ->columnNames(array_column($constraint, 'column_name')) - ->foreignSchemaName($constraint[0]['foreign_table_schema']) - ->foreignTableName($constraint[0]['foreign_table_name']) - ->foreignColumnNames(array_column($constraint, 'foreign_column_name')) - ->onDelete($constraint[0]['on_delete']) - ->onUpdate(null); + $result[self::FOREIGN_KEYS][] = new ForeignKeyConstraint( + $name, + array_column($constraint, 'column_name'), + $constraint[0]['foreign_table_schema'] . '.' . $constraint[0]['foreign_table_name'], + array_column($constraint, 'foreign_column_name'), + null, + $constraint[0]['on_delete'], + ); break; case 'U': - $result[self::UNIQUES][] = (new Constraint()) - ->name($name) - ->columnNames(array_column($constraint, 'column_name')); + $result[self::UNIQUES][] = new IndexConstraint( + $name, + array_column($constraint, 'column_name'), + true, + ); break; case 'C': - $result[self::CHECKS][] = (new CheckConstraint()) - ->name($name) - ->columnNames(array_column($constraint, 'column_name')) - ->expression($constraint[0]['check_expr']); + $result[self::CHECKS][] = new CheckConstraint( + $name, + array_column($constraint, 'column_name'), + $constraint[0]['check_expr'], + ); break; } } @@ -784,29 +689,14 @@ private function loadTableConstraints(string $tableName, string $returnType): mi return $result[$returnType]; } - /** - * @throws Exception - * @throws InvalidConfigException - * @throws Throwable - */ protected function findViewNames(string $schema = ''): array { $sql = match ($schema) { - '' => << << 'SELECT VIEW_NAME FROM USER_VIEWS', + default => "SELECT VIEW_NAME FROM ALL_VIEWS WHERE OWNER = '$schema'", }; - /** @psalm-var string[][] $views */ - $views = $this->db->createCommand($sql)->queryAll(); - - foreach ($views as $key => $view) { - $views[$key] = $view['VIEW_NAME']; - } - - return $views; + /** @var string[] */ + return $this->db->createCommand($sql)->queryColumn(); } } diff --git a/tests/CommandTest.php b/tests/CommandTest.php index 1241e1d..f3abfcd 100644 --- a/tests/CommandTest.php +++ b/tests/CommandTest.php @@ -632,12 +632,12 @@ public function testCreateSearchIndex() $this->assertSame(['col1'], $index->getColumnNames()); $this->assertFalse($index->isUnique()); - $this->assertFalse($index->isPrimary()); + $this->assertFalse($index->isPrimaryKey()); $sysIndex = $schema->getTableIndexes($tableName)[1]; $this->assertSame([], $sysIndex->getColumnNames()); $this->assertTrue($sysIndex->isUnique()); - $this->assertFalse($sysIndex->isPrimary()); + $this->assertFalse($sysIndex->isPrimaryKey()); $db->close(); } diff --git a/tests/Provider/SchemaProvider.php b/tests/Provider/SchemaProvider.php index 0580d16..91eb5cf 100644 --- a/tests/Provider/SchemaProvider.php +++ b/tests/Provider/SchemaProvider.php @@ -17,7 +17,6 @@ use Yiisoft\Db\Schema\Column\DoubleColumn; use Yiisoft\Db\Schema\Column\IntegerColumn; use Yiisoft\Db\Schema\Column\StringColumn; -use Yiisoft\Db\Tests\Support\AnyValue; final class SchemaProvider extends \Yiisoft\Db\Tests\Provider\SchemaProvider { @@ -177,56 +176,23 @@ public static function constraints(): array $constraints = parent::constraints(); $constraints['1: check'][2][0]->expression('"C_check" <> \'\''); - $constraints['1: check'][2][] = (new CheckConstraint()) - ->name(AnyValue::getInstance()) - ->columnNames(['C_id']) - ->expression('"C_id" IS NOT NULL'); - $constraints['1: check'][2][] = (new CheckConstraint()) - ->name(AnyValue::getInstance()) - ->columnNames(['C_not_null']) - ->expression('"C_not_null" IS NOT NULL'); - $constraints['1: check'][2][] = (new CheckConstraint()) - ->name(AnyValue::getInstance()) - ->columnNames(['C_unique']) - ->expression('"C_unique" IS NOT NULL'); - $constraints['1: check'][2][] = (new CheckConstraint()) - ->name(AnyValue::getInstance()) - ->columnNames(['C_default']) - ->expression('"C_default" IS NOT NULL'); + $constraints['1: check'][2][] = new CheckConstraint('', ['C_id'], '"C_id" IS NOT NULL'); + $constraints['1: check'][2][] = new CheckConstraint('', ['C_not_null'], '"C_not_null" IS NOT NULL'); + $constraints['1: check'][2][] = new CheckConstraint('', ['C_unique'], '"C_unique" IS NOT NULL'); + $constraints['1: check'][2][] = new CheckConstraint('', ['C_default'], '"C_default" IS NOT NULL'); - $constraints['2: check'][2][] = (new CheckConstraint()) - ->name(AnyValue::getInstance()) - ->columnNames(['C_id_1']) - ->expression('"C_id_1" IS NOT NULL'); - $constraints['2: check'][2][] = (new CheckConstraint()) - ->name(AnyValue::getInstance()) - ->columnNames(['C_id_2']) - ->expression('"C_id_2" IS NOT NULL'); + $constraints['2: check'][2][] = new CheckConstraint('', ['C_id_1'], '"C_id_1" IS NOT NULL'); + $constraints['2: check'][2][] = new CheckConstraint('', ['C_id_2'], '"C_id_2" IS NOT NULL'); - $constraints['3: foreign key'][2][0]->foreignSchemaName('SYSTEM'); + $constraints['3: foreign key'][2][0]->foreignTableName('SYSTEM.T_constraints_2'); $constraints['3: foreign key'][2][0]->onUpdate(null); $constraints['3: index'][2] = []; - $constraints['3: check'][2][] = (new CheckConstraint()) - ->name(AnyValue::getInstance()) - ->columnNames(['C_fk_id_1']) - ->expression('"C_fk_id_1" IS NOT NULL'); - $constraints['3: check'][2][] = (new CheckConstraint()) - ->name(AnyValue::getInstance()) - ->columnNames(['C_fk_id_2']) - ->expression('"C_fk_id_2" IS NOT NULL'); - $constraints['3: check'][2][] = (new CheckConstraint()) - ->name(AnyValue::getInstance()) - ->columnNames(['C_id']) - ->expression('"C_id" IS NOT NULL'); + $constraints['3: check'][2][] = new CheckConstraint('', ['C_fk_id_1'], '"C_fk_id_1" IS NOT NULL'); + $constraints['3: check'][2][] = new CheckConstraint('', ['C_fk_id_2'], '"C_fk_id_2" IS NOT NULL'); + $constraints['3: check'][2][] = new CheckConstraint('', ['C_id'], '"C_id" IS NOT NULL'); - $constraints['4: check'][2][] = (new CheckConstraint()) - ->name(AnyValue::getInstance()) - ->columnNames(['C_id']) - ->expression('"C_id" IS NOT NULL'); - $constraints['4: check'][2][] = (new CheckConstraint()) - ->name(AnyValue::getInstance()) - ->columnNames(['C_col_2']) - ->expression('"C_col_2" IS NOT NULL'); + $constraints['4: check'][2][] = new CheckConstraint('', ['C_id'], '"C_id" IS NOT NULL'); + $constraints['4: check'][2][] = new CheckConstraint('', ['C_col_2'], '"C_col_2" IS NOT NULL'); return $constraints; }