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

Implement options for ZRANGE, ZRANGEBYSCORE, ZREVRANGE, ZREVRANGEBYSCORE #78

Closed
wants to merge 2 commits into from
Closed
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
52 changes: 52 additions & 0 deletions src/RangeByScoreOptions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

namespace Amp\Redis;

final class RangeByScoreOptions
{
/** @var bool */
private $withScores = false;
/** @var int|null */
private $offset;
/** @var int|null */
private $count;

public function withScores(): self
{
$clone = clone $this;
$clone->withScores = true;

return $clone;
}

public function isWithScores(): bool
{
return $this->withScores;
}

public function withOffset(int $offset, int $count): self
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't this be called withLimit instead?

{
$clone = clone $this;
$clone->offset = $offset;
$clone->count = $count;

return $clone;
}

public function toQuery(): array
{
$query = [];

if ($this->withScores() !== false) {
$query[] = "WITHSCORES";
}

if ($this->offset !== null) {
$query[] = "LIMIT";
$query[] = $this->offset;
$query[] = $this->count;
}

return $query;
}
}
33 changes: 33 additions & 0 deletions src/RangeOptions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Amp\Redis;

final class RangeOptions
{
/** @var bool */
private $withScores = false;

public function isWithScores(): bool
{
return $this->withScores;
}

public function withScores(): self
{
$clone = clone $this;
$clone->withScores = true;

return $clone;
}

public function toQuery(): array
{
$query = [];

if ($this->withScores() !== false) {
$query[] = "WITHSCORES";
}

return $query;
}
}
2 changes: 1 addition & 1 deletion src/RedisMap.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public function setValues(array $data): Promise
/**
* @param string $field
*
* @return Promise<string>
* @return Promise<string|null>
*
* @link https://redis.io/commands/hget
*/
Expand Down
42 changes: 31 additions & 11 deletions src/RedisSortedSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,14 @@ public function add(array $data): Promise
*
* @return Promise
*/
public function getRange(int $start, int $end): Promise
public function getRange(int $start, int $end, ?RangeByScoreOptions $options = null): Promise
{
return $this->queryExecutor->execute(['zrange', $this->key, $start, $end]);
$query = ['zrange', $this->key, $start, $end];
if ($options !== null) {
$query = \array_merge($query, $options->toQuery());
}

return $this->queryExecutor->execute($query, $options !== null && $options->isWithScores() ? toFloatMap : null);
}

/**
Expand All @@ -53,9 +58,14 @@ public function getRange(int $start, int $end): Promise
*
* @return Promise
*/
public function getReverseRange(int $start, int $end): Promise
public function getReverseRange(int $start, int $end, ?RangeByScoreOptions $options = null): Promise
{
return $this->queryExecutor->execute(['zrevrange', $this->key, $start, $end]);
$query = ['zrevrange', $this->key, $start, $end];
if ($options !== null) {
$query = \array_merge($query, $options->toQuery());
}

return $this->queryExecutor->execute($query, $options !== null && $options->isWithScores() ? toFloatMap : null);
}

/**
Expand All @@ -64,9 +74,14 @@ public function getReverseRange(int $start, int $end): Promise
*
* @return Promise
*/
public function getRangeByScore(float $min, float $max): Promise
public function getRangeByScore(float $min, float $max, RangeByScoreOptions $options = null): Promise
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
public function getRangeByScore(float $min, float $max, RangeByScoreOptions $options = null): Promise
public function getRangeByScore(float $min, float $max, ?RangeByScoreOptions $options = null): Promise

{
return $this->queryExecutor->execute(['zrangebyscore', $this->key, $min, $max]);
$query = ['zrangebyscore', $this->key, $min, $max];
if ($options !== null) {
$query = \array_merge($query, $options->toQuery());
}

return $this->queryExecutor->execute($query, $options !== null && $options->isWithScores() ? toFloatMap : null);
}

/**
Expand All @@ -75,9 +90,14 @@ public function getRangeByScore(float $min, float $max): Promise
*
* @return Promise
*/
public function getReverseRangeByScore(float $min, float $max): Promise
public function getReverseRangeByScore(float $min, float $max, RangeByScoreOptions $options = null): Promise
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
public function getReverseRangeByScore(float $min, float $max, RangeByScoreOptions $options = null): Promise
public function getReverseRangeByScore(float $min, float $max, ?RangeByScoreOptions $options = null): Promise

{
return $this->queryExecutor->execute(['ZREVRANGEBYSCORE', $this->key, $min, $max]);
$query = ['zrevrangebyscore', $this->key, $min, $max];
if ($options !== null) {
$query = \array_merge($query, $options->toQuery());
}

return $this->queryExecutor->execute($query, $options !== null && $options->isWithScores() ? toFloatMap : null);
}

/**
Expand All @@ -89,12 +109,12 @@ public function getSize(): Promise
}

/**
* @param int $min
* @param int $max
* @param float $min
* @param float $max
*
* @return Promise<int>
*/
public function count(int $min, int $max): Promise
public function count(float $min, float $max): Promise
{
return $this->queryExecutor->execute(['zcount', $this->key, $min, $max]);
}
Expand Down
17 changes: 17 additions & 0 deletions src/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
const toBool = __NAMESPACE__ . '\toBool';
const toNull = __NAMESPACE__ . '\toNull';
const toMap = __NAMESPACE__ . '\toMap';
const toFloatMap = __NAMESPACE__ . '\toFloatMap';

function toFloat($response): ?float
{
Expand Down Expand Up @@ -46,6 +47,22 @@ function toMap(?array $values): ?array
return $result;
}

function toFloatMap(?array $values): ?array
{
if ($values === null) {
return null;
}

$size = \count($values);
$result = [];

for ($i = 0; $i < $size; $i += 2) {
$result[$values[$i]] = (float)$values[$i + 1];
}

return $result;
}

function toNull($response): void
{
// nothing to do
Expand Down
1 change: 1 addition & 0 deletions test/RedisMapTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public function test(): \Generator
'rofl' => 'lol',
]));

$this->assertSame(null, yield $map->getValue('does_not_exist'));
$this->assertSame('bar', yield $map->getValue('foo'));
$this->assertSame('lol', yield $map->getValue('rofl'));
$this->assertSame(2, yield $map->getSize());
Expand Down
4 changes: 4 additions & 0 deletions test/RedisSortedSetTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,20 @@ public function test(): \Generator
$this->assertSame(1, yield $set->count(3, 3));

$this->assertSame(['foo'], yield $set->getRange(0, 0));
$this->assertSame(['foo' => 1.0], yield $set->getRange(0, 0, (new RangeOptions())->withScores()));
$this->assertSame(['foo', 'bar'], yield $set->getRange(0, 1));
$this->assertSame(['bar'], yield $set->getRange(1, 2));

$this->assertSame(['foo'], yield $set->getRangeByScore(1, 2));
$this->assertSame(['foo' => 1.0], yield $set->getRangeByScore(1, 2, (new RangeByScoreOptions())->withScores()));
$this->assertSame(['foo', 'bar'], yield $set->getRangeByScore(1, 4));

$this->assertSame(['bar', 'foo'], yield $set->getReverseRange(0, 1));
$this->assertSame(['bar' => 3.0], yield $set->getReverseRange(0, 0, (new RangeOptions())->withScores()));
$this->assertSame(['foo'], yield $set->getReverseRange(1, 2));

$this->assertSame(['foo'], yield $set->getReverseRangeByScore(2, 1));
$this->assertSame(['bar' => 3.0, 'foo' => 1.0], yield $set->getReverseRangeByScore(4, 1, (new RangeByScoreOptions())->withScores()));
$this->assertSame(['bar', 'foo'], yield $set->getReverseRangeByScore(4, 1));

$this->assertSame(0, yield $set->getRank('foo'));
Expand Down