Skip to content
Closed
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
25 changes: 12 additions & 13 deletions src/Quoter.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@
namespace Yiisoft\Db\Mssql;

use Yiisoft\Db\Schema\Quoter as BaseQuoter;
use Yiisoft\Db\Schema\QuoterInterface;

use function preg_match;
use function preg_match_all;
use function str_replace;

final class Quoter extends BaseQuoter implements QuoterInterface
final class Quoter extends BaseQuoter
{
/**
* @psalm-param string[] $columnQuoteCharacter
Expand All @@ -25,24 +24,24 @@ public function __construct(
parent::__construct($columnQuoteCharacter, $tableQuoteCharacter, $tablePrefix);
}

public function quoteColumnName(string $name): string
{
if (preg_match('/^\[.*]$/', $name)) {
return $name;
}

return parent::quoteColumnName($name);
}

protected function getTableNameParts(string $name): array
public function getTableNameParts(string $name): array
{
$parts = [$name];
preg_match_all('/([^.\[\]]+)|\[([^\[\]]+)]/', $name, $matches);

if (isset($matches[0]) && !empty($matches[0])) {
$parts = $matches[0];
$parts = array_slice($matches[0], -4, 4, true);
}

return str_replace(['[', ']'], '', $parts);
}

public function quoteColumnName(string $name): string
{
if (preg_match('/^\[.*]$/', $name)) {
return $name;
}

return parent::quoteColumnName($name);
}
}
136 changes: 37 additions & 99 deletions src/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use Throwable;
use Yiisoft\Arrays\ArrayHelper;
use Yiisoft\Db\Cache\SchemaCache;
use Yiisoft\Db\Connection\ConnectionInterface;
use Yiisoft\Db\Constraint\CheckConstraint;
use Yiisoft\Db\Constraint\Constraint;
Expand All @@ -18,19 +17,16 @@
use Yiisoft\Db\Schema\ColumnSchemaBuilder;
use Yiisoft\Db\Schema\ColumnSchemaInterface;
use Yiisoft\Db\Schema\Schema as AbstractSchema;
use Yiisoft\Db\Schema\TableNameInterface;
use Yiisoft\Db\Schema\TableSchemaInterface;

use function array_change_key_case;
use function array_map;
use function count;
use function explode;
use function is_array;
use function md5;
use function preg_match;
use function preg_match_all;
use function preg_replace;
use function serialize;
use function str_contains;
use function str_replace;
use function strcasecmp;
use function stripos;
Expand Down Expand Up @@ -128,88 +124,26 @@ final class Schema extends AbstractSchema
'table' => self::TYPE_STRING,
];

public function __construct(private ConnectionInterface $db, SchemaCache $schemaCache)
{
parent::__construct($schemaCache);
}

/**
* Resolves the table name and schema name (if any).
*
* @param string $name the table name.
* @param TableNameInterface $name the table name.
*
* @return TableSchemaInterface resolved table, schema, etc. names.
*
* @todo Review this method and see if it can be simplified @darkdef.
* also see case `wrongBehaviour` in \Yiisoft\Db\TestSupport\TestCommandTrait::batchInsertSqlProviderTrait
* @todo also see case `wrongBehaviour` in \Yiisoft\Db\TestSupport\TestCommandTrait::batchInsertSqlProviderTrait
*/
protected function resolveTableName(string $name): TableSchemaInterface
protected function resolveTableName(TableNameInterface $name): TableSchemaInterface
{
$resolvedName = new TableSchema();
$parts = $this->getTableNameParts($name);
$partCount = count($parts);

if ($partCount === 4) {
/** server name, catalog name, schema name and table name passed - not coverage tests */
$resolvedName->catalogName($parts[1]);
$resolvedName->schemaName($parts[2]);
$resolvedName->name($parts[3]);
$resolvedName->fullName(
(string) $resolvedName->getCatalogName() . '.' .
(string) $resolvedName->getSchemaName() . '.' .
$resolvedName->getName()
);
} elseif ($partCount === 3) {
/** catalog name, schema name and table name passed - not coverage tests */
$resolvedName->catalogName($parts[0]);
$resolvedName->schemaName($parts[1]);
$resolvedName->name($parts[2]);
$resolvedName->fullName(
(string) $resolvedName->getCatalogName() . '.' .
(string) $resolvedName->getSchemaName() . '.' .
$resolvedName->getName()
);
} elseif ($partCount === 2) {
/** only schema name and table name passed - not coverage tests */
$resolvedName->schemaName($parts[0]);
$resolvedName->name($parts[1]);
$resolvedName->fullName(
(
$resolvedName->getSchemaName() !== $this->defaultSchema
? (string) $resolvedName->getSchemaName() . '.' : ''
) . $resolvedName->getName()
);
} else {
/** only table name passed */
$resolvedName->schemaName($this->defaultSchema);
$resolvedName->name($parts[0]);
$resolvedName->fullName($resolvedName->getName());
}

return $resolvedName;
}
$resolvedName->serverName($name->getServerName());
$resolvedName->catalogName($name->getCatalogName());
$resolvedName->schemaName($name->getSchemaName() ?? $this->defaultSchema);
$resolvedName->name($name->getTableName());
$resolvedName->fullName((string) $name);

/**
* Splits full table name into parts.
*
* @param string $name
*
* @return array
*
* @psalm-return string[]
*/
protected function getTableNameParts(string $name): array
{
$parts = [$name];

preg_match_all('/([^.\[\]]+)|\[([^\[\]]+)]/', $name, $matches);

if (isset($matches[0]) && !empty($matches[0])) {
$parts = $matches[0];
}

/** @psalm-var string[] */
return str_replace(['[', ']'], '', $parts);
return $resolvedName;
}

/**
Expand Down Expand Up @@ -270,13 +204,13 @@ protected function findTableNames(string $schema = ''): array
/**
* Loads the metadata for the specified table.
*
* @param string $name table name.
* @param TableNameInterface $name table name.
*
* @throws Exception|InvalidConfigException|Throwable
*
* @return TableSchemaInterface|null DBMS-dependent table metadata, `null` if the table does not exist.
*/
protected function loadTableSchema(string $name): ?TableSchemaInterface
protected function loadTableSchema(TableNameInterface $name): ?TableSchemaInterface
{
$table = $this->resolveTableName($name);
$this->findPrimaryKeys($table);
Expand All @@ -292,13 +226,13 @@ protected function loadTableSchema(string $name): ?TableSchemaInterface
/**
* Loads a primary key for the given table.
*
* @param string $tableName table name.
* @param TableNameInterface $tableName table name.
*
* @throws Exception|InvalidConfigException|Throwable
*
* @return Constraint|null The primary key for the given table, `null` if the table has no primary key.
*/
protected function loadTablePrimaryKey(string $tableName): ?Constraint
protected function loadTablePrimaryKey(TableNameInterface $tableName): ?Constraint
{
/** @var mixed */
$tablePrimaryKey = $this->loadTableConstraints($tableName, self::PRIMARY_KEY);
Expand All @@ -308,13 +242,13 @@ protected function loadTablePrimaryKey(string $tableName): ?Constraint
/**
* Loads all foreign keys for the given table.
*
* @param string $tableName table name.
* @param TableNameInterface $tableName table name.
*
* @throws Exception|InvalidConfigException|Throwable
*
* @return array The foreign keys for the given table.
*/
protected function loadTableForeignKeys(string $tableName): array
protected function loadTableForeignKeys(TableNameInterface $tableName): array
{
/** @var mixed */
$tableForeingKeys = $this->loadTableConstraints($tableName, self::FOREIGN_KEYS);
Expand All @@ -324,13 +258,13 @@ protected function loadTableForeignKeys(string $tableName): array
/**
* Loads all indexes for the given table.
*
* @param string $tableName table name.
* @param TableNameInterface $tableName table name.
*
* @throws Exception|InvalidConfigException|Throwable
*
* @return array indexes for the given table.
*/
protected function loadTableIndexes(string $tableName): array
protected function loadTableIndexes(TableNameInterface $tableName): array
{
$sql = <<<SQL
SELECT
Expand All @@ -348,6 +282,7 @@ protected function loadTableIndexes(string $tableName): array
SQL;

$resolvedName = $this->resolveTableName($tableName);
// @todo check fullName or name????
$indexes = $this->db->createCommand($sql, [':fullName' => $resolvedName->getFullName()])->queryAll();

/** @psalm-var array[] $indexes */
Expand Down Expand Up @@ -379,13 +314,13 @@ protected function loadTableIndexes(string $tableName): array
/**
* Loads all unique constraints for the given table.
*
* @param string $tableName table name.
* @param TableNameInterface $tableName table name.
*
* @throws Exception|InvalidConfigException|Throwable
*
* @return array The unique constraints for the given table.
*/
protected function loadTableUniques(string $tableName): array
protected function loadTableUniques(TableNameInterface $tableName): array
{
/** @var mixed */
$tableUniques = $this->loadTableConstraints($tableName, self::UNIQUES);
Expand All @@ -395,13 +330,13 @@ protected function loadTableUniques(string $tableName): array
/**
* Loads all check constraints for the given table.
*
* @param string $tableName table name.
* @param TableNameInterface $tableName table name.
*
* @throws Exception|InvalidConfigException|Throwable
*
* @return array The check constraints for the given table.
*/
protected function loadTableChecks(string $tableName): array
protected function loadTableChecks(TableNameInterface $tableName): array
{
/** @var mixed */
$tableCheck = $this->loadTableConstraints($tableName, self::CHECKS);
Expand All @@ -411,13 +346,13 @@ protected function loadTableChecks(string $tableName): array
/**
* Loads all default value constraints for the given table.
*
* @param string $tableName table name.
* @param TableNameInterface $tableName table name.
*
* @throws Exception|InvalidConfigException|Throwable
*
* @return array The default value constraints for the given table.
*/
protected function loadTableDefaultValues(string $tableName): array
protected function loadTableDefaultValues(TableNameInterface $tableName): array
{
/** @var mixed */
$tableDefault = $this->loadTableConstraints($tableName, self::DEFAULTS);
Expand Down Expand Up @@ -766,7 +701,7 @@ public function findUniqueIndexes(TableSchemaInterface $table): array
/**
* Loads multiple types of constraints and returns the specified ones.
*
* @param string $tableName table name.
* @param TableNameInterface $tableName table name.
* @param string $returnType return type:
* - primaryKey
* - foreignKeys
Expand All @@ -778,7 +713,7 @@ public function findUniqueIndexes(TableSchemaInterface $table): array
*
* @return mixed constraints.
*/
private function loadTableConstraints(string $tableName, string $returnType): mixed
private function loadTableConstraints(TableNameInterface $tableName, string $returnType): mixed
{
$sql = <<<SQL
SELECT
Expand Down Expand Up @@ -910,19 +845,22 @@ public function createColumnSchemaBuilder(string $type, array|int|string $length
* This method will strip off curly brackets from the given table name and replace the percentage character '%' with
* {@see ConnectionInterface::tablePrefix}.
*
* @param string $name the table name to be converted.
* @param string|TableNameInterface $name the table name to be converted.
*
* @return string the real name of the given table name.
*/
public function getRawTableName(string $name): string
public function getRawTableName(string|TableNameInterface $name): string
{
if (str_contains($name, '{{')) {
$name = preg_replace('/{{(.*?)}}/', '\1', $name);
if ($name instanceof TableNameInterface) {
return (string)$name;
}

return str_replace('%', $this->db->getTablePrefix(), $name);
if (!str_contains($name, '{{')) {
return $name;
}

return $name;
$name = preg_replace('/{{(.*?)}}/', '\1', $name);
return str_replace('%', $this->db->getTablePrefix(), $name);
}

/**
Expand All @@ -934,7 +872,7 @@ public function getRawTableName(string $name): string
*/
protected function getCacheKey(string $name): array
{
return array_merge([__CLASS__], $this->db->getCacheKey(), [$this->getRawTableName($name)]);
return array_merge([__CLASS__], $this->db->getCacheKey(), [$name]);
}

/**
Expand Down
2 changes: 2 additions & 0 deletions tests/Provider/SchemaProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Yiisoft\Db\Mssql\Tests\Provider;

use Yiisoft\Db\Mssql\Tests\TestCase;
use Yiisoft\Db\Schema\TableName;

final class SchemaProvider extends TestCase
{
Expand All @@ -29,6 +30,7 @@ public function getTableSchemaDataProvider(): array
['dbo.profile', 'profile'],
['profile', 'profile'],
['dbo.[table.with.special.characters]', 'table.with.special.characters'],
[new TableName('table.with.special.characters', 'dbo'), 'table.with.special.characters'],
];
}
}
5 changes: 3 additions & 2 deletions tests/SchemaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Yiisoft\Db\Constraint\DefaultValueConstraint;
use Yiisoft\Db\Exception\NotSupportedException;
use Yiisoft\Db\Mssql\Schema;
use Yiisoft\Db\Schema\TableNameInterface;
use Yiisoft\Db\Schema\TableSchemaInterface;
use Yiisoft\Db\TestSupport\AnyValue;
use Yiisoft\Db\TestSupport\TestSchemaTrait;
Expand Down Expand Up @@ -147,10 +148,10 @@ public function testGetTableNames(array $pdoAttributes): void
/**
* @dataProvider \Yiisoft\Db\Mssql\Tests\Provider\SchemaProvider::getTableSchemaDataProvider
*
* @param string $name
* @param string|TableNameInterface $name
* @param string $expectedName
*/
public function testGetTableSchema(string $name, string $expectedName): void
public function testGetTableSchema(string|TableNameInterface $name, string $expectedName): void
{
$tableSchema = $this->getConnection()->getSchema()->getTableSchema($name);
$this->assertInstanceOf(TableSchemaInterface::class, $tableSchema);
Expand Down