Skip to content

Commit

Permalink
Big 💥
Browse files Browse the repository at this point in the history
  • Loading branch information
simPod committed Jan 19, 2020
1 parent 9868436 commit 1c31ad0
Show file tree
Hide file tree
Showing 15 changed files with 208 additions and 17 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

[![Build Status](https://github.com/simPod/PhpClickHouseClient/workflows/Continuous%20Integration/badge.svg?branch=master)](https://github.com/simPod/PhpClickHouseClient/actions)
[![Coverage Status](https://coveralls.io/repos/github/simPod/PhpClickHouseClient/badge.svg?branch=master)](https://coveralls.io/github/simPod/PhpClickHouseClient?branch=master)
[![Downloads](https://poser.pugx.org/simpod/php-clickhouse-client/d/total.svg)](https://packagist.org/packages/simpod/php-clickhouse-client)
[![Packagist](https://poser.pugx.org/simpod/php-clickhouse-client/v/stable.svg)](https://packagist.org/packages/simpod/php-clickhouse-client)
[![Licence](https://poser.pugx.org/simpod/php-clickhouse-client/license.svg)](https://packagist.org/packages/simpod/php-clickhouse-client)
[![Downloads](https://poser.pugx.org/simpod/clickhouse-client/d/total.svg)](https://packagist.org/packages/simpod/clickhouse-client)
[![Packagist](https://poser.pugx.org/simpod/clickhouse-client/v/stable.svg)](https://packagist.org/packages/simpod/clickhouse-client)
[![Licence](https://poser.pugx.org/simpod/clickhouse-client/license.svg)](https://packagist.org/packages/simpod/clickhouse-client)
[![GitHub Issues](https://img.shields.io/github/issues/simPod/PhpClickHouseClient.svg?style=flat-square)](https://github.com/simPod/PhpClickHouseClient/issues)

PHP Client that talks to ClickHouse via HTTP layer
Expand Down
19 changes: 17 additions & 2 deletions src/ClickHouseClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,31 @@

namespace SimPod\ClickHouseClient;

use Ds\Set;
use Ds\Vector;
use SimPod\ClickHouseClient\Format\Format;
use SimPod\ClickHouseClient\Output\Output;

interface ClickHouseClient
{
public function executeQuery(string $sql) : void;

/**
* @phpstan-template O of Output
* @phpstan-param Format<O> $outputFormat
* @phpstan-return O
*/
public function select(string $sql, Format $outputFormat) : Output;

public function insert(string $table, $values, $columns) : void;
/**
* @param Vector<mixed> $values
* @param Set<string>|null $columns
*/
public function insert(string $table, Vector $values, ?Set $columns = null) : void;

public function insertWithFormat(string $table, Format $format, string $data) : void;
/**
* @phpstan-template O of Output
* @phpstan-param Format<O> $inputFormat
*/
public function insertWithFormat(string $table, Format $inputFormat, string $data) : void;
}
15 changes: 15 additions & 0 deletions src/Exception/CannotInsert.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace SimPod\ClickHouseClient\Exception;

use Exception;

final class CannotInsert extends Exception implements ClickHouseClientException
{
public static function noValues() : self
{
return new self();
}
}
9 changes: 9 additions & 0 deletions src/Exception/ClickHouseClientException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace SimPod\ClickHouseClient\Exception;

interface ClickHouseClientException
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Exception;
use Psr\Http\Message\ResponseInterface;

final class ServerException extends Exception
final class ServerError extends Exception
{
public static function fromResponse(ResponseInterface $response) : self
{
Expand Down
6 changes: 6 additions & 0 deletions src/Format/Format.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@

use SimPod\ClickHouseClient\Output\Output;

/**
* @phpstan-template O of Output
*/
interface Format
{
public static function toSql() : string;

/**
* @phpstan-return O
*/
public static function output(string $contents) : Output;
}
3 changes: 3 additions & 0 deletions src/Format/Json.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

use SimPod\ClickHouseClient\Output\Output;

/**
* @phpstan-implements Format<\SimPod\ClickHouseClient\Output\Json>
*/
final class Json implements Format
{
public static function toSql() : string
Expand Down
3 changes: 3 additions & 0 deletions src/Format/JsonCompact.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

use SimPod\ClickHouseClient\Output\Output;

/**
* @phpstan-implements Format<\SimPod\ClickHouseClient\Output\JsonCompact>
*/
final class JsonCompact implements Format
{
public static function toSql() : string
Expand Down
3 changes: 3 additions & 0 deletions src/Format/JsonEachRow.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

use SimPod\ClickHouseClient\Output\Output;

/**
* @phpstan-implements Format<\SimPod\ClickHouseClient\Output\JsonEachRow>
*/
final class JsonEachRow implements Format
{
public static function toSql() : string
Expand Down
3 changes: 3 additions & 0 deletions src/Format/None.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
use SimPod\ClickHouseClient\Output\Output;
use SimPod\ClickHouseClient\Output\Raw;

/**
* @phpstan-implements Format<\SimPod\ClickHouseClient\Output\Raw>
*/
final class None implements Format
{
public static function toSql() : string
Expand Down
49 changes: 40 additions & 9 deletions src/HttpClickHouseClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,21 @@

namespace SimPod\ClickHouseClient;

use Ds\Set;
use Ds\Vector;
use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamFactoryInterface;
use Psr\Http\Message\UriFactoryInterface;
use SimPod\ClickHouseClient\Exception\ServerException;
use SimPod\ClickHouseClient\Exception\CannotInsert;
use SimPod\ClickHouseClient\Exception\ServerError;
use SimPod\ClickHouseClient\Format\Format;
use SimPod\ClickHouseClient\Output\Output;
use function array_keys;
use function implode;
use function Safe\sprintf;

final class HttpClickHouseClient implements ClickHouseClient
{
Expand Down Expand Up @@ -73,23 +79,48 @@ public function select(string $sql, Format $outputFormat) : Output
return $outputFormat::output((string) $response->getBody());
}

public function insert(string $table, $values, $columns) : void
/** {@inheritDoc} */
public function insert(string $table, Vector $values, ?Set $columns = null) : void
{
$formatClause = $outputFormat::toSql();
if ($values->isEmpty()) {
throw CannotInsert::noValues();
}

if ($columns === null) {
/** @var array<mixed> $row */
$row = $values->first();
$columnNames = array_keys($row);
} else {
$columnNames = $columns->toArray();
}

$columnsSql = implode(',', $columnNames);

$valuesSql = implode(
',',
$values->map(
static function (array $map) : string {
return sprintf(
'(%s)',
implode(',', $map)
);
}
)->toArray()
);

$response = $this->executeRequest(
<<<CLICKHOUSE
$sql
$formatClause
INSERT INTO $table
($columnsSql)
VALUES $valuesSql
CLICKHOUSE
);

// return $outputFormat::output((string) $response->getBody());
}

public function insertWithFormat(string $table, Format $format, string $data) : void
public function insertWithFormat(string $table, Format $inputFormat, string $data) : void
{
$formatSql = $format::toSql();
$formatSql = $inputFormat::toSql();

$this->executeRequest(
<<<CLICKHOUSE
Expand All @@ -103,7 +134,7 @@ private function executeRequest(string $sql) : ResponseInterface
$request = $this->prepareRequest($sql);
$response = $this->client->sendRequest($request);
if ($response->getStatusCode() !== 200) {
throw ServerException::fromResponse($response);
throw ServerError::fromResponse($response);
}

return $response;
Expand Down
1 change: 1 addition & 0 deletions src/Output/Json.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ final class Json implements Output
public function __construct(string $contentsJson)
{
$this->wakeUp = function () use ($contentsJson) : void {
/** @var array{data: array<array<mixed>>, meta: array<mixed>, rows: int, statistics: array{elapsed: float, rows_read: int, bytes_read: int}} $contents */
$contents = json_decode($contentsJson, true);
$this->data = $contents['data'];
$this->meta = $contents['meta'];
Expand Down
1 change: 1 addition & 0 deletions src/Output/JsonCompact.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ final class JsonCompact implements Output
public function __construct(string $contentsJson)
{
$this->wakeUp = function () use ($contentsJson) : void {
/** @var array{data: array<array<mixed>>, meta: array<mixed>, rows: int, statistics: array{elapsed: float, rows_read: int, bytes_read: int}} $contents */
$contents = json_decode($contentsJson, true);
$this->data = $contents['data'];
$this->meta = $contents['meta'];
Expand Down
101 changes: 101 additions & 0 deletions tests/InsertTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php

declare(strict_types=1);

namespace SimPod\ClickHouseClient\Tests;

use Ds\Set;
use Ds\Vector;
use SimPod\ClickHouseClient\Exception\CannotInsert;
use SimPod\ClickHouseClient\Format\JsonEachRow;

final class InsertTest extends TestCaseBase
{
use WithClient;

/**
* @dataProvider providerInsert
*/
public function testInsert(string $tableSql) : void
{
$data = new Vector(
[
['PageViews' => 5, 'UserID' => '4324182021466249494', 'Duration' => 146, 'Sign' => -1],
['PageViews' => 6, 'UserID' => '4324182021466249494', 'Duration' => 185, 'Sign' => 1],
]
);

$this->client->executeQuery($tableSql);

$this->client->insert('UserActivity', $data);

$output = $this->client->select(
<<<CLICKHOUSE
SELECT * FROM UserActivity
CLICKHOUSE
,
new JsonEachRow()
);

self::assertSame($data->toArray(), $output->data());
}

/**
* @dataProvider providerInsert
*/
public function testInsertUseColumns(string $tableSql) : void
{
$data = [
['PageViews' => 5, 'UserID' => '4324182021466249494', 'Duration' => 146, 'Sign' => -1],
['PageViews' => 6, 'UserID' => '4324182021466249494', 'Duration' => 185, 'Sign' => 1],
];

$this->client->executeQuery($tableSql);

$this->client->insert(
'UserActivity',
new Vector(
[
[5, '4324182021466249494', 146, -1],
[6, '4324182021466249494', 185, 1],
]
),
new Set(['PageViews', 'UserID', 'Duration', 'Sign'])
);

$output = $this->client->select(
<<<CLICKHOUSE
SELECT * FROM UserActivity
CLICKHOUSE
,
new JsonEachRow()
);

self::assertSame($data, $output->data());
}

/**
* @return iterable<array<mixed>>
*/
public function providerInsert() : iterable
{
$sql = <<<CLICKHOUSE
CREATE TABLE UserActivity (
PageViews UInt32,
UserID UInt64,
Duration UInt32,
Sign Int8
)
ENGINE Memory
CLICKHOUSE;

yield [$sql];
}

public function testInsertEmptyValuesThrowsException() : void
{
$this->expectException(CannotInsert::class);

$this->client->insert('table', new Vector());
}
}
4 changes: 2 additions & 2 deletions tests/InsertWithFormatTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ public function testInsertWithFormat() : void

self::assertSame(
[
['PageViews' => 5, "UserID" => "4324182021466249494", "Duration" => 146, "Sign" => -1],
["PageViews" => 6, "UserID" => "4324182021466249494", "Duration" => 185, "Sign" => 1],
['PageViews' => 5, 'UserID' => '4324182021466249494', 'Duration' => 146, 'Sign' => -1],
['PageViews' => 6, 'UserID' => '4324182021466249494', 'Duration' => 185, 'Sign' => 1],
],
$output->data()
);
Expand Down

0 comments on commit 1c31ad0

Please sign in to comment.