diff --git a/README.md b/README.md index c3e5f9b..1d3c1f9 100644 --- a/README.md +++ b/README.md @@ -36,17 +36,16 @@ composer require utopia-php/usage use Utopia\Usage\Usage; use Utopia\Usage\Adapter\ClickHouse; +// Configuration is fixed at construction; only the tenant changes per request. $adapter = new ClickHouse( host: 'clickhouse-server', username: 'default', password: '', port: 8123, - secure: false + secure: false, + namespace: 'my_app', + sharedTables: true, ); - -// Multi-tenant setup -$adapter->setNamespace('my_app'); -$adapter->setSharedTables(true); $adapter->setTenant('project_123'); $usage = new Usage($adapter); @@ -333,9 +332,11 @@ Extend `Utopia\Usage\Adapter` and implement: - `sumDaily(array $queries, string $attribute): int` - `sumDailyBatch(array $metrics, array $queries): array` - `purge(array $queries, ?string $type): bool` -- `setNamespace(string $namespace): self` - `setTenant(?string $tenant): self` -- `setSharedTables(bool $sharedTables): self` + +Namespace, database, shared-tables mode, async inserts, query logging and the +dual-read sample rate are set once via the adapter constructor (see "Using +ClickHouse Adapter" above). Only the tenant changes over an instance's lifetime. ## System Requirements diff --git a/src/Usage/Adapter.php b/src/Usage/Adapter.php index 79c2efd..20c53ed 100644 --- a/src/Usage/Adapter.php +++ b/src/Usage/Adapter.php @@ -158,18 +158,4 @@ abstract public function sumDaily(array $queries = [], string $attribute = 'valu * @return array Metric name => sum value */ abstract public function sumDailyBatch(array $metrics, array $queries = []): array; - - /** - * Enable parity sampling for routed reads. At rate=0 the sampler is - * disabled (default). At rate>0 each routed read is re-executed against - * the raw table with the given probability and logs a dual_read_warning - * entry when totals diverge by more than 1%. Pass 1.0 for every-read - * sampling (CI use) or small values (0.01) for production canaries. - * - * Adapters without parity sampling override this with a no-op. - */ - public function setDualReadSampleRate(float $rate): self - { - return $this; - } } diff --git a/src/Usage/Adapter/ClickHouse.php b/src/Usage/Adapter/ClickHouse.php index 698915a..6b87e7b 100644 --- a/src/Usage/Adapter/ClickHouse.php +++ b/src/Usage/Adapter/ClickHouse.php @@ -79,36 +79,30 @@ class ClickHouse extends SQL Query::TYPE_ENDS_WITH, ]; - private string $host; + private readonly string $host; - private int $port; + private readonly int $port; - private string $database = self::DEFAULT_DATABASE; + private readonly string $database; private string $table = self::DEFAULT_TABLE; - private string $username; + private readonly string $username; - private string $password; + private readonly string $password; /** @var bool Whether to use HTTPS for ClickHouse HTTP interface */ - private bool $secure = false; + private readonly bool $secure; - private ClientInterface $client; + private readonly ClientInterface $client; - private RequestFactory $requestFactory; + private readonly RequestFactory $requestFactory; protected ?string $tenant = null; - protected bool $sharedTables = false; + protected readonly bool $sharedTables; - protected string $namespace = ''; - - /** @var bool Whether to log queries for debugging */ - private bool $enableQueryLogging = false; - - /** @var array, duration: float, timestamp: float, success: bool, error?: string}> Query execution log */ - private array $queryLog = []; + protected readonly string $namespace; /** @var int Number of requests made using this adapter instance */ private int $requestCount = 0; @@ -117,10 +111,10 @@ class ClickHouse extends SQL private ?string $operationContext = null; /** @var bool Whether to enable ClickHouse async inserts (server-side batching) */ - private bool $asyncInserts = false; + private readonly bool $asyncInserts; /** @var bool Whether to wait for async insert confirmation before returning */ - private bool $asyncInsertWait = true; + private readonly bool $asyncInsertWait; /** * Opt-in query_id forwarded to ClickHouse on the next query() call only. @@ -141,7 +135,7 @@ class ClickHouse extends SQL * the raw events table and logs the delta. Recommended 0.01 for * progressive rollout; default 0.0 (off). */ - private float $dualReadSampleRate = 0.0; + private readonly float $dualReadSampleRate; /** * @param string $host ClickHouse host @@ -154,6 +148,16 @@ class ClickHouse extends SQL * timeouts, TLS, or retries — e.g. wrap an adapter in * `Utopia\Client\Decorator\Retry`, or pass a `Utopia\Client\Pool` to share a * bounded set of connections across concurrent (coroutine) callers. + * @param string $namespace Table name prefix for multi-project support + * @param string $database ClickHouse database name (default: 'default') + * @param bool $sharedTables Whether tables are shared across tenants + * @param bool $asyncInserts Whether to use ClickHouse async inserts (server-side batching) + * @param bool $asyncInsertWait Whether to wait for async insert confirmation before returning + * @param float $dualReadSampleRate Parity-sampling rate, clamped to + * 0.0 (off) … 1.0 (every read). When > 0 each eligible routed read is + * re-executed against the raw events table and logs a `warning` route + * entry if the totals diverge by >1%. Use 0.01 for a production canary + * or 1.0 in CI. */ public function __construct( string $host, @@ -161,16 +165,34 @@ public function __construct( string $password = '', int $port = self::DEFAULT_PORT, bool $secure = false, - ?ClientInterface $client = null + ?ClientInterface $client = null, + string $namespace = '', + string $database = self::DEFAULT_DATABASE, + bool $sharedTables = false, + bool $asyncInserts = false, + bool $asyncInsertWait = true, + float $dualReadSampleRate = 0.0 ) { $this->validateHost($host); $this->validatePort($port); + if (!empty($namespace)) { + $this->validateIdentifier($namespace, 'Namespace'); + } + $this->validateIdentifier($database, 'Database'); $this->host = $host; $this->port = $port; $this->username = $username; $this->password = $password; $this->secure = $secure; + $this->namespace = $namespace; + $this->database = $database; + $this->sharedTables = $sharedTables; + $this->asyncInserts = $asyncInserts; + $this->asyncInsertWait = $asyncInsertWait; + // Clamp to [0.0, 1.0] so out-of-range rates can't disable or + // over-trigger the parity sampler. + $this->dualReadSampleRate = max(0.0, min(1.0, $dualReadSampleRate)); // `withConnectionReuse()` keeps the underlying cURL handle alive across // requests so the TCP/TLS handshake is paid once. Auth and database are @@ -180,32 +202,6 @@ public function __construct( $this->requestFactory = new RequestFactory(); } - /** - * Enable or disable query logging for debugging. - * - * @param bool $enable Whether to enable query logging - * @return self - */ - public function enableQueryLogging(bool $enable = true): self - { - $this->enableQueryLogging = $enable; - return $this; - } - - /** - * Enable or disable ClickHouse async inserts (server-side batching). - * - * @param bool $enable Whether to enable async inserts - * @param bool $waitForConfirmation Whether to wait for server-side flush before returning - * @return self - */ - public function setAsyncInserts(bool $enable, bool $waitForConfirmation = true): self - { - $this->asyncInserts = $enable; - $this->asyncInsertWait = $waitForConfirmation; - return $this; - } - /** * Forward a single-use query_id to ClickHouse on the next query() call. * Cleared after one dispatch. @@ -236,61 +232,20 @@ public function clearRouteLog(): self return $this; } - /** - * Sample rate for dual-read parity checks. When > 0, eligible - * routed reads also execute against the raw events table and log a - * `warning` route entry if the totals diverge by >1%. - * - * @param float $rate 0.0 (off) … 1.0 (every read) - */ - public function setDualReadSampleRate(float $rate): self - { - if ($rate < 0.0) { - $rate = 0.0; - } - if ($rate > 1.0) { - $rate = 1.0; - } - $this->dualReadSampleRate = $rate; - return $this; - } - /** * Get connection statistics for monitoring. * - * @return array{request_count: int, query_logging_enabled: bool, async_inserts: bool, async_insert_wait: bool} + * @return array{request_count: int, async_inserts: bool, async_insert_wait: bool} */ public function getConnectionStats(): array { return [ 'request_count' => $this->requestCount, - 'query_logging_enabled' => $this->enableQueryLogging, 'async_inserts' => $this->asyncInserts, 'async_insert_wait' => $this->asyncInsertWait, ]; } - /** - * Get the query execution log. - * - * @return array, duration: float, timestamp: float, success: bool, error?: string}> - */ - public function getQueryLog(): array - { - return $this->queryLog; - } - - /** - * Clear the query execution log. - * - * @return self - */ - public function clearQueryLog(): self - { - $this->queryLog = []; - return $this; - } - /** * Get adapter name. */ @@ -416,58 +371,14 @@ private function escapeIdentifier(string $identifier): string return '`' . str_replace('`', '``', $identifier) . '`'; } - /** - * Set the namespace for multi-project support. - * - * @param string $namespace - * @return self - * @throws Exception - */ - public function setNamespace(string $namespace): self - { - if (!empty($namespace)) { - $this->validateIdentifier($namespace, 'Namespace'); - } - $this->namespace = $namespace; - return $this; - } - - /** - * Set the database name for subsequent operations. - * - * @param string $database - * @return self - * @throws Exception - */ - public function setDatabase(string $database): self - { - $this->validateIdentifier($database, 'Database'); - $this->database = $database; - return $this; - } - - /** - * Enable or disable HTTPS for ClickHouse HTTP interface. - */ - public function setSecure(bool $secure): self - { - $this->secure = $secure; - return $this; - } - - /** - * Get the namespace. - * - * @return string - */ - public function getNamespace(): string - { - return $this->namespace; - } - /** * Set the tenant ID for multi-tenant support. * + * Tenant is the one piece of adapter configuration that legitimately + * changes over an instance's lifetime — a single adapter serves many + * tenants across requests — so it stays a mutable setter while the rest + * of the configuration is fixed at construction. + * * @param string|null $tenant * @return self */ @@ -477,38 +388,6 @@ public function setTenant(?string $tenant): self return $this; } - /** - * Get the tenant ID. - * - * @return string|null - */ - public function getTenant(): ?string - { - return $this->tenant; - } - - /** - * Set whether tables are shared across tenants. - * - * @param bool $sharedTables - * @return self - */ - public function setSharedTables(bool $sharedTables): self - { - $this->sharedTables = $sharedTables; - return $this; - } - - /** - * Get whether tables are shared across tenants. - * - * @return bool - */ - public function isSharedTables(): bool - { - return $this->sharedTables; - } - /** * Get the base table name with namespace prefix. * @@ -571,36 +450,6 @@ private function buildTableReference(string $tableName): string return $this->escapeIdentifier($this->database) . '.' . $this->escapeIdentifier($tableName); } - /** - * Log a query execution for debugging purposes. - * - * @param string $sql SQL query executed - * @param array $params Query parameters - * @param float $duration Execution duration in seconds - * @param bool $success Whether the query succeeded - * @param string|null $error Error message if query failed - */ - private function logQuery(string $sql, array $params, float $duration, bool $success, ?string $error = null): void - { - if (!$this->enableQueryLogging) { - return; - } - - $logEntry = [ - 'sql' => $sql, - 'params' => $params, - 'duration' => $duration, - 'timestamp' => microtime(true), - 'success' => $success, - ]; - - if ($error !== null) { - $logEntry['error'] = $error; - } - - $this->queryLog[] = $logEntry; - } - /** * Set the current operation context for better error messages. * @@ -655,7 +504,6 @@ private function query(string $sql, array $params = []): string $queryId = $this->nextQueryId; $this->nextQueryId = null; - $startTime = microtime(true); $scheme = $this->secure ? 'https' : 'http'; // ClickHouse reads `query` and `param_*` from a multipart/form-data @@ -681,23 +529,18 @@ private function query(string $sql, array $params = []): string try { $response = $this->client->sendRequest($request); } catch (Throwable $e) { - $duration = microtime(true) - $startTime; $errorMsg = $this->buildErrorMessage("ClickHouse query failed: {$e->getMessage()}", null, $sql); - $this->logQuery($sql, $params, $duration, false, $errorMsg); throw new Exception($errorMsg, 0, $e); } $httpCode = $response->getStatusCode(); $bodyStr = (string) $response->getBody(); - $duration = microtime(true) - $startTime; if ($httpCode !== 200) { $errorMsg = $this->buildErrorMessage("ClickHouse query failed with HTTP {$httpCode}: {$bodyStr}", null, $sql); - $this->logQuery($sql, $params, $duration, false, $errorMsg); throw new Exception($errorMsg); } - $this->logQuery($sql, $params, $duration, true); return $bodyStr; } @@ -777,7 +620,6 @@ private function insert(string $table, array $data): void // deduplication, so a retried insert that reaches the server twice // leaves duplicate rows behind. The default transport does not retry // POST; any injected retry strategy must keep it that way. - $startTime = microtime(true); $scheme = $this->secure ? 'https' : 'http'; $escapedTable = $this->escapeIdentifier($table); $rowCount = count($data); @@ -792,31 +634,21 @@ private function insert(string $table, array $data): void $this->requestCount++; $body = implode("\n", $data); - $sql = "INSERT INTO {$escapedTable} FORMAT JSONEachRow"; - $params = ['rows' => $rowCount, 'bytes' => strlen($body)]; $request = $this->requestFactory->body(Method::POST, $url, $body, 'application/x-ndjson', $this->buildHeaders()); try { $response = $this->client->sendRequest($request); } catch (Throwable $e) { - $duration = microtime(true) - $startTime; $errorMsg = $this->buildErrorMessage("ClickHouse insert failed: {$e->getMessage()}", $table, "INSERT INTO {$table} ({$rowCount} rows)"); - $this->logQuery($sql, $params, $duration, false, $errorMsg); throw new Exception($errorMsg, 0, $e); } - $httpCode = $response->getStatusCode(); - $duration = microtime(true) - $startTime; - - if ($httpCode !== 200) { + if ($response->getStatusCode() !== 200) { $bodyStr = (string) $response->getBody(); - $errorMsg = $this->buildErrorMessage("ClickHouse insert failed with HTTP {$httpCode}: {$bodyStr}", $table, "INSERT INTO {$table} ({$rowCount} rows)"); - $this->logQuery($sql, $params, $duration, false, $errorMsg); + $errorMsg = $this->buildErrorMessage("ClickHouse insert failed with HTTP {$response->getStatusCode()}: {$bodyStr}", $table, "INSERT INTO {$table} ({$rowCount} rows)"); throw new Exception($errorMsg); } - - $this->logQuery($sql, $params, $duration, true); } /** diff --git a/src/Usage/Adapter/Database.php b/src/Usage/Adapter/Database.php index 2f2f9ac..b008be6 100644 --- a/src/Usage/Adapter/Database.php +++ b/src/Usage/Adapter/Database.php @@ -622,21 +622,14 @@ private function withTypeFilter(array $queries, ?string $type): array return array_merge($queries, [Query::equal('type', [$type])]); } - /** - * Set the namespace prefix for table names. - * - * @param string $namespace - * @return self - */ - public function setNamespace(string $namespace): self - { - $this->db->setNamespace($namespace); - return $this; - } - /** * Set the tenant ID for multi-tenant support. * + * Tenant is the one piece of configuration that changes over an + * instance's lifetime (a single adapter serves many tenants across + * requests), so it stays a mutable setter. Namespace and shared-tables + * mode are configured directly on the injected Utopia\Database instance. + * * @param string|null $tenant * @return self */ @@ -651,16 +644,4 @@ public function setTenant(?string $tenant): self $this->db->setTenant($tenant !== null ? (int) $tenant : null); return $this; } - - /** - * Enable or disable shared tables mode. - * - * @param bool $sharedTables - * @return self - */ - public function setSharedTables(bool $sharedTables): self - { - $this->db->setSharedTables($sharedTables); - return $this; - } } diff --git a/src/Usage/Usage.php b/src/Usage/Usage.php index 1715bd6..3097de1 100644 --- a/src/Usage/Usage.php +++ b/src/Usage/Usage.php @@ -263,25 +263,6 @@ public function sumDailyBatch(array $metrics, array $queries = []): array return $this->adapter->sumDailyBatch($metrics, $queries); } - /** - * Set the namespace prefix for table names. - * - * Flushes the buffer first so any pending metrics are written under the - * previous namespace — buffered entries don't carry adapter context. - * - * @param string $namespace - * @return $this - * @throws \Exception - */ - public function setNamespace(string $namespace): self - { - $this->flush(); - if (method_exists($this->adapter, 'setNamespace')) { - $this->adapter->setNamespace($namespace); - } - return $this; - } - /** * Set the tenant ID for multi-tenant support. * @@ -301,40 +282,6 @@ public function setTenant(?string $tenant): self return $this; } - /** - * Enable or disable shared tables mode (multi-tenant with tenant column). - * - * Flushes the buffer first so any pending metrics are written under the - * previous mode — buffered entries don't carry adapter context. - * - * @param bool $sharedTables - * @return $this - * @throws \Exception - */ - public function setSharedTables(bool $sharedTables): self - { - $this->flush(); - if (method_exists($this->adapter, 'setSharedTables')) { - $this->adapter->setSharedTables($sharedTables); - } - return $this; - } - - /** - * Enable parity sampling for routed reads. At rate=0 the sampler is - * disabled (default). At rate>0 each routed read is re-executed against - * the raw table with the given probability and logs a `dual_read_warning` - * entry when totals diverge by more than 1%. Pass 1.0 for every-read - * sampling (CI use) or small values (0.01) for production canaries. - * - * @param float $rate 0.0 (off) … 1.0 (every read) - */ - public function setDualReadSampleRate(float $rate): self - { - $this->adapter->setDualReadSampleRate($rate); - return $this; - } - /** * Collect a metric into the in-memory buffer for deferred flushing. * diff --git a/tests/Benchmark/BenchmarkBase.php b/tests/Benchmark/BenchmarkBase.php index 5749ae8..c86acce 100644 --- a/tests/Benchmark/BenchmarkBase.php +++ b/tests/Benchmark/BenchmarkBase.php @@ -55,15 +55,18 @@ protected function setUp(): void $port = (int) (getenv('CLICKHOUSE_PORT') ?: 8123); $secure = (bool) (getenv('CLICKHOUSE_SECURE') ?: false); - $this->adapter = new ClickHouseAdapter($host, $username, $password, $port, $secure); - $this->adapter->setNamespace($this->namespace); - $this->adapter->setSharedTables(true); + $this->adapter = new ClickHouseAdapter( + $host, + $username, + $password, + $port, + $secure, + namespace: $this->namespace, + database: getenv('CLICKHOUSE_DATABASE') ?: 'default', + sharedTables: true, + ); $this->adapter->setTenant($this->tenant); - if ($database = getenv('CLICKHOUSE_DATABASE')) { - $this->adapter->setDatabase($database); - } - $this->usage = new Usage($this->adapter); $this->usage->setup(); diff --git a/tests/Usage/Adapter/ClickHouseTest.php b/tests/Usage/Adapter/ClickHouseTest.php index 92f0a83..28b2abb 100644 --- a/tests/Usage/Adapter/ClickHouseTest.php +++ b/tests/Usage/Adapter/ClickHouseTest.php @@ -22,15 +22,17 @@ protected function initializeUsage(): void $secure = (bool) (getenv('CLICKHOUSE_SECURE') ?: false); - $adapter = new ClickHouseAdapter($host, $username, $password, $port, $secure); - $adapter->setNamespace('utopia_usage'); + $adapter = new ClickHouseAdapter( + $host, + $username, + $password, + $port, + $secure, + namespace: 'utopia_usage', + database: getenv('CLICKHOUSE_DATABASE') ?: 'default', + ); $adapter->setTenant('1'); - // Optional customization via env vars - if ($database = getenv('CLICKHOUSE_DATABASE')) { - $adapter->setDatabase($database); - } - $this->usage = new Usage($adapter); $this->usage->setup(); } @@ -43,15 +45,18 @@ public function testMetricTenantOverridesAdapterTenantInBatch(): void $port = (int) (getenv('CLICKHOUSE_PORT') ?: 8123); $secure = (bool) (getenv('CLICKHOUSE_SECURE') ?: false); - $adapter = new ClickHouseAdapter($host, $username, $password, $port, $secure); - $adapter->setNamespace('utopia_usage_shared'); - $adapter->setSharedTables(true); + $adapter = new ClickHouseAdapter( + $host, + $username, + $password, + $port, + $secure, + namespace: 'utopia_usage_shared', + database: getenv('CLICKHOUSE_DATABASE') ?: 'default', + sharedTables: true, + ); $adapter->setTenant('1'); - if ($database = getenv('CLICKHOUSE_DATABASE')) { - $adapter->setDatabase($database); - } - $usage = new Usage($adapter); $usage->setup(); $usage->purge(); @@ -742,14 +747,17 @@ public function testConnectionPooling(): void $port = (int) (getenv('CLICKHOUSE_PORT') ?: 8123); $secure = (bool) (getenv('CLICKHOUSE_SECURE') ?: false); - $adapter = new ClickHouseAdapter($host, $username, $password, $port, $secure); - $adapter->setNamespace('utopia_usage_pooling_test'); + $adapter = new ClickHouseAdapter( + $host, + $username, + $password, + $port, + $secure, + namespace: 'utopia_usage_pooling_test', + database: getenv('CLICKHOUSE_DATABASE') ?: 'default', + ); $adapter->setTenant('1'); - if ($database = getenv('CLICKHOUSE_DATABASE')) { - $adapter->setDatabase($database); - } - $usage = new Usage($adapter); $usage->setup(); @@ -758,7 +766,6 @@ public function testConnectionPooling(): void // can confirm requests are flowing over the pooled connection. $stats = $adapter->getConnectionStats(); $this->assertArrayHasKey('request_count', $stats); - $this->assertArrayHasKey('query_logging_enabled', $stats); $initialCount = $stats['request_count']; @@ -786,9 +793,15 @@ public function testErrorMessagesIncludeContext(): void $port = (int) (getenv('CLICKHOUSE_PORT') ?: 8123); $secure = (bool) (getenv('CLICKHOUSE_SECURE') ?: false); - $adapter = new ClickHouseAdapter($host, $username, $password, $port, $secure); - $adapter->setNamespace('utopia_usage_error_test'); - $adapter->setDatabase('nonexistent_db_for_testing_errors_12345'); + $adapter = new ClickHouseAdapter( + $host, + $username, + $password, + $port, + $secure, + namespace: 'utopia_usage_error_test', + database: 'nonexistent_db_for_testing_errors_12345', + ); $adapter->setTenant('1'); $usage = new Usage($adapter); @@ -819,17 +832,25 @@ public function testAsyncInsertConfiguration(): void $port = (int) (getenv('CLICKHOUSE_PORT') ?: 8123); $secure = (bool) (getenv('CLICKHOUSE_SECURE') ?: false); - $adapter = new ClickHouseAdapter($host, $username, $password, $port, $secure); - $adapter->setNamespace('utopia_usage_async'); + $database = getenv('CLICKHOUSE_DATABASE') ?: 'default'; + + $makeAdapter = static fn (bool $asyncInserts, bool $asyncInsertWait): ClickHouseAdapter => + new ClickHouseAdapter( + $host, + $username, + $password, + $port, + $secure, + namespace: 'utopia_usage_async', + database: $database, + asyncInserts: $asyncInserts, + asyncInsertWait: $asyncInsertWait, + ); + + // Async inserts enabled, waiting for confirmation. + $adapter = $makeAdapter(true, true); $adapter->setTenant('1'); - if ($database = getenv('CLICKHOUSE_DATABASE')) { - $adapter->setDatabase($database); - } - - // Enable async inserts - $adapter->setAsyncInserts(true, waitForConfirmation: true); - $stats = $adapter->getConnectionStats(); $this->assertTrue($stats['async_inserts']); $this->assertTrue($stats['async_insert_wait']); @@ -846,14 +867,13 @@ public function testAsyncInsertConfiguration(): void $total = $usage->getTotal('async-test', [], Usage::TYPE_EVENT); $this->assertEquals(42, $total); - // Test fire-and-forget mode - $adapter->setAsyncInserts(true, waitForConfirmation: false); - $stats = $adapter->getConnectionStats(); + // Fire-and-forget mode: async on, no wait for confirmation. + $stats = $makeAdapter(true, false)->getConnectionStats(); + $this->assertTrue($stats['async_inserts']); $this->assertFalse($stats['async_insert_wait']); - // Disable async inserts - $adapter->setAsyncInserts(false); - $stats = $adapter->getConnectionStats(); + // Async inserts disabled. + $stats = $makeAdapter(false, true)->getConnectionStats(); $this->assertFalse($stats['async_inserts']); $usage->purge(); diff --git a/tests/Usage/Adapter/ClickHouseTestCase.php b/tests/Usage/Adapter/ClickHouseTestCase.php index 9836dce..b9c2df0 100644 --- a/tests/Usage/Adapter/ClickHouseTestCase.php +++ b/tests/Usage/Adapter/ClickHouseTestCase.php @@ -27,17 +27,22 @@ protected function makeAdapter(string $namespace, ?string $tenant = '1'): ClickH $port = (int) (getenv('CLICKHOUSE_PORT') ?: 8123); $secure = (bool) (getenv('CLICKHOUSE_SECURE') ?: false); - $adapter = new ClickHouseAdapter($host, $username, $password, $port, $secure); - $adapter->setNamespace($namespace); - $adapter->setSharedTables(true); + $database = getenv('CLICKHOUSE_DATABASE') ?: 'default'; + + $adapter = new ClickHouseAdapter( + $host, + $username, + $password, + $port, + $secure, + namespace: $namespace, + database: $database, + sharedTables: true, + ); if ($tenant !== null) { $adapter->setTenant($tenant); } - if ($database = getenv('CLICKHOUSE_DATABASE')) { - $adapter->setDatabase($database); - } - return $adapter; }