Skip to content

Commit 2c644c5

Browse files
authored
feat: insert with parameters (#247)
1 parent 425b8d2 commit 2c644c5

File tree

4 files changed

+85
-3
lines changed

4 files changed

+85
-3
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,10 @@ use SimPod\ClickHouseClient\Client\ClickHouseClient;
207207
$client->insert('table', $data, $columnNames);
208208
```
209209

210+
If `$columnNames` is provided and is key->value array column names are generated based on it and values are passed as parameters:
211+
212+
`$client->insert( 'table', [[1,2]], ['a' => 'Int8, 'b' => 'String'] );` generates `INSERT INTO table (a,b) VALUES ({p1:Int8},{p2:String})` and values are passed along the query.
213+
210214
If `$columnNames` is provided column names are generated based on it:
211215

212216
`$client->insert( 'table', [[1,2]], ['a', 'b'] );` generates `INSERT INTO table (a,b) VALUES (1,2)`.

src/Client/ClickHouseClient.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public function selectWithParams(string $query, array $params, Format $outputFor
6464

6565
/**
6666
* @param array<array<mixed>> $values
67-
* @param list<string>|null $columns
67+
* @param list<string>|array<string, string>|null $columns
6868
* @param array<string, float|int|string> $settings
6969
*
7070
* @throws CannotInsert

src/Client/PsrClickHouseClient.php

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@
2020
use SimPod\ClickHouseClient\Sql\SqlFactory;
2121
use SimPod\ClickHouseClient\Sql\ValueFormatter;
2222

23+
use function array_is_list;
2324
use function array_key_first;
2425
use function array_keys;
2526
use function array_map;
27+
use function array_values;
2628
use function implode;
29+
use function is_array;
2730
use function is_int;
2831
use function SimPod\ClickHouseClient\absurd;
2932
use function sprintf;
@@ -96,6 +99,54 @@ public function insert(string $table, array $values, array|null $columns = null,
9699
throw CannotInsert::noValues();
97100
}
98101

102+
$table = Escaper::quoteIdentifier($table);
103+
104+
if (is_array($columns) && ! array_is_list($columns)) {
105+
$columnsSql = sprintf('(%s)', implode(',', array_keys($columns)));
106+
107+
$types = array_values($columns);
108+
109+
$params = [];
110+
$pN = 1;
111+
foreach ($values as $row) {
112+
foreach ($row as $value) {
113+
$params['p' . $pN++] = $value;
114+
}
115+
}
116+
117+
$pN = 1;
118+
$valuesSql = implode(
119+
',',
120+
array_map(
121+
static function (array $row) use (&$pN, $types): string {
122+
return sprintf(
123+
'(%s)',
124+
implode(',', array_map(static function ($i) use (&$pN, $types) {
125+
return sprintf('{p%d:%s}', $pN++, $types[$i]);
126+
}, array_keys($row))),
127+
);
128+
},
129+
$values,
130+
),
131+
);
132+
133+
try {
134+
$this->executeRequest(
135+
<<<CLICKHOUSE
136+
INSERT INTO $table
137+
$columnsSql
138+
VALUES $valuesSql
139+
CLICKHOUSE,
140+
params: $params,
141+
settings: $settings,
142+
);
143+
} catch (UnsupportedParamType) {
144+
absurd();
145+
}
146+
147+
return;
148+
}
149+
99150
if ($columns === null) {
100151
$firstRow = $values[array_key_first($values)];
101152
$columns = array_keys($firstRow);
@@ -117,8 +168,6 @@ public function insert(string $table, array $values, array|null $columns = null,
117168
),
118169
);
119170

120-
$table = Escaper::quoteIdentifier($table);
121-
122171
try {
123172
$this->executeRequest(
124173
<<<CLICKHOUSE

tests/Client/InsertTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,35 @@ public function testInsertUseColumns(string $tableSql): void
7878
self::assertSame($expectedData, $output->data);
7979
}
8080

81+
#[DataProvider('providerInsert')]
82+
public function testInsertUseColumnsWithTypes(string $tableSql): void
83+
{
84+
$expectedData = [
85+
['PageViews' => 5, 'UserID' => '4324182021466249494', 'Duration' => 146, 'Sign' => -1],
86+
['PageViews' => 6, 'UserID' => '4324182021466249494', 'Duration' => 185, 'Sign' => 1],
87+
];
88+
89+
self::$client->executeQuery($tableSql);
90+
91+
self::$client->insert(
92+
'UserActivity',
93+
[
94+
[5, 4324182021466249494, 146, -1],
95+
[6, 4324182021466249494, 185, 1],
96+
],
97+
['PageViews' => 'UInt32', 'UserID' => 'UInt64', 'Duration' => 'UInt32', 'Sign' => 'Int8'],
98+
);
99+
100+
$output = self::$client->select(
101+
<<<'CLICKHOUSE'
102+
SELECT * FROM UserActivity
103+
CLICKHOUSE,
104+
new JsonEachRow(),
105+
);
106+
107+
self::assertSame($expectedData, $output->data);
108+
}
109+
81110
public function testInsertEscaping(): void
82111
{
83112
self::$client->executeQuery(

0 commit comments

Comments
 (0)