diff --git a/src/Illuminate/Redis/Connections/PhpRedisConnection.php b/src/Illuminate/Redis/Connections/PhpRedisConnection.php index a16997187af2..5b279ea11a98 100644 --- a/src/Illuminate/Redis/Connections/PhpRedisConnection.php +++ b/src/Illuminate/Redis/Connections/PhpRedisConnection.php @@ -294,6 +294,60 @@ public function zunionstore($output, $keys, $options = []) ]); } + /** + * Scans the given set for all values based on options. + * + * @param string $key + * @param mixed $cursor + * @param array $options + * @return mixed + */ + public function zscan($key, $cursor, $options = []) + { + $result = $this->client->zscan($key, $cursor, + $options['match'] ?? '*', + $options['count'] ?? 10 + ); + + return $result === false ? [0, []] : [$cursor, $result]; + } + + /** + * Scans the given set for all values based on options. + * + * @param string $key + * @param mixed $cursor + * @param array $options + * @return mixed + */ + public function hscan($key, $cursor, $options = []) + { + $result = $this->client->hscan($key, $cursor, + $options['match'] ?? '*', + $options['count'] ?? 10 + ); + + return $result === false ? [0, []] : [$cursor, $result]; + } + + /** + * Scans the given set for all values based on options. + * + * @param string $key + * @param mixed $cursor + * @param array $options + * @return mixed + */ + public function sscan($key, $cursor, $options = []) + { + $result = $this->client->sscan($key, $cursor, + $options['match'] ?? '*', + $options['count'] ?? 10 + ); + + return $result === false ? [0, []] : [$cursor, $result]; + } + /** * Execute commands in a pipeline. * diff --git a/tests/Redis/RedisConnectionTest.php b/tests/Redis/RedisConnectionTest.php index 79bc853f2540..3f1bb20f612a 100644 --- a/tests/Redis/RedisConnectionTest.php +++ b/tests/Redis/RedisConnectionTest.php @@ -577,6 +577,122 @@ public function testItScansForKeys() } } + public function testItZscansForKeys() + { + foreach ($this->connections() as $redis) { + $members = range(1, 200); + + foreach ($members as $score => $member) { + $redis->zadd('set', $score, $member); + } + + $iterator = null; + $result = []; + + do { + [$iterator, $returnedMembers] = $redis->zscan('set', $iterator); + + if (!is_array($returnedMembers)) { + $returnedMembers = [$returnedMembers]; + } + + foreach ($returnedMembers as $member => $score) { + $this->assertArrayHasKey((int) $score, $members); + $this->assertContains($member, $members); + } + + $result += $returnedMembers; + } while ($iterator > 0); + + $this->assertCount(200, $result); + + $iterator = null; + [$iterator, $unmatched] = $redis->zscan('set', $iterator, ['match' => 'test:unmatch']); + $this->assertEmpty($unmatched); + + $iterator = null; + [$iterator, $returned] = $redis->zscan('set', $iterator, ['count' => 50]); + $this->assertGreaterThan(10, count($returned)); + $this->assertLessThan(200, count($returned)); + + $redis->flushAll(); + } + } + + public function testItHscansForKeys() + { + foreach ($this->connections() as $redis) { + $fields = array_combine(range(1, 1000), range(1, 1000)); + + foreach ($fields as $field => $value) { + $redis->hset('hash', $field, $value); + } + + $iterator = null; + $result = []; + + do { + [$iterator, $returnedFields] = $redis->hscan('hash', $iterator); + + foreach ($returnedFields as $field => $value) { + $this->assertArrayHasKey($field, $fields); + $this->assertContains((int) $value, $fields); + } + + $result += $returnedFields; + } while ($iterator > 0); + + $this->assertCount(1000, $result); + + $iterator = null; + [$iterator, $unmatched] = $redis->hscan('hash', $iterator, ['match' => 'test:unmatch']); + $this->assertEmpty($unmatched); + + $iterator = null; + [$iterator, $returned] = $redis->hscan('hash', $iterator, ['count' => 100]); + $this->assertGreaterThan(50, count($returned)); + $this->assertLessThan(1000, count($returned)); + + $redis->flushAll(); + } + } + + public function testItSscansForKeys() + { + foreach ($this->connections() as $redis) { + $members = range(1, 1000); + + foreach ($members as $member) { + $redis->sadd('set', $member); + } + + $iterator = null; + $result = []; + + do { + [$iterator, $returnedMembers] = $redis->sscan('set', $iterator); + + foreach ($returnedMembers as $member) { + $this->assertContains((int) $member, $members); + array_push($result, $member); + } + } while ($iterator > 0); + + $this->assertCount(1000, $result); + + $iterator = null; + [$iterator, $unmatched] = $redis->sscan('set', $iterator, ['match' => 'test:unmatch']); + $this->assertEmpty($unmatched); + + $iterator = null; + [$iterator, $returned] = $redis->sscan('set', $iterator, ['count' => 100]); + $this->assertGreaterThan(50, count($returned)); + $this->assertLessThan(1000, count($returned)); + + $redis->flushAll(); + } + } + public function testPhpRedisScanOption() { foreach ($this->connections() as $redis) {