diff --git a/README.md b/README.md index ff32c46..e559ab8 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ foreach ($sqlArray as $sql) { ``` ```php -// ***more options*** +// ***more options (optional)*** //specify table engine $newTable->addOption('engine', 'MergeTree'); @@ -112,7 +112,8 @@ $newTable->addOption('eventDateProviderColumn', 'updated_at'); // *if specified -- event date column will be added with default value toDate(updated_at); // if the type of the provider column is `string`, the valid format of provider column values must be either `YYYY-MM-DD` or `YYYY-MM-DD hh:mm:ss` // if the type of provider column is neither `string`, nor `date`, nor `datetime`, provider column values must contain a valid UNIX Timestamp - +$newTable->addOption('samplingExpression', 'intHash32(id)'); +// samplingExpression -- a tuple that defines the table's primary key, and the index granularity //specify index granularity $newTable->addOption('indexGranularity', 4096); diff --git a/src/ClickHousePlatform.php b/src/ClickHousePlatform.php index ea3c98b..7962d96 100644 --- a/src/ClickHousePlatform.php +++ b/src/ClickHousePlatform.php @@ -659,7 +659,8 @@ protected function _getCreateTableSQL($tableName, array $columns, array $options ], true )) { - $indexGranularity = ! empty($options['indexGranularity']) ? $options['indexGranularity'] : 8192; + $indexGranularity = ! empty($options['indexGranularity']) ? $options['indexGranularity'] : 8192; + $samplingExpression = ''; /** * eventDateColumn section @@ -746,10 +747,22 @@ protected function _getCreateTableSQL($tableName, array $columns, array $options throw new \Exception('You need specify PrimaryKey for MergeTree* tables'); } - $engineOptions = '(' . $eventDateColumnName . ', (' . implode( - ', ', - array_unique(array_values($options['primary'])) - ) . '), ' . $indexGranularity; + $primaryIndex = array_values($options['primary']); + if (! empty($options['samplingExpression'])) { + $samplingExpression = ', ' . $options['samplingExpression']; + $primaryIndex[] = $options['samplingExpression']; + } + + $engineOptions = sprintf( + '(%s%s, (%s), %d', + $eventDateColumnName, + $samplingExpression, + implode( + ', ', + array_unique($primaryIndex) + ), + $indexGranularity + ); /** * any specific MergeTree* table parameters diff --git a/tests/CreateSchemaTest.php b/tests/CreateSchemaTest.php index 7866a3d..5abdac6 100644 --- a/tests/CreateSchemaTest.php +++ b/tests/CreateSchemaTest.php @@ -56,7 +56,8 @@ public function testCreateNewTableSQL() $newTable->setPrimaryKey(['id']); $migrationSQLs = $fromSchema->getMigrateToSql($toSchema, $this->connection->getDatabasePlatform()); - $this->assertEquals("CREATE TABLE test_table (EventDate Date DEFAULT today(), id UInt32, payload String, oneVal Float64, twoVal String, flag UInt8, mask Int16, hash FixedString(32)) ENGINE = ReplacingMergeTree(EventDate, (id), 8192)", implode(';', $migrationSQLs)); + $this->assertEquals("CREATE TABLE test_table (EventDate Date DEFAULT today(), id UInt32, payload String, oneVal Float64, twoVal String, flag UInt8, mask Int16, hash FixedString(32)) ENGINE = ReplacingMergeTree(EventDate, (id), 8192)", + implode(';', $migrationSQLs)); foreach ($migrationSQLs as $sql) { $this->connection->exec($sql); } @@ -102,7 +103,8 @@ public function testIndexGranularityOption() $migrationSQLs = $fromSchema->getMigrateToSql($toSchema, $this->connection->getDatabasePlatform()); $generatedSQL = implode(';', $migrationSQLs); - $this->assertEquals("CREATE TABLE test_table (EventDate Date DEFAULT today(), id UInt32, payload String) ENGINE = ReplacingMergeTree(EventDate, (id), 4096)", $generatedSQL); + $this->assertEquals("CREATE TABLE test_table (EventDate Date DEFAULT today(), id UInt32, payload String) ENGINE = ReplacingMergeTree(EventDate, (id), 4096)", + $generatedSQL); foreach ($migrationSQLs as $sql) { $this->connection->exec($sql); } @@ -123,7 +125,8 @@ public function testEngineMergeOption() $migrationSQLs = $fromSchema->getMigrateToSql($toSchema, $this->connection->getDatabasePlatform()); $generatedSQL = implode(';', $migrationSQLs); - $this->assertEquals("CREATE TABLE test_table (EventDate Date DEFAULT today(), id UInt32, payload String) ENGINE = MergeTree(EventDate, (id), 8192)", $generatedSQL); + $this->assertEquals("CREATE TABLE test_table (EventDate Date DEFAULT today(), id UInt32, payload String) ENGINE = MergeTree(EventDate, (id), 8192)", + $generatedSQL); foreach ($migrationSQLs as $sql) { $this->connection->exec($sql); } @@ -166,7 +169,8 @@ public function testEventDateColumnOption() $migrationSQLs = $fromSchema->getMigrateToSql($toSchema, $this->connection->getDatabasePlatform()); $generatedSQL = implode(';', $migrationSQLs); - $this->assertEquals("CREATE TABLE test_table (event_date Date DEFAULT today(), id UInt32, payload String) ENGINE = ReplacingMergeTree(event_date, (id), 8192)", $generatedSQL); + $this->assertEquals("CREATE TABLE test_table (event_date Date DEFAULT today(), id UInt32, payload String) ENGINE = ReplacingMergeTree(event_date, (id), 8192)", + $generatedSQL); foreach ($migrationSQLs as $sql) { $this->connection->exec($sql); } @@ -189,7 +193,8 @@ public function testEventDateColumnBadOption() $this->expectException(\Exception::class); $migrationSQLs = $fromSchema->getMigrateToSql($toSchema, $this->connection->getDatabasePlatform()); $generatedSQL = implode(';', $migrationSQLs); - $this->assertEquals("CREATE TABLE test_table (event_date Date DEFAULT today(), id UInt32, payload String) ENGINE = ReplacingMergeTree(event_date, (id), 8192)", $generatedSQL); + $this->assertEquals("CREATE TABLE test_table (event_date Date DEFAULT today(), id UInt32, payload String) ENGINE = ReplacingMergeTree(event_date, (id), 8192)", + $generatedSQL); foreach ($migrationSQLs as $sql) { $this->connection->exec($sql); } @@ -211,7 +216,8 @@ public function testEventDateProviderColumnOption() $migrationSQLs = $fromSchema->getMigrateToSql($toSchema, $this->connection->getDatabasePlatform()); $generatedSQL = implode(';', $migrationSQLs); - $this->assertEquals("CREATE TABLE test_table (EventDate Date DEFAULT toDate(updated_at), id UInt32, payload String, updated_at DateTime) ENGINE = ReplacingMergeTree(EventDate, (id), 8192)", $generatedSQL); + $this->assertEquals("CREATE TABLE test_table (EventDate Date DEFAULT toDate(updated_at), id UInt32, payload String, updated_at DateTime) ENGINE = ReplacingMergeTree(EventDate, (id), 8192)", + $generatedSQL); foreach ($migrationSQLs as $sql) { $this->connection->exec($sql); } @@ -234,7 +240,8 @@ public function testEventDateProviderColumnBadOption() $this->expectException(\Exception::class); $migrationSQLs = $fromSchema->getMigrateToSql($toSchema, $this->connection->getDatabasePlatform()); $generatedSQL = implode(';', $migrationSQLs); - $this->assertEquals("CREATE TABLE test_table (EventDate Date DEFAULT toDate(updated_at), id UInt32, payload String, updated_at DateTime) ENGINE = ReplacingMergeTree(EventDate, (id), 8192)", $generatedSQL); + $this->assertEquals("CREATE TABLE test_table (EventDate Date DEFAULT toDate(updated_at), id UInt32, payload String, updated_at DateTime) ENGINE = ReplacingMergeTree(EventDate, (id), 8192)", + $generatedSQL); foreach ($migrationSQLs as $sql) { $this->connection->exec($sql); } @@ -262,7 +269,7 @@ public function testListTableIndexes() $this->assertEquals(1, \count($indexes)); - if($index = current($indexes)) { + if ($index = current($indexes)) { $this->assertInstanceOf(Index::class, $index); $this->assertEquals(['id', 'event_date'], $index->getColumns()); @@ -272,6 +279,41 @@ public function testListTableIndexes() $this->connection->exec('DROP TABLE test_indexes_table'); } + public function testTableWithSamplingExpression() + { + $fromSchema = $this->connection->getSchemaManager()->createSchema(); + $toSchema = clone $fromSchema; + + $newTable = $toSchema->createTable('test_sampling_table'); + + $newTable->addColumn('id', 'integer', ['unsigned' => true]); + $newTable->addColumn('payload', 'string'); + $newTable->addColumn('event_date', Type::DATE); + $newTable->addOption('eventDateColumn', 'event_date'); + $newTable->addOption('samplingExpression', 'intHash32(id)'); + $newTable->setPrimaryKey(['id', 'event_date']); + $migrationSQLs = $fromSchema->getMigrateToSql($toSchema, $this->connection->getDatabasePlatform()); + $generatedSQL = implode(';', $migrationSQLs); + $this->assertEquals("CREATE TABLE test_sampling_table (event_date Date DEFAULT today(), id UInt32, payload String) ENGINE = ReplacingMergeTree(event_date, intHash32(id), (id, event_date, intHash32(id)), 8192)", + $generatedSQL); + foreach ($migrationSQLs as $sql) { + $this->connection->exec($sql); + } + + $indexes = $this->connection->getSchemaManager()->listTableIndexes('test_sampling_table'); + + $this->assertEquals(1, \count($indexes)); + + if ($index = current($indexes)) { + $this->assertInstanceOf(Index::class, $index); + + $this->assertEquals(['id', 'event_date'], $index->getColumns()); + $this->assertTrue($index->isPrimary()); + } + + $this->connection->exec('DROP TABLE test_sampling_table'); + } + public function testNullableColumns() { $fromSchema = $this->connection->getSchemaManager()->createSchema();