diff --git a/src/Audit/Adapter/ClickHouse.php b/src/Audit/Adapter/ClickHouse.php index 1524a5d..760c553 100644 --- a/src/Audit/Adapter/ClickHouse.php +++ b/src/Audit/Adapter/ClickHouse.php @@ -84,15 +84,13 @@ class ClickHouse extends SQL protected bool $asyncCleanup = false; - /** @var int|null Retention in days; when set, setup() applies a TTL on the table. Null disables TTL. */ - private ?int $retention = null; - /** * @param string $host ClickHouse host * @param string $username ClickHouse username (default: 'default') * @param string $password ClickHouse password (default: '') * @param int $port ClickHouse HTTP port (default: 8123) * @param bool $secure Whether to use HTTPS (default: false) + * @param int|null $retention Retention window in days; when set, setup() applies a TTL so rows older than the window are dropped. Null disables TTL. * @throws Exception If validation fails */ public function __construct( @@ -100,10 +98,12 @@ public function __construct( string $username = 'default', string $password = '', int $port = self::DEFAULT_PORT, - bool $secure = false + bool $secure = false, + public ?int $retention = null, ) { $this->validateHost($host); $this->validatePort($port); + $this->validateRetention($retention); $this->host = $host; $this->port = $port; @@ -354,41 +354,41 @@ public function setAsyncCleanup(bool $asyncCleanup): self } /** - * Get whether cleanup() runs asynchronously. + * Set the retention window in days applied by setup() as a TTL, or null to + * disable it. Call before setup(); a single adapter can setup() several + * tables (differing namespaces), so retention is settable per table rather + * than fixed at construction. * - * @return bool + * @param int|null $retention + * @return self + * @throws Exception If retention is not a positive number of days. */ - public function isAsyncCleanup(): bool + public function setRetention(?int $retention): self { - return $this->asyncCleanup; + $this->validateRetention($retention); + $this->retention = $retention; + return $this; } /** - * Set the retention window in days. When set, setup() applies a TTL so - * rows older than the window are dropped by background merges. Pass null - * to disable (the default). - * - * @param int|null $days - * @return self - * @throws Exception If $days is not positive + * @param int|null $retention + * @throws Exception If retention is set but not a positive number of days. */ - public function setRetention(?int $days): self + private function validateRetention(?int $retention): void { - if ($days !== null && $days < 1) { + if ($retention !== null && $retention < 1) { throw new Exception('Retention must be a positive number of days'); } - $this->retention = $days; - return $this; } /** - * Get the retention window in days, or null when TTL is disabled. + * Get whether cleanup() runs asynchronously. * - * @return int|null + * @return bool */ - public function getRetention(): ?int + public function isAsyncCleanup(): bool { - return $this->retention; + return $this->asyncCleanup; } /** diff --git a/tests/Audit/Adapter/ClickHouseTest.php b/tests/Audit/Adapter/ClickHouseTest.php index c3c6a40..1efc86e 100644 --- a/tests/Audit/Adapter/ClickHouseTest.php +++ b/tests/Audit/Adapter/ClickHouseTest.php @@ -377,27 +377,30 @@ public function testSetSecure(): void } /** - * Test setRetention stores the value and getRetention returns it + * Test retention defaults to null and is stored when passed to the constructor */ - public function testSetRetention(): void + public function testRetention(): void { $adapter = new ClickHouse( host: 'clickhouse', username: 'default', password: 'clickhouse' ); + $this->assertNull($adapter->retention); - $this->assertNull($adapter->getRetention()); - - $result = $adapter->setRetention(30); - $this->assertInstanceOf(ClickHouse::class, $result); - $this->assertEquals(30, $adapter->getRetention()); + $adapter = new ClickHouse( + host: 'clickhouse', + username: 'default', + password: 'clickhouse', + retention: 30 + ); + $this->assertEquals(30, $adapter->retention); } /** - * Test setRetention accepts null to disable retention + * Test retention can be set and cleared per table via the fluent setter */ - public function testSetRetentionAcceptsNull(): void + public function testSetRetention(): void { $adapter = new ClickHouse( host: 'clickhouse', @@ -405,43 +408,47 @@ public function testSetRetentionAcceptsNull(): void password: 'clickhouse' ); - $adapter->setRetention(30); + $this->assertSame($adapter, $adapter->setRetention(30)); + $this->assertEquals(30, $adapter->retention); + $adapter->setRetention(null); - $this->assertNull($adapter->getRetention()); + $this->assertNull($adapter->retention); + + $this->expectException(Exception::class); + $this->expectExceptionMessage('Retention must be a positive number of days'); + $adapter->setRetention(0); } /** - * Test setRetention rejects zero days + * Test retention rejects zero days */ - public function testSetRetentionRejectsZero(): void + public function testRetentionRejectsZero(): void { $this->expectException(Exception::class); $this->expectExceptionMessage('Retention must be a positive number of days'); - $adapter = new ClickHouse( + new ClickHouse( host: 'clickhouse', username: 'default', - password: 'clickhouse' + password: 'clickhouse', + retention: 0 ); - - $adapter->setRetention(0); } /** - * Test setRetention rejects negative days + * Test retention rejects negative days */ - public function testSetRetentionRejectsNegative(): void + public function testRetentionRejectsNegative(): void { $this->expectException(Exception::class); $this->expectExceptionMessage('Retention must be a positive number of days'); - $adapter = new ClickHouse( + new ClickHouse( host: 'clickhouse', username: 'default', - password: 'clickhouse' + password: 'clickhouse', + retention: -1 ); - - $adapter->setRetention(-1); } /**