From f721e0c2180880ef25fbe92bd4f2ed3ba2739345 Mon Sep 17 00:00:00 2001 From: Andrzej Wasiak Date: Wed, 4 Apr 2018 12:37:52 +0200 Subject: [PATCH] ResourceInfoRepository methods update (#4) * added replace and exists methods * insert() now throws exception when resource exists --- .../Redis/RedisResourceInfoRepository.php | 31 ++++++++++-- .../Resource/ResourceInfoException.php | 15 ++++++ .../Resource/ResourceInfoExistsException.php | 28 +++++++++++ ....php => ResourceInfoNotFoundException.php} | 7 +-- .../Resource/ResourceInfoRepository.php | 20 +++++++- .../RedisResourceInfoRepositoryITest.php | 47 +++++++++++++++++-- 6 files changed, 133 insertions(+), 15 deletions(-) create mode 100644 src/SAREhub/MultiTenantUtil/Resource/ResourceInfoException.php create mode 100644 src/SAREhub/MultiTenantUtil/Resource/ResourceInfoExistsException.php rename src/SAREhub/MultiTenantUtil/Resource/{NotFoundResourceInfoException.php => ResourceInfoNotFoundException.php} (81%) diff --git a/src/SAREhub/MultiTenantUtil/Resource/Redis/RedisResourceInfoRepository.php b/src/SAREhub/MultiTenantUtil/Resource/Redis/RedisResourceInfoRepository.php index bdefd6a..96106c3 100644 --- a/src/SAREhub/MultiTenantUtil/Resource/Redis/RedisResourceInfoRepository.php +++ b/src/SAREhub/MultiTenantUtil/Resource/Redis/RedisResourceInfoRepository.php @@ -6,8 +6,10 @@ use Predis\Client; use Predis\Collection\Iterator\Keyspace; -use SAREhub\MultiTenantUtil\Resource\NotFoundResourceInfoException; +use Predis\Transaction\MultiExec; use SAREhub\MultiTenantUtil\Resource\ResourceInfo; +use SAREhub\MultiTenantUtil\Resource\ResourceInfoExistsException; +use SAREhub\MultiTenantUtil\Resource\ResourceInfoNotFoundException; use SAREhub\MultiTenantUtil\Resource\ResourceInfoRepository; class RedisResourceInfoRepository implements ResourceInfoRepository @@ -41,19 +43,40 @@ public function insert(ResourceInfo $resource) { $key = $this->getPrefixedKey($resource->getId()); $data = $this->serializeResource($resource); - $this->getRedisClient()->hmset($key, $data); + + $options = ["cas" => true, "watch" => $key, "retry" => 0]; + + $this->redisClient->transaction($options, function (MultiExec $tx) use ($key, $resource, $data) { + if ($tx->exists($key)) { + throw new ResourceInfoExistsException($this->getResourceTypeName(), $resource->getId()); + } + $tx->multi(); + $tx->hmset($key, $data); + }); + } + + public function replace(ResourceInfo $resource) + { + $key = $this->getPrefixedKey($resource->getId()); + $data = $this->serializeResource($resource); + $this->redisClient->hmset($key, $data); + } + + public function exists(string $id): bool + { + return (bool)$this->redisClient->exists($this->getPrefixedKey($id)); } /** * @param string $id * @return ResourceInfo - * @throws NotFoundResourceInfoException + * @throws ResourceInfoNotFoundException */ public function find(string $id): ResourceInfo { $data = $this->getRedisClient()->hgetall($this->getPrefixedKey($id)); if (empty($data)) { - throw new NotFoundResourceInfoException($this->getResourceTypeName(), $id); + throw new ResourceInfoNotFoundException($this->getResourceTypeName(), $id); } return $this->deserializeResource($id, $data); diff --git a/src/SAREhub/MultiTenantUtil/Resource/ResourceInfoException.php b/src/SAREhub/MultiTenantUtil/Resource/ResourceInfoException.php new file mode 100644 index 0000000..7978c46 --- /dev/null +++ b/src/SAREhub/MultiTenantUtil/Resource/ResourceInfoException.php @@ -0,0 +1,15 @@ +resourceType = $resourceType; + $this->resourceId = $resourceId; + } + + public function getResourceType(): string + { + return $this->resourceType; + } + + public function getResourceId(): string + { + return $this->resourceId; + } +} \ No newline at end of file diff --git a/src/SAREhub/MultiTenantUtil/Resource/NotFoundResourceInfoException.php b/src/SAREhub/MultiTenantUtil/Resource/ResourceInfoNotFoundException.php similarity index 81% rename from src/SAREhub/MultiTenantUtil/Resource/NotFoundResourceInfoException.php rename to src/SAREhub/MultiTenantUtil/Resource/ResourceInfoNotFoundException.php index c87af32..8138c2c 100644 --- a/src/SAREhub/MultiTenantUtil/Resource/NotFoundResourceInfoException.php +++ b/src/SAREhub/MultiTenantUtil/Resource/ResourceInfoNotFoundException.php @@ -4,16 +4,11 @@ namespace SAREhub\MultiTenantUtil\Resource; -class NotFoundResourceInfoException extends \Exception +class ResourceInfoNotFoundException extends ResourceInfoException { private $resourceType; private $resourceId; - /** - * - * @param $resourceType - * @param $resourceId - */ public function __construct(string $resourceType, string $resourceId) { parent::__construct("Resource of type '$resourceType' and id '$resourceId' not found"); diff --git a/src/SAREhub/MultiTenantUtil/Resource/ResourceInfoRepository.php b/src/SAREhub/MultiTenantUtil/Resource/ResourceInfoRepository.php index 36731f8..bdb10ae 100644 --- a/src/SAREhub/MultiTenantUtil/Resource/ResourceInfoRepository.php +++ b/src/SAREhub/MultiTenantUtil/Resource/ResourceInfoRepository.php @@ -6,12 +6,27 @@ interface ResourceInfoRepository { + /** + * @param ResourceInfo $resource + * @throws ResourceInfoExistsException When resource with same id exists + */ public function insert(ResourceInfo $resource); + /** + * @param ResourceInfo $resource + */ + public function replace(ResourceInfo $resource); + + /** + * @param string $id + * @return bool + */ + public function exists(string $id): bool; + /** * @param string $id * @return ResourceInfo - * @throws NotFoundResourceInfoException + * @throws ResourceInfoNotFoundException When resource with id not exists */ public function find(string $id): ResourceInfo; @@ -20,5 +35,8 @@ public function find(string $id): ResourceInfo; */ public function findAll(): array; + /** + * @param string $id + */ public function delete(string $id); } \ No newline at end of file diff --git a/tests/integration/SAREhub/MultiTenantUtil/Resource/Redis/RedisResourceInfoRepositoryITest.php b/tests/integration/SAREhub/MultiTenantUtil/Resource/Redis/RedisResourceInfoRepositoryITest.php index ab4af3b..b8f36d8 100644 --- a/tests/integration/SAREhub/MultiTenantUtil/Resource/Redis/RedisResourceInfoRepositoryITest.php +++ b/tests/integration/SAREhub/MultiTenantUtil/Resource/Redis/RedisResourceInfoRepositoryITest.php @@ -4,8 +4,9 @@ use SAREhub\MultiTenantUtil\RedisTestCase; use SAREhub\MultiTenantUtil\Resource\AccountSharedResourceInfo; -use SAREhub\MultiTenantUtil\Resource\NotFoundResourceInfoException; use SAREhub\MultiTenantUtil\Resource\ResourceInfo; +use SAREhub\MultiTenantUtil\Resource\ResourceInfoExistsException; +use SAREhub\MultiTenantUtil\Resource\ResourceInfoNotFoundException; class RedisResourceInfoRepositoryITest extends RedisTestCase { @@ -21,6 +22,44 @@ protected function setUp() $this->repository = new RedisResourceInfoRepository($this->redisClient, "test_prefix", "test_resource_type"); } + public function testInsertWhenExists() + { + $res = $this->createResource(); + $this->repository->insert($res); + + $this->expectException(ResourceInfoExistsException::class); + $this->repository->insert($res); + } + + public function testReplaceWhenNotExists() + { + $res = $this->createResource(); + $this->repository->replace($res); + $this->assertEquals($res, $this->repository->find($res->getId())); + } + + public function testReplaceWhenExistsThenReplaced() + { + $old = $this->createResource("test", ["field" => "initial"]); + $this->repository->replace($old); + + $expected = $this->createResource("test", ["field" => "replaced"]); + $this->repository->replace($expected); + + $this->assertEquals($expected, $this->repository->find($expected->getId())); + } + + public function testExistsWhenExists() + { + $res = $this->insertResourceToRepository(); + $this->assertTrue($this->repository->exists($res->getId())); + } + + public function testExistsWhenNotExists() + { + $this->assertFalse($this->repository->exists("not exists")); + } + public function testFindWhenExists() { $res = $this->insertResourceToRepository(); @@ -30,7 +69,7 @@ public function testFindWhenExists() public function testFindWhenNotExists() { $resId = "test_id"; - $this->expectException(NotFoundResourceInfoException::class); + $this->expectException(ResourceInfoNotFoundException::class); $this->expectExceptionMessage("Resource of type 'test_resource_type' and id 'test_id' not found"); $this->repository->find($resId); } @@ -61,8 +100,8 @@ private function insertResourceToRepository(): ResourceInfo return $res; } - private function createResource(): ResourceInfo + private function createResource(string $idSuffix = "", array $fields = ["field" => "value"]): ResourceInfo { - return new ResourceInfo("test_id", ["field" => "value"]); + return new ResourceInfo("test_id" . $idSuffix, $fields); } }