diff --git a/src/Stores/LaravelCacheStore.php b/src/Stores/LaravelCacheStore.php index 27a0ddd..6d0df2a 100644 --- a/src/Stores/LaravelCacheStore.php +++ b/src/Stores/LaravelCacheStore.php @@ -32,6 +32,17 @@ public function get(string $key): ?string */ public function set(string $key, string $value, int $ttl): bool { - return $this->store->put($key, $value, $ttl); + $result = $this->store->put($key, $value, $ttl); + + // If the data already exists in the cache, then mysql returns 0 rows affected. Technically, this is not a + // failure. We should check for this before returning anything and return true if it does exist. + if ($result === false) { + $existingValue = $this->store->get($key); + if ($existingValue === $value) { + return true; + } + } + + return $result; } } diff --git a/tests/Laravel/Feature/LaravelStoreTest.php b/tests/Laravel/Feature/LaravelStoreTest.php index 777589d..82b4a41 100644 --- a/tests/Laravel/Feature/LaravelStoreTest.php +++ b/tests/Laravel/Feature/LaravelStoreTest.php @@ -4,6 +4,7 @@ use Saloon\RateLimitPlugin\Limit; use Illuminate\Support\Facades\Cache; +use Illuminate\Contracts\Cache\Repository; use Saloon\RateLimitPlugin\Stores\LaravelCacheStore; test('it records and can check exceeded limits', function () { @@ -37,3 +38,17 @@ 'hits' => 1, ])); }); + +test('it handles MySQL upsert behavior returning false for identical data', function () { + $mockCache = Mockery::mock(Repository::class); + + $key = 'test:limit'; + $value = json_encode(['timestamp' => time() + 60, 'hits' => 1]); + + $mockCache->shouldReceive('put')->with($key, $value, Mockery::any())->andReturn(false); + $mockCache->shouldReceive('get')->with($key)->andReturn($value); + + $store = new LaravelCacheStore($mockCache); + + expect($store->set($key, $value, 60))->toBeTrue(); +});