From f1948f219d274a6a17594045b50b84746ebfe828 Mon Sep 17 00:00:00 2001 From: rishtigupta <127137312+rishtigupta@users.noreply.github.com> Date: Thu, 17 Oct 2024 09:12:53 -0700 Subject: [PATCH] feat: add sortedSetRemoveElement api (#222) --- src/Cache/CacheClient.php | 51 +++++++++++++++- .../CacheOperationTypes.php | 58 +++++++++++++++++++ src/Cache/Internal/ScsDataClient.php | 45 ++++++++++++++ tests/Cache/CacheClientTest.php | 55 +++++++++++++++++- 4 files changed, 207 insertions(+), 2 deletions(-) diff --git a/src/Cache/CacheClient.php b/src/Cache/CacheClient.php index acd1b87..123db6b 100644 --- a/src/Cache/CacheClient.php +++ b/src/Cache/CacheClient.php @@ -51,6 +51,7 @@ use Momento\Cache\CacheOperationTypes\CreateCacheResponse; use Momento\Cache\CacheOperationTypes\DeleteCacheResponse; use Momento\Cache\CacheOperationTypes\ListCachesResponse; +use Momento\Cache\CacheOperationTypes\SortedSetRemoveElementResponse; use Momento\Cache\CacheOperationTypes\UpdateTtlResponse; use Momento\Cache\Errors\InvalidArgumentError; use Momento\Cache\Internal\IdleDataClientWrapper; @@ -1730,7 +1731,7 @@ public function setRemoveElement(string $cacheName, string $setName, string $ele * @param float $score The score to assign to the value. * @param CollectionTtl|null $ttl TTL for the sorted set in the cache. This TTL takes precedence over the TTL used when initializing a cache client. Defaults to the client TTL. * @return ResponseFuture A waitable future which - * will provide the result of the set operation upon a blocking call to + * will provide the result of the sorted set put element operation upon a blocking call to * wait. * $response = $responseFuture->wait();
* The response represents the result of the sorted set put element operation. @@ -1904,6 +1905,54 @@ private function getNextDataClient(): ScsDataClient return $client; } + /** + * Remove an element to a sorted set. + * + * @param string $cacheName Name of the cache that contains the sorted set. + * @param string $sortedSetName The set to remove the element from. + * @param string $value The value to remove. + * @return ResponseFuture A waitable future which + * will provide the result of the sorted set remove element operation upon a blocking call to + * wait. + * $response = $responseFuture->wait();
+ * The response represents the result of the sorted set remove element operation. + * This result is resolved to a type-safe object of one of the following + * types:
+ * * SortedSetRemoveElementSuccess
+ * * SortedSetRemoveElementError
+ * + * if ($error = $response->asError()) { + * // handle error condition + * } + * + * If inspection of the response is not required, one need not call wait as + * we implicitly wait for completion of the request on destruction of the + * response future. + */ + public function sortedSetRemoveElementAsync(string $cacheName, string $sortedSetName, string $value): ResponseFuture + { + return $this->getNextDataClient()->sortedSetRemoveElement($cacheName, $sortedSetName, $value); + } + + /** + * Remove an element to a sorted set. + * + * @param string $cacheName Name of the cache that contains the sorted set. + * @param string $sortedSetName The set to remove the element from. + * @param string $value The value to add. + * @return SortedSetRemoveElementResponse Represents the result of the sorted set remove element operation. + * This result is resolved to a type-safe object of one of the following types:
+ * * SortedSetRemoveElementSuccess
+ * * SortedSetRemoveElementError
+ * if ($error = $response->asError()) {
+ *   // handle error condition
+ * } + */ + public function sortedSetRemoveElement(string $cacheName, string $sortedSetName, string $value): SortedSetRemoveElementResponse + { + return $this->sortedSetRemoveElementAsync($cacheName, $sortedSetName, $value)->wait(); + } + /** * Gets the cache values stored for given keys. * diff --git a/src/Cache/CacheOperationTypes/CacheOperationTypes.php b/src/Cache/CacheOperationTypes/CacheOperationTypes.php index 1005ddd..0ebab6f 100644 --- a/src/Cache/CacheOperationTypes/CacheOperationTypes.php +++ b/src/Cache/CacheOperationTypes/CacheOperationTypes.php @@ -3508,6 +3508,64 @@ public function __construct(string $value, SdkError $error) } } +/** + * Parent response type for a sorted set remove element request. The + * response object is resolved to a type-safe object of one of + * the following subtypes: + * + * * SortedSetRemoveElementSuccess + * * SortedSetRemoveElementError + * + * Pattern matching can be used to operate on the appropriate subtype. + * For example: + * + * if ($response->asSuccess()) { + * // handle success as appropriate + * } elseif ($error = $response->asError()) + * // handle error as appropriate + * } + * + */ +abstract class SortedSetRemoveElementResponse extends ResponseBase +{ + /** + * @return SortedSetRemoveElementSuccess|null Returns the success subtype if the request was successful and null otherwise. + */ + public function asSuccess(): ?SortedSetRemoveElementSuccess + { + if ($this->isSuccess()) { + return $this; + } + return null; + } + + /** + * @return SortedSetRemoveElementError|null Returns the error subtype if the request returned an error and null otherwise. + */ + public function asError(): ?SortedSetRemoveElementError + { + if ($this->isError()) { + return $this; + } + return null; + } +} + +/** + * Indicates that the request that generated it was successful. + */ +class SortedSetRemoveElementSuccess extends SortedSetRemoveElementResponse +{ +} + +/** + * Contains information about an error returned from the request. + */ +class SortedSetRemoveElementError extends SortedSetRemoveElementResponse +{ + use ErrorBody; +} + abstract class GetBatchResponse extends ResponseBase { /** diff --git a/src/Cache/Internal/ScsDataClient.php b/src/Cache/Internal/ScsDataClient.php index 7f47224..9182dd6 100644 --- a/src/Cache/Internal/ScsDataClient.php +++ b/src/Cache/Internal/ScsDataClient.php @@ -36,6 +36,7 @@ use Cache_client\_SortedSetFetchRequest; use Cache_client\_SortedSetGetScoreRequest; use Cache_client\_SortedSetPutRequest; +use Cache_client\_SortedSetRemoveRequest; use Cache_client\_UpdateTtlRequest; use Cache_client\ECacheResult; use Common\_Unbounded; @@ -198,6 +199,9 @@ use Momento\Cache\CacheOperationTypes\SortedSetPutElementError; use Momento\Cache\CacheOperationTypes\SortedSetPutElementResponse; use Momento\Cache\CacheOperationTypes\SortedSetPutElementSuccess; +use Momento\Cache\CacheOperationTypes\SortedSetRemoveElementError; +use Momento\Cache\CacheOperationTypes\SortedSetRemoveElementResponse; +use Momento\Cache\CacheOperationTypes\SortedSetRemoveElementSuccess; use Momento\Cache\CacheOperationTypes\UpdateTtlError; use Momento\Cache\CacheOperationTypes\UpdateTtlMiss; use Momento\Cache\CacheOperationTypes\UpdateTtlResponse; @@ -1640,6 +1644,47 @@ function () use ($call): SortedSetFetchResponse { ); } + /** + * @return ResponseFuture + */ + public function sortedSetRemoveElement(string $cacheName, string $sortedSetName, string $value): ResponseFuture + { + try { + validateCacheName($cacheName); + validateSortedSetName($sortedSetName); + validateValueName($value); + $sortedSetRemoveElementRequest = new _SortedSetRemoveRequest(); + $sortedSetRemoveElementRequest->setSetName($sortedSetName); + $sortedSetRemoveElementRequest->setSome(new _SortedSetRemoveRequest\_Some()); + $sortedSetRemoveElementRequest->getSome()->setValues([$value]); + + $call = $this->grpcManager->client->SortedSetRemove( + $sortedSetRemoveElementRequest, + ["cache" => [$cacheName]], + ["timeout" => $this->timeout], + ); + } catch (SdkError $e) { + return ResponseFuture::createResolved(new SortedSetRemoveElementError($e)); + } catch (Exception $e) { + return ResponseFuture::createResolved(new SortedSetRemoveElementError(new UnknownError($e->getMessage(), 0, $e))); + } + + return ResponseFuture::createPending( + function () use ($call): SortedSetRemoveElementResponse { + try { + $this->processCall($call); + + return new SortedSetRemoveElementSuccess(); + } catch (SdkError $e) { + return new SortedSetRemoveElementError($e); + } catch (Exception $e) { + return new SortedSetRemoveElementError(new UnknownError($e->getMessage(), 0, $e)); + } + } + ); + + } + /** * @return ResponseFuture */ diff --git a/tests/Cache/CacheClientTest.php b/tests/Cache/CacheClientTest.php index ab906f4..d8f4541 100644 --- a/tests/Cache/CacheClientTest.php +++ b/tests/Cache/CacheClientTest.php @@ -3112,7 +3112,7 @@ public function testSortedSetAddElement_HappyPath() $this->assertEquals($score, $valuesArray[$value], "The score for value '$value' does not match the expected score."); } - public function testSortedSetAddElementWithNonexistantCache_ThrowsException() + public function testSortedSetAddElementWithNonexistentCache_ThrowsException() { $cacheName = uniqid(); $sortedSetName = uniqid(); @@ -3297,6 +3297,59 @@ public function testSortedSetFetchByRankWithNegativeStartRankLessThanEndRank_Thr $this->assertEquals(MomentoErrorCode::INVALID_ARGUMENT_ERROR, $response->asError()->errorCode()); } + public function testSortedSetRemoveElement_HappyPath() + { + $sortedSetName = uniqid(); + $value = uniqid(); + $response = $this->client->sortedSetRemoveElement($this->TEST_CACHE_NAME, $sortedSetName, $value); + $this->assertNull($response->asError()); + $this->assertNotNull($response->asSuccess(), "Expected a success but got: $response"); + + $response = $this->client->sortedSetFetchByRank($this->TEST_CACHE_NAME, $sortedSetName); + $this->assertNull($response->asError()); + $this->assertNotNull($response->asMiss(), "Expected a miss but got: $response"); + } + + public function testSortedSetRemoveElementWithNonexistentCache_ThrowsException() + { + $cacheName = uniqid(); + $sortedSetName = uniqid(); + $value = uniqid(); + + $response = $this->client->sortedSetRemoveElement($cacheName, $sortedSetName, $value); + $this->assertNotNull($response->asError(), "Expected error but got: $response"); + $this->assertEquals(MomentoErrorCode::CACHE_NOT_FOUND_ERROR, $response->asError()->errorCode()); + } + + public function testSortedSetRemoveElementWithNullCacheName_ThrowsException() + { + $sortedSetName = uniqid(); + $value = uniqid(); + + $response = $this->client->sortedSetRemoveElement((string)null, $sortedSetName, $value); + $this->assertNotNull($response->asError(), "Expected error but got: $response"); + $this->assertEquals(MomentoErrorCode::INVALID_ARGUMENT_ERROR, $response->asError()->errorCode()); + } + + public function testSortedSetRemoveElementWithEmptyCacheName_ThrowsException() + { + $sortedSetName = uniqid(); + $value = uniqid(); + + $response = $this->client->sortedSetRemoveElement("", $sortedSetName, $value); + $this->assertNotNull($response->asError(), "Expected error but got: $response"); + $this->assertEquals(MomentoErrorCode::INVALID_ARGUMENT_ERROR, $response->asError()->errorCode()); + } + + public function testSortedSetRemoveElementWithEmptyValue_ThrowsException() + { + $sortedSetName = uniqid(); + + $response = $this->client->sortedSetRemoveElement($this->TEST_CACHE_NAME, $sortedSetName, (string)null); + $this->assertNotNull($response->asError(), "Expected error but got: $response"); + $this->assertEquals(MomentoErrorCode::INVALID_ARGUMENT_ERROR, $response->asError()->errorCode()); + } + public function testSortedSetGetScore_HappyPath() { $sortedSetName = uniqid();