Skip to content
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

feat: introduce Table helper, allow Table as an input for inserts #284

Merged
merged 1 commit into from
Jan 27, 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
2 changes: 1 addition & 1 deletion infection.json.dist
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@
"text": "infection-log.txt"
},
"minMsi": 90,
"minCoveredMsi": 95
"minCoveredMsi": 94
}
12 changes: 9 additions & 3 deletions src/Client/ClickHouseClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use SimPod\ClickHouseClient\Exception\UnsupportedParamValue;
use SimPod\ClickHouseClient\Format\Format;
use SimPod\ClickHouseClient\Output\Output;
use SimPod\ClickHouseClient\Schema\Table;

interface ClickHouseClient
{
Expand Down Expand Up @@ -74,7 +75,7 @@ public function selectWithParams(string $query, array $params, Format $outputFor
* @throws UnsupportedParamType
* @throws UnsupportedParamValue
*/
public function insert(string $table, array $values, array|null $columns = null, array $settings = []): void;
public function insert(Table|string $table, array $values, array|null $columns = null, array $settings = []): void;

/**
* @param array<string, float|int|string> $settings
Expand All @@ -85,7 +86,12 @@ public function insert(string $table, array $values, array|null $columns = null,
*
* @template O of Output
*/
public function insertWithFormat(string $table, Format $inputFormat, string $data, array $settings = []): void;
public function insertWithFormat(
Table|string $table,
Format $inputFormat,
string $data,
array $settings = [],
): void;

/**
* @param array<string, float|int|string> $settings
Expand All @@ -97,7 +103,7 @@ public function insertWithFormat(string $table, Format $inputFormat, string $dat
* @throws ServerError
*/
public function insertPayload(
string $table,
Table|string $table,
Format $inputFormat,
StreamInterface $payload,
array $columns = [],
Expand Down
40 changes: 28 additions & 12 deletions src/Client/PsrClickHouseClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
use SimPod\ClickHouseClient\Format\Format;
use SimPod\ClickHouseClient\Logger\SqlLogger;
use SimPod\ClickHouseClient\Output\Output;
use SimPod\ClickHouseClient\Sql\Escaper;
use SimPod\ClickHouseClient\Schema\Table;
use SimPod\ClickHouseClient\Sql\SqlFactory;
use SimPod\ClickHouseClient\Sql\ValueFormatter;

Expand Down Expand Up @@ -66,7 +66,7 @@

public function executeQueryWithParams(string $query, array $params, array $settings = []): void
{
$this->executeRequest(

Check warning on line 69 in src/Client/PsrClickHouseClient.php

View workflow job for this annotation

GitHub Actions / Infection

Escaped Mutant for Mutator "MethodCallRemoval": @@ @@ } public function executeQueryWithParams(string $query, array $params, array $settings = []): void { - $this->executeRequest($this->sqlFactory->createWithParameters($query, $params), params: $params, settings: $settings); + } public function select(string $query, Format $outputFormat, array $settings = []): Output {
$this->sqlFactory->createWithParameters($query, $params),
params: $params,
settings: $settings,
Expand All @@ -77,7 +77,7 @@
{
try {
return $this->selectWithParams($query, params: [], outputFormat: $outputFormat, settings: $settings);
} catch (UnsupportedParamValue | UnsupportedParamType) {

Check warning on line 80 in src/Client/PsrClickHouseClient.php

View workflow job for this annotation

GitHub Actions / Infection

Escaped Mutant for Mutator "Catch_": @@ @@ { try { return $this->selectWithParams($query, params: [], outputFormat: $outputFormat, settings: $settings); - } catch (UnsupportedParamValue|UnsupportedParamType) { + } catch (UnsupportedParamType) { absurd(); } }
absurd();
}
}
Expand All @@ -100,13 +100,17 @@
return $outputFormat::output($response->getBody()->__toString());
}

public function insert(string $table, array $values, array|null $columns = null, array $settings = []): void
public function insert(Table|string $table, array $values, array|null $columns = null, array $settings = []): void
{
if ($values === []) {
throw CannotInsert::noValues();
}

$table = Escaper::quoteIdentifier($table);
if (! $table instanceof Table) {
$table = new Table($table);
}

$tableName = $table->fullName();

if (is_array($columns) && ! array_is_list($columns)) {
$columnsSql = sprintf('(%s)', implode(',', array_keys($columns)));
Expand Down Expand Up @@ -139,7 +143,7 @@

$this->executeRequest(
<<<CLICKHOUSE
INSERT INTO $table
INSERT INTO $tableName
$columnsSql
VALUES $valuesSql
CLICKHOUSE,
Expand Down Expand Up @@ -174,7 +178,7 @@
try {
$this->executeRequest(
<<<CLICKHOUSE
INSERT INTO $table
INSERT INTO $tableName
$columnsSql
VALUES $valuesSql
CLICKHOUSE,
Expand All @@ -186,16 +190,24 @@
}
}

public function insertWithFormat(string $table, Format $inputFormat, string $data, array $settings = []): void
{
public function insertWithFormat(
Table|string $table,
Format $inputFormat,
string $data,
array $settings = [],
): void {
$formatSql = $inputFormat::toSql();

$table = Escaper::quoteIdentifier($table);
if (! $table instanceof Table) {
$table = new Table($table);
}

$tableName = $table->fullName();

try {
$this->executeRequest(
<<<CLICKHOUSE
INSERT INTO $table $formatSql $data
INSERT INTO $tableName $formatSql $data
CLICKHOUSE,
params: [],
settings: $settings,
Expand All @@ -206,7 +218,7 @@
}

public function insertPayload(
string $table,
Table|string $table,
Format $inputFormat,
StreamInterface $payload,
array $columns = [],
Expand All @@ -218,12 +230,16 @@

$formatSql = $inputFormat::toSql();

$table = Escaper::quoteIdentifier($table);
if (! $table instanceof Table) {
$table = new Table($table);
}

$tableName = $table->fullName();

$columnsSql = $columns === [] ? '' : sprintf('(%s)', implode(',', $columns));

$sql = <<<CLICKHOUSE
INSERT INTO $table $columnsSql $formatSql
INSERT INTO $tableName $columnsSql $formatSql
CLICKHOUSE;

$request = $this->requestFactory->initRequest(
Expand Down
33 changes: 33 additions & 0 deletions src/Schema/Table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace SimPod\ClickHouseClient\Schema;

use SimPod\ClickHouseClient\Sql\Escaper;

final readonly class Table
{
public function __construct(
public string $name,
public string|null $database = null,
) {
}

public function fullName(): string
{
$escapedName = $this->name[0] === '`' && $this->name[-1] === '`'
? $this->name
: Escaper::quoteIdentifier($this->name);

if ($this->database === null) {
return $escapedName;
}

$escapedDatabase = $this->database[0] === '`' && $this->database[-1] === '`'
? $this->database
: Escaper::quoteIdentifier($this->database);

return $escapedDatabase . '.' . $escapedName;
}
}
47 changes: 47 additions & 0 deletions tests/Schema/TableTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

namespace SimPod\ClickHouseClient\Tests\Schema;

use Generator;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use SimPod\ClickHouseClient\Schema\Table;
use SimPod\ClickHouseClient\Tests\TestCaseBase;

#[CoversClass(Table::class)]
final class TableTest extends TestCaseBase
{
public function testConstruct(): void
{
$table = new Table('t1', 'db');
self::assertSame('t1', $table->name);
self::assertSame('db', $table->database);
}

#[DataProvider('providerFullName')]
public function testFullName(string $expectedFullName, Table $table): void
{
self::assertSame($expectedFullName, $table->fullName());
}

/** @return Generator<string, array{string, Table}> */
public static function providerFullName(): Generator
{
yield 'no database' => [
'`t1`',
new Table('t1'),
];

yield 'with database' => [
'`db`.`t1`',
new Table('t1', 'db'),
];

yield 'escaped' => [
'`db`.`t1`',
new Table('`t1`', '`db`'),
];
}
}
Loading