Skip to content

Commit

Permalink
Refactor Quoter (#756)
Browse files Browse the repository at this point in the history
Co-authored-by: Sergei Predvoditelev <[email protected]>
  • Loading branch information
Tigrov and vjik authored Sep 26, 2023
1 parent fb4c084 commit 264d589
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 11 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
## 1.1.2 under development

- Bug #751: Fix collected debug actions (@xepozz)
- Enh #756: Refactor `Quoter` (@Tigrov)
- Bug #756: Fix `quoteSql()` for SQL containing table with prefix (@Tigrov)
- Bug #756: Fix `getTableNameParts()` for cases when different quotes for tables and columns (@Tigrov)
- Bug #756: Fix `quoteTableName()` for sub-query with alias (@Tigrov)

## 1.1.1 August 16, 2023

Expand Down
33 changes: 22 additions & 11 deletions src/Schema/Quoter.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@
use Yiisoft\Db\Expression\ExpressionInterface;

use function addcslashes;
use function array_slice;
use function count;
use function explode;
use function implode;
use function is_string;
use function preg_match;
use function preg_replace;
use function preg_replace_callback;
use function str_contains;
use function str_replace;
Expand Down Expand Up @@ -44,7 +48,7 @@ public function cleanUpTableNames(array $tableNames): array
{
$cleanedUpTableNames = [];
$pattern = <<<PATTERN
~^\s*((?:['"`\[]|{{).*?(?:['"`\]]|}})|\(.*?\)|.*?)(?:(?:\s+(?:as\s+)?)((?:['"`\[]|{{).*?(?:['"`\]]|}})|.*?))?\s*$~iux
~^\s*((?:['"`\[]|{{).*?(?:['"`\]]|}})|\(.*?\)|.*?)(?:\s+(?:as\s+)?((?:['"`\[]|{{).*?(?:['"`\]]|}})|.*?))?\s*$~iux
PATTERN;

/** @psalm-var array<array-key, ExpressionInterface|string> $tableNames */
Expand Down Expand Up @@ -104,7 +108,7 @@ public function ensureColumnName(string $name): string
$name = $parts[count($parts) - 1];
}

return preg_replace('|^\[\[([_\w\-. ]+)\]\]$|', '\1', $name);
return preg_replace('|^\[\[([\w\-. ]+)]]$|', '\1', $name);
}

public function quoteColumnName(string $name): string
Expand Down Expand Up @@ -135,8 +139,9 @@ public function quoteSimpleColumnName(string $name): string
[$startingCharacter, $endingCharacter] = $this->columnQuoteCharacter;
}

return $name === '*' || str_contains($name, $startingCharacter) ? $name : $startingCharacter . $name
. $endingCharacter;
return $name === '*' || str_starts_with($name, $startingCharacter)
? $name
: $startingCharacter . $name . $endingCharacter;
}

public function quoteSimpleTableName(string $name): string
Expand All @@ -147,13 +152,15 @@ public function quoteSimpleTableName(string $name): string
[$startingCharacter, $endingCharacter] = $this->tableQuoteCharacter;
}

return str_contains($name, $startingCharacter) ? $name : $startingCharacter . $name . $endingCharacter;
return str_starts_with($name, $startingCharacter)
? $name
: $startingCharacter . $name . $endingCharacter;
}

public function quoteSql(string $sql): string
{
return preg_replace_callback(
'/({{(%?[\w\-. ]+%?)}}|\\[\\[([\w\-. ]+)]])/',
'/({{(%?[\w\-. ]+)%?}}|\\[\\[([\w\-. ]+)]])/',
function ($matches) {
if (isset($matches[3])) {
return $this->quoteColumnName($matches[3]);
Expand All @@ -167,7 +174,7 @@ function ($matches) {

public function quoteTableName(string $name): string
{
if (str_starts_with($name, '(') && str_ends_with($name, ')')) {
if (str_starts_with($name, '(')) {
return $name;
}

Expand All @@ -194,7 +201,7 @@ public function quoteValue(mixed $value): mixed
return $value;
}

return '\'' . str_replace('\'', '\'\'', addcslashes($value, "\000\032")) . '\'';
return "'" . str_replace("'", "''", addcslashes($value, "\000\032")) . "'";
}

public function unquoteSimpleColumnName(string $name): string
Expand All @@ -205,7 +212,9 @@ public function unquoteSimpleColumnName(string $name): string
$startingCharacter = $this->columnQuoteCharacter[0];
}

return !str_contains($name, $startingCharacter) ? $name : substr($name, 1, -1);
return !str_starts_with($name, $startingCharacter)
? $name
: substr($name, 1, -1);
}

public function unquoteSimpleTableName(string $name): string
Expand All @@ -216,7 +225,9 @@ public function unquoteSimpleTableName(string $name): string
$startingCharacter = $this->tableQuoteCharacter[0];
}

return !str_contains($name, $startingCharacter) ? $name : substr($name, 1, -1);
return !str_starts_with($name, $startingCharacter)
? $name
: substr($name, 1, -1);
}

/**
Expand All @@ -229,7 +240,7 @@ protected function unquoteParts(array $parts, bool $withColumn): array
$lastKey = count($parts) - 1;

foreach ($parts as $k => &$part) {
$part = ($withColumn || $lastKey === $k) ?
$part = ($withColumn && $lastKey === $k) ?
$this->unquoteSimpleColumnName($part) :
$this->unquoteSimpleTableName($part);
}
Expand Down
23 changes: 23 additions & 0 deletions tests/Db/Schema/QuoterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,27 @@ public function testCleanUpTableNamesWithCastException(): void
['tableAlias' => 123],
);
}

public function testGetTableNamePartsWithDifferentQuotes(): void
{
$quoter = new Quoter('`', '"');

$this->assertSame(['schema', 'table'], $quoter->getTableNameParts('"schema"."table"'));
}

public function testQuoteSqlWithTablePrefix(): void
{
$quoter = new Quoter('`', '`', 'prefix_');
$sql = 'SELECT * FROM {{%table%}}';

$this->assertSame('SELECT * FROM `prefix_table`', $quoter->quoteSql($sql));
}

public function testQuoteTableNameWithQueryAlias()
{
$quoter = new Quoter('`', '`');
$name = '(SELECT * FROM table) alias';

$this->assertSame($name, $quoter->quoteTableName($name));
}
}

0 comments on commit 264d589

Please sign in to comment.