Skip to content

Commit 75ac749

Browse files
authored
Merge pull request #4 from FriendsOfDoctrine/PHPUnit
add PHPUnit tests
2 parents be82c70 + cdb7e79 commit 75ac749

17 files changed

+1262
-39
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.idea/
2+
composer.lock
3+
vendor/
4+
phpunit.xml

README.md

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ doctrine:
4646
$conn = $this->get('doctrine.dbal.clickhouse_connection');
4747
```
4848

49-
5049
## Usage
5150

5251
### Create new table
@@ -142,8 +141,52 @@ while ($row = $stmt->fetch()) {
142141
}
143142
```
144143

145-
### Update
146-
*ClickHouse has no classical updates. Will add ersatz-updates for ReplacingMergeTree and CollapcingMergeTree engines later*
144+
### Additional types
145+
146+
If you want to use [Array(T) type](https://clickhouse.yandex/reference_en.html#Array(T)), register additional DBAL types in your code:
147+
```php
148+
// register all custom DBAL Array types
149+
ArrayType::registerArrayTypes($conn->getDatabasePlatform());
150+
// register one custom DBAL Array(Int8) type
151+
Type::addType('array(int8)', 'FOD\DBALClickHouse\Types\ArrayInt8Type');
152+
```
153+
or register them in Symfony configuration file:
154+
```yml
155+
# app/config/config.yml
156+
doctrine:
157+
dbal:
158+
connections:
159+
...
160+
types:
161+
array(int8): FOD\DBALClickHouse\Types\ArrayInt8Type
162+
array(int16): FOD\DBALClickHouse\Types\ArrayInt16Type
163+
array(int32): FOD\DBALClickHouse\Types\ArrayInt32Type
164+
array(int64): FOD\DBALClickHouse\Types\ArrayInt64Type
165+
array(uint8): FOD\DBALClickHouse\Types\ArrayUInt8Type
166+
array(uint16): FOD\DBALClickHouse\Types\ArrayUInt16Type
167+
array(uint32): FOD\DBALClickHouse\Types\ArrayUInt32Type
168+
array(uint64): FOD\DBALClickHouse\Types\ArrayUInt64Type
169+
array(float32): FOD\DBALClickHouse\Types\ArrayFloat32Type
170+
array(float64): FOD\DBALClickHouse\Types\ArrayFloat64Type
171+
array(string): FOD\DBALClickHouse\Types\ArrayStringType
172+
array(datetime): FOD\DBALClickHouse\Types\ArrayDateTimeType
173+
array(date): FOD\DBALClickHouse\Types\ArrayDateType
174+
```
175+
176+
Additional type `BigIntType` helps you to store bigint values as [Int64/UInt64](https://clickhouse.yandex/reference_en.html#UInt8,%20UInt16,%20UInt32,%20UInt64,%20Int8,%20Int16,%20Int32,%20Int64) value type in ClickHouse.
177+
You can override DBAL type in your code:
178+
```php
179+
Type::overrideType(Type::BIGINT, 'FOD\DBALClickHouse\Types\BigIntType');
180+
```
181+
or use custom mapping types in Symfony configuration:
182+
```yml
183+
# app/config/config.yml
184+
doctrine:
185+
dbal:
186+
types:
187+
bigint: FOD\DBALClickHouse\Types\BigIntType
188+
...
189+
```
147190

148191
### More information in Doctrine DBAL documentation:
149192
* [Data Retrieval And Manipulation](http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/data-retrieval-and-manipulation.html)

composer.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,11 @@
1919
},
2020
"autoload": {
2121
"psr-4": { "FOD\\DBALClickHouse\\": "src/" }
22+
},
23+
"autoload-dev": {
24+
"psr-4": { "FOD\\DBALClickHouse\\Tests\\": "tests/" }
25+
},
26+
"require-dev": {
27+
"phpunit/phpunit": "^6.1"
2228
}
2329
}

phpunit.xml.dist

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<phpunit bootstrap="vendor/autoload.php" colors="true">
3+
<testsuites>
4+
<testsuite name="ClickHouse">
5+
<directory>tests</directory>
6+
</testsuite>
7+
</testsuites>
8+
<php>
9+
<const name="phpunit_ch_host" value="localhost"/>
10+
<const name="phpunit_ch_port" value="8123"/>
11+
<const name="phpunit_ch_user" value="default"/>
12+
<const name="phpunit_ch_password" value=""/>
13+
<const name="phpunit_ch_dbname" value="default"/>
14+
<const name="phpunit_ch_driver_class" value="FOD\DBALClickHouse\Driver"/>
15+
<const name="phpunit_ch_wrapper_class" value="FOD\DBALClickHouse\Connection"/>
16+
</php>
17+
</phpunit>

src/ClickHouseConnection.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public function beginTransaction()
122122
*/
123123
public function commit()
124124
{
125-
throw new \Exception('Transactions are not allowed in ClickHouse');
125+
throw new \LogicException('Transactions are not allowed in ClickHouse');
126126
}
127127

128128
/**

src/ClickHousePlatform.php

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,7 @@ public function getCommentOnColumnSQL($tableName, $columnName, $comment)
526526
protected function _getCreateTableSQL($tableName, array $columns, array $options = [])
527527
{
528528
$engine = !empty($options['engine']) ? $options['engine'] : 'ReplacingMergeTree';
529+
$engineOptions = '';
529530

530531
if (isset($options['uniqueConstraints']) && ! empty($options['uniqueConstraints'])) {
531532
throw DBALException::notSupported('uniqueConstraints');
@@ -535,11 +536,10 @@ protected function _getCreateTableSQL($tableName, array $columns, array $options
535536
throw DBALException::notSupported('uniqueConstraints');
536537
}
537538

538-
539539
/**
540540
* MergeTree* specific section
541541
*/
542-
if ( in_array($engine, ['MergeTree', 'CollapsingMergeTree', 'SummingMergeTree', 'AggregatingMergeTree', 'ReplacingMergeTree']) ) {
542+
if ( in_array($engine, ['MergeTree', 'CollapsingMergeTree', 'SummingMergeTree', 'AggregatingMergeTree', 'ReplacingMergeTree'], true) ) {
543543
$indexGranularity = !empty($options['indexGranularity']) ? $options['indexGranularity'] : 8192;
544544

545545
/**
@@ -572,9 +572,7 @@ protected function _getCreateTableSQL($tableName, array $columns, array $options
572572
$dateColumnParams['default'] =
573573
$columns[$options['eventDateProviderColumn']]['type'] instanceof IntegerType ||
574574
$columns[$options['eventDateProviderColumn']]['type'] instanceof SmallIntType ||
575-
$columns[$options['eventDateProviderColumn']]['type'] instanceof BigIntType ||
576-
$columns[$options['eventDateProviderColumn']]['type'] instanceof FloatType ||
577-
$columns[$options['eventDateProviderColumn']]['type'] instanceof DecimalType ?
575+
$columns[$options['eventDateProviderColumn']]['type'] instanceof FloatType ?
578576
('toDate(toDateTime(' . $options['eventDateProviderColumn'] . '))') :
579577
('toDate(' . $options['eventDateProviderColumn'] . ')');
580578
} else {
@@ -613,18 +611,12 @@ protected function _getCreateTableSQL($tableName, array $columns, array $options
613611
throw new \Exception('You need specify PrimaryKey for MergeTree* tables');
614612
}
615613

616-
}
617-
618-
$columnListSql = $this->getColumnDeclarationListSQL($columns);
619-
$query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql . ') ENGINE = ' . $engine;
620-
621-
if ( in_array($engine, ['MergeTree', 'CollapsingMergeTree', 'SummingMergeTree', 'AggregatingMergeTree', 'ReplacingMergeTree']) ) {
622-
$query .= '(' . $eventDateColumnName . ', (' . implode(', ', array_unique(array_values($options['primary']))) . '), ' . $indexGranularity;
614+
$engineOptions = '(' . $eventDateColumnName . ', (' . implode(', ', array_unique(array_values($options['primary']))) . '), ' . $indexGranularity;
623615

624616
/**
625617
* any specific MergeTree* table parameters
626618
*/
627-
if ('ReplacingMergeTree' == $engine) {
619+
if ('ReplacingMergeTree' === $engine) {
628620
if (! empty($options['versionColumn'])) {
629621
if (! isset($columns[$options['versionColumn']]) ) {
630622
throw new \Exception('If you specify `versionColumn` for ReplacingMergeTree table -- you must add this column manually (any of UInt*, Date or DateTime types)');
@@ -640,13 +632,16 @@ protected function _getCreateTableSQL($tableName, array $columns, array $options
640632
throw new \Exception('For ReplacingMergeTree tables `versionColumn` must be any of UInt* family, or Date, or DateTime types. ' . get_class($columns[$options['versionColumn']]['type']) . ' given.');
641633
}
642634

643-
$query .= ', ' . $columns[$options['versionColumn']]['name'];
635+
$engineOptions .= ', ' . $columns[$options['versionColumn']]['name'];
644636
}
645637
}
646638

647-
$query .= ')';
639+
$engineOptions .= ')';
648640
}
649641

642+
$columnListSql = $this->getColumnDeclarationListSQL($columns);
643+
$query = 'CREATE TABLE ' . $tableName . ' (' . $columnListSql . ') ENGINE = ' . $engine . $engineOptions;
644+
650645
$sql[] = $query;
651646

652647
return $sql;
@@ -940,7 +935,12 @@ public function getDateTimeTypeDeclarationSQL(array $fieldDeclaration)
940935
*/
941936
public function getDateTimeTzTypeDeclarationSQL(array $fieldDeclaration)
942937
{
943-
throw DBALException::notSupported(__METHOD__);
938+
return 'DateTime';
939+
}
940+
941+
public function getTimeTypeDeclarationSQL(array $fieldDeclaration)
942+
{
943+
return 'String';
944944
}
945945

946946
/**
@@ -1092,7 +1092,7 @@ public function getDefaultValueDeclarationSQL($field)
10921092

10931093
$default = " DEFAULT '" . $field['default'] . "'";
10941094
if ( isset($field['type']) ) {
1095-
if (in_array((string)$field['type'], ['Integer', 'BigInt', 'SmallInt', 'Float'])) {
1095+
if (in_array((string)$field['type'], ['Integer', 'SmallInt', 'Float']) || ('BigInt' === $field['type'] && \PDO::PARAM_INT === Type::getType('BigInt')->getBindingType())) {
10961096
$default = ' DEFAULT ' . $field['default'];
10971097
} else if (in_array((string)$field['type'], ['DateTime']) && $field['default'] == $this->getCurrentTimestampSQL()) {
10981098
$default = ' DEFAULT ' . $this->getCurrentTimestampSQL();

src/ClickHouseStatement.php

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -141,21 +141,26 @@ protected function assumeFetchMode($fetchMode = null)
141141
public function fetch($fetchMode = null)
142142
{
143143
$data = $this->getIterator()->current();
144+
145+
if (null === $data) {
146+
return false;
147+
}
148+
144149
$this->getIterator()->next();
145150

146-
if (\PDO::FETCH_NUM == $this->assumeFetchMode($fetchMode)) {
151+
if (\PDO::FETCH_NUM === $this->assumeFetchMode($fetchMode)) {
147152
return array_values($data);
148153
}
149154

150-
if (\PDO::FETCH_BOTH == $this->assumeFetchMode($fetchMode)) {
155+
if (\PDO::FETCH_BOTH === $this->assumeFetchMode($fetchMode)) {
151156
return array_values($data) + $data;
152157
}
153158

154-
if (\PDO::FETCH_OBJ == $this->assumeFetchMode($fetchMode)) {
159+
if (\PDO::FETCH_OBJ === $this->assumeFetchMode($fetchMode)) {
155160
return (object)$data;
156161
}
157162

158-
if (\PDO::FETCH_KEY_PAIR == $this->assumeFetchMode($fetchMode)) {
163+
if (\PDO::FETCH_KEY_PAIR === $this->assumeFetchMode($fetchMode)) {
159164
if (count($data) < 2) {
160165
throw new \Exception('To fetch in \PDO::FETCH_KEY_PAIR mode, result set must contain at least 2 columns');
161166
}
@@ -171,28 +176,28 @@ public function fetch($fetchMode = null)
171176
*/
172177
public function fetchAll($fetchMode = null)
173178
{
174-
if (\PDO::FETCH_NUM == $this->assumeFetchMode($fetchMode)) {
179+
if (\PDO::FETCH_NUM === $this->assumeFetchMode($fetchMode)) {
175180
return array_map(
176181
function ($row) {return array_values($row);},
177182
$this->rows
178183
);
179184
}
180185

181-
if (\PDO::FETCH_BOTH == $this->assumeFetchMode($fetchMode)) {
186+
if (\PDO::FETCH_BOTH === $this->assumeFetchMode($fetchMode)) {
182187
return array_map(
183188
function ($row) {return array_values($row) + $row;},
184189
$this->rows
185190
);
186191
}
187192

188-
if (\PDO::FETCH_OBJ == $this->assumeFetchMode($fetchMode)) {
193+
if (\PDO::FETCH_OBJ === $this->assumeFetchMode($fetchMode)) {
189194
return array_map(
190195
function ($row) {return (object)$row;},
191196
$this->rows
192197
);
193198
}
194199

195-
if (\PDO::FETCH_KEY_PAIR == $this->assumeFetchMode($fetchMode)) {
200+
if (\PDO::FETCH_KEY_PAIR === $this->assumeFetchMode($fetchMode)) {
196201
return array_map(
197202
function ($row) {
198203
if (count($row) < 2) {
@@ -215,12 +220,9 @@ function ($row) {
215220
*/
216221
public function fetchColumn($columnIndex = 0)
217222
{
218-
if ($elem = $this->fetch()) {
219-
if (array_key_exists($columnIndex, $elem)) {
220-
return $elem[$columnIndex];
221-
} else {
222-
return array_values($elem)[0];
223-
}
223+
if ($elem = $this->fetch(\PDO::FETCH_NUM)) {
224+
225+
return isset($elem[$columnIndex]) ? $elem[$columnIndex] : $elem[0];
224226
}
225227

226228
return false;

src/Connection.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,5 +165,4 @@ public function isRollbackOnly()
165165
{
166166
throw DBALException::notSupported(__METHOD__);
167167
}
168-
169168
}

src/Types/ArrayType.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,11 @@ abstract class ArrayType extends Type
4646
public static function registerArrayTypes(AbstractPlatform $platform)
4747
{
4848
foreach (self::ARRAY_TYPES as $typeName => $className) {
49-
self::addType($typeName, $className);
50-
foreach (Type::getType($typeName)->getMappedDatabaseTypes($platform) as $dbType) {
51-
$platform->registerDoctrineTypeMapping($dbType, $typeName);
49+
if (!self::hasType($typeName)) {
50+
self::addType($typeName, $className);
51+
foreach (Type::getType($typeName)->getMappedDatabaseTypes($platform) as $dbType) {
52+
$platform->registerDoctrineTypeMapping($dbType, $typeName);
53+
}
5254
}
5355
}
5456
}

0 commit comments

Comments
 (0)