Skip to content

Commit

Permalink
Merge pull request #1 from 007hacky007/if-custom-compare
Browse files Browse the repository at this point in the history
Custom compare support for the If methods
  • Loading branch information
matthi4s authored May 1, 2020
2 parents c96bcf9 + 6decc1d commit 656c019
Show file tree
Hide file tree
Showing 4 changed files with 266 additions and 70 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ $client = new Aternos\Etcd\Client("localhost:2379", "username", "password");
$client->put("key", "value");
$client->get("key");
$client->delete("key");
$client->putIf("key", "newValue", "expectedPreviousValue");
$client->deleteIf("key", "expectedPreviousValue");
$client->putIf("key", "newValue", "valueToCompareWith");
$client->deleteIf("key", "3");
```

#### Sharded client
Expand Down
213 changes: 154 additions & 59 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -191,42 +191,41 @@ public function delete(string $key)
* Put $value if $key value matches $previousValue otherwise $returnNewValueOnFail
*
* @param string $key
* @param mixed $value The new value to set
* @param mixed $previousValue The previous value to compare against
* @param string $value The new value to set
* @param bool|string $compareValue The previous value to compare against
* @param bool $returnNewValueOnFail
* @return bool|string
* @throws InvalidResponseStatusCodeException
* @throws \Exception
*/
public function putIf(string $key, $value, $previousValue, bool $returnNewValueOnFail = false)
public function putIf(string $key, string $value, $compareValue, bool $returnNewValueOnFail = false)
{
$request = new PutRequest();
$request->setKey($key);
$request->setValue($value);

$operation = new RequestOp();
$operation->setRequestPut($request);
$operation = $this->getPutOperation($key, $value);
$compare = $this->getCompareForIf($key, $compareValue);
$failOperation = $this->getFailOperation($key, $returnNewValueOnFail);

return $this->requestIf($key, $previousValue, $operation, $returnNewValueOnFail);
$response = $this->txnRequest($key, [$operation], $failOperation, [$compare]);
return $this->getIfResponse($returnNewValueOnFail, $response);
}

/**
* Delete if $key value matches $previous value otherwise $returnNewValueOnFail
*
* @param string $key
* @param $previousValue
* @param bool|string $compareValue The previous value to compare against
* @param bool $returnNewValueOnFail
* @return bool|string
* @throws InvalidResponseStatusCodeException
* @throws \Exception
*/
public function deleteIf(string $key, $previousValue, bool $returnNewValueOnFail = false)
public function deleteIf(string $key, $compareValue, bool $returnNewValueOnFail = false)
{
$request = new DeleteRangeRequest();
$request->setKey($key);
$operation = $this->getDeleteOperation($key);
$compare = $this->getCompareForIf($key, $compareValue);
$failOperation = $this->getFailOperation($key, $returnNewValueOnFail);

$operation = new RequestOp();
$operation->setRequestDeleteRange($request);

return $this->requestIf($key, $previousValue, $operation, $returnNewValueOnFail);
$response = $this->txnRequest($key, [$operation], $failOperation, [$compare]);
return $this->getIfResponse($returnNewValueOnFail, $response);
}

/**
Expand Down Expand Up @@ -295,62 +294,103 @@ public function refreshLease(int $leaseID)
* Execute $requestOperation if $key value matches $previous otherwise $returnNewValueOnFail
*
* @param string $key
* @param $previousValue
* @param RequestOp $requestOperation
* @param bool $returnNewValueOnFail
* @return bool|string
* @param array $requestOperations operations to perform on success, array of RequestOp objects
* @param array|null $failureOperations operations to perform on failure, array of RequestOp objects
* @param array $compare array of Compare objects
* @return TxnResponse
* @throws InvalidResponseStatusCodeException
*/
protected function requestIf(string $key, $previousValue, RequestOp $requestOperation, bool $returnNewValueOnFail = false)
public function txnRequest(string $key, array $requestOperations, ?array $failureOperations, array $compare): TxnResponse
{
$client = $this->getKvClient();

$compare = new Compare();
$compare->setKey($key);

if ($previousValue === false) {
$compare->setValue("0");
$compare->setResult(CompareResult::EQUAL);
$compare->setTarget(CompareTarget::VERSION);
} else {
$compare->setValue($previousValue);
$compare->setResult(CompareResult::EQUAL);
$compare->setTarget(CompareTarget::VALUE);
}

$request = new TxnRequest();
$request->setCompare([$compare]);
$request->setSuccess([$requestOperation]);

if ($returnNewValueOnFail) {
$getRequest = new RangeRequest();
$getRequest->setKey($key);

$getOperation = new RequestOp();
$getOperation->setRequestRange($getRequest);
$request->setFailure([$getOperation]);
}
$request->setCompare($compare);
$request->setSuccess($requestOperations);
if($failureOperations !== null)
$request->setFailure($failureOperations);

/** @var TxnResponse $response */
list($response, $status) = $client->Txn($request, $this->getMetaData(), $this->getOptions())->wait();
$this->validateStatus($status);

if ($returnNewValueOnFail && !$response->getSucceeded()) {
/** @var ResponseOp $responseOp */
$responseOp = $response->getResponses()[0];
return $response;
}

$getResponse = $responseOp->getResponseRange();
/**
* Creates RequestOp of Get operation for requestIf method
*
* @param string $key
* @return RequestOp
*/
public function getGetOperation(string $key): RequestOp
{
$request = new RangeRequest();
$request->setKey($key);

$field = $getResponse->getKvs();
$operation = new RequestOp();
$operation->setRequestRange($request);

if (count($field) === 0) {
return false;
}
return $operation;
}

return $field[0]->getValue();
} else {
return $response->getSucceeded();
}
/**
* Creates RequestOp of Put operation for requestIf method
*
* @param string $key
* @param string $value
* @param int $leaseId
* @return RequestOp
*/
public function getPutOperation(string $key, string $value, int $leaseId = 0): RequestOp
{
$request = new PutRequest();
$request->setKey($key);
$request->setValue($value);
if($leaseId !== 0)
$request->setLease($leaseId);

$operation = new RequestOp();
$operation->setRequestPut($request);

return $operation;
}

/**
* Creates RequestOp of Delete operation for requestIf method
*
* @param string $key
* @return RequestOp
*/
public function getDeleteOperation(string $key): RequestOp
{
$request = new DeleteRangeRequest();
$request->setKey($key);

$operation = new RequestOp();
$operation->setRequestDeleteRange($request);

return $operation;
}

/**
* Get an instance of Compare
*
* @param string $key
* @param string $value
* @param int $result see CompareResult class for available constants
* @param int $target check constants in the CompareTarget class for available values
* @return Compare
*/
public function getCompare(string $key, string $value, int $result, int $target): Compare
{
$compare = new Compare();
$compare->setKey($key);
$compare->setValue($value);
$compare->setTarget($target);
$compare->setResult($result);

return $compare;
}

/**
Expand Down Expand Up @@ -401,6 +441,7 @@ protected function getAuthClient(): AuthClient
return $this->authClient;
}


/**
* Get an authentication token
*
Expand Down Expand Up @@ -463,4 +504,58 @@ protected function validateStatus($status)
throw ResponseStatusCodeExceptionFactory::getExceptionByCode($status->code, $status->details);
}
}

/**
* @param string $key
* @param string $compareValue
* @return Compare
*/
protected function getCompareForIf(string $key, string $compareValue): Compare
{
if ($compareValue === false) {
$compare = $this->getCompare($key, '0', CompareResult::EQUAL, CompareTarget::VERSION);
} else {
$compare = $this->getCompare($key, $compareValue, CompareResult::EQUAL, CompareTarget::VALUE);
}
return $compare;
}

/**
* @param bool $returnNewValueOnFail
* @param TxnResponse $response
* @return bool
*/
protected function getIfResponse(bool $returnNewValueOnFail, TxnResponse $response): bool
{
if ($returnNewValueOnFail && !$response->getSucceeded()) {
/** @var ResponseOp $responseOp */
$responseOp = $response->getResponses()[0];

$getResponse = $responseOp->getResponseRange();

$field = $getResponse->getKvs();

if (count($field) === 0) {
return false;
}

return $field[0]->getValue();
} else {
return $response->getSucceeded();
}
}

/**
* @param string $key
* @param bool $returnNewValueOnFail
* @return array|null
*/
protected function getFailOperation(string $key, bool $returnNewValueOnFail)
{
$failOperation = null;
if ($returnNewValueOnFail)
$failOperation = [$this->getGetOperation($key)];

return $failOperation;
}
}
63 changes: 58 additions & 5 deletions src/ClientInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
namespace Aternos\Etcd;

use Aternos\Etcd\Exception\Status\InvalidResponseStatusCodeException;
use Etcdserverpb\Compare;
use Etcdserverpb\RequestOp;
use Etcdserverpb\TxnResponse;
use Exception;

/**
Expand Down Expand Up @@ -54,24 +57,74 @@ public function delete(string $key);
* Put $value if $key value matches $previousValue otherwise $returnNewValueOnFail
*
* @param string $key
* @param mixed $value The new value to set
* @param mixed $previousValue The previous value to compare against
* @param string $value The new value to set
* @param bool|string $compareValue The previous value to compare against
* @param bool $returnNewValueOnFail
* @return bool|string
* @throws InvalidResponseStatusCodeException
*/
public function putIf(string $key, $value, $previousValue, bool $returnNewValueOnFail = false);
public function putIf(string $key, string $value, $compareValue, bool $returnNewValueOnFail = false);

/**
* Delete if $key value matches $previous value otherwise $returnNewValueOnFail
*
* @param string $key
* @param $previousValue
* @param bool|string $compareValue The previous value to compare against
* @param bool $returnNewValueOnFail
* @return bool|string
* @throws InvalidResponseStatusCodeException
* @throws \Exception
*/
public function deleteIf(string $key, $previousValue, bool $returnNewValueOnFail = false);
public function deleteIf(string $key, $compareValue, bool $returnNewValueOnFail = false);

/**
* Execute $requestOperation if $key value matches $previous otherwise $returnNewValueOnFail
*
* @param string $key
* @param array $requestOperations operations to perform on success, array of RequestOp objects
* @param array|null $failureOperations operations to perform on failure, array of RequestOp objects
* @param array $compare array of Compare objects
* @return TxnResponse
* @throws InvalidResponseStatusCodeException
*/
public function txnRequest(string $key, array $requestOperations, ?array $failureOperations, array $compare): TxnResponse;

/**
* Get an instance of Compare
*
* @param string $key
* @param string $value
* @param int $result see CompareResult class for available constants
* @param int $target check constants in the CompareTarget class for available values
* @return Compare
*/
public function getCompare(string $key, string $value, int $result, int $target): Compare;

/**
* Creates RequestOp of Get operation for requestIf method
*
* @param string $key
* @return RequestOp
*/
public function getGetOperation(string $key): RequestOp;

/**
* Creates RequestOp of Put operation for requestIf method
*
* @param string $key
* @param string $value
* @param int $leaseId
* @return RequestOp
*/
public function getPutOperation(string $key, string $value, int $leaseId = 0): RequestOp;

/**
* Creates RequestOp of Delete operation for requestIf method
*
* @param string $key
* @return RequestOp
*/
public function getDeleteOperation(string $key): RequestOp;

/**
* Get leaseID which can be used with etcd's put
Expand Down
Loading

0 comments on commit 656c019

Please sign in to comment.