Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add sortedSetRemoveElement api #222

Merged
merged 1 commit into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 50 additions & 1 deletion src/Cache/CacheClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<SortedSetPutElementResponse> 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.
* <code>$response = $responseFuture->wait();</code><br />
* The response represents the result of the sorted set put element operation.
Expand Down Expand Up @@ -1904,6 +1905,54 @@ private function getNextDataClient(): ScsDataClient
return $client;
}

/**
* Remove an element to a sorted set.
malandis marked this conversation as resolved.
Show resolved Hide resolved
*
* @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<SortedSetRemoveElementResponse> A waitable future which
* will provide the result of the sorted set remove element operation upon a blocking call to
* wait.
* <code>$response = $responseFuture->wait();</code><br />
* 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:<br>
* * SortedSetRemoveElementSuccess<br>
* * SortedSetRemoveElementError<br>
* <code>
* if ($error = $response->asError()) {
* // handle error condition
* }
* </code>
* 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.
malandis marked this conversation as resolved.
Show resolved Hide resolved
*
* @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:<br>
* * SortedSetRemoveElementSuccess<br>
* * SortedSetRemoveElementError<br>
* if ($error = $response->asError()) {<br>
* &nbsp;&nbsp;// handle error condition<br>
* }</code>
*/
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.
*
Expand Down
58 changes: 58 additions & 0 deletions src/Cache/CacheOperationTypes/CacheOperationTypes.php
Original file line number Diff line number Diff line change
Expand Up @@ -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:
* <code>
* if ($response->asSuccess()) {
* // handle success as appropriate
* } elseif ($error = $response->asError())
* // handle error as appropriate
* }
* </code>
*/
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
{
/**
Expand Down
45 changes: 45 additions & 0 deletions src/Cache/Internal/ScsDataClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1640,6 +1644,47 @@ function () use ($call): SortedSetFetchResponse {
);
}

/**
* @return ResponseFuture<SortedSetRemoveElementResponse>
*/
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<SortedSetGetScoreResponse>
*/
Expand Down
55 changes: 54 additions & 1 deletion tests/Cache/CacheClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -3297,6 +3297,59 @@ public function testSortedSetFetchByRankWithNegativeStartRankLessThanEndRank_Thr
$this->assertEquals(MomentoErrorCode::INVALID_ARGUMENT_ERROR, $response->asError()->errorCode());
}

public function testSortedSetRemoveElement_HappyPath()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: also test a sorted set with multiple elements:

  • remove an element in the sorted set; the sorted set is still there but lacking that element
  • remove an element not in the sorted set; the sorted set is the same as before

{
$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();
Expand Down
Loading