use crate::{
clients::RedisClient,
error::RedisError,
interfaces,
modules::inner::RedisClientInner,
protocol::{
command::{RedisCommand, RedisCommandKind},
responders::ResponseKind,
types::{KeyScanInner, ValueScanInner},
},
runtime::RefCount,
types::{RedisKey, RedisMap, RedisValue},
utils,
};
use bytes_utils::Str;
use std::borrow::Cow;
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ScanType {
Set,
String,
ZSet,
List,
Hash,
Stream,
}
impl ScanType {
pub(crate) fn to_str(&self) -> Str {
utils::static_str(match *self {
ScanType::Set => "set",
ScanType::String => "string",
ScanType::List => "list",
ScanType::ZSet => "zset",
ScanType::Hash => "hash",
ScanType::Stream => "stream",
})
}
}
pub trait Scanner {
type Page;
fn cursor(&self) -> Option<Cow<str>>;
fn has_more(&self) -> bool;
fn results(&self) -> &Option<Self::Page>;
fn take_results(&mut self) -> Option<Self::Page>;
fn create_client(&self) -> RedisClient;
fn next(self) -> Result<(), RedisError>;
}
pub struct ScanResult {
pub(crate) results: Option<Vec<RedisKey>>,
pub(crate) inner: RefCount<RedisClientInner>,
pub(crate) scan_state: KeyScanInner,
pub(crate) can_continue: bool,
}
impl Scanner for ScanResult {
type Page = Vec<RedisKey>;
fn cursor(&self) -> Option<Cow<str>> {
self.scan_state.args[self.scan_state.cursor_idx].as_str()
}
fn has_more(&self) -> bool {
self.can_continue
}
fn results(&self) -> &Option<Self::Page> {
&self.results
}
fn take_results(&mut self) -> Option<Self::Page> {
self.results.take()
}
fn create_client(&self) -> RedisClient {
RedisClient {
inner: self.inner.clone(),
}
}
fn next(self) -> Result<(), RedisError> {
if !self.can_continue {
return Ok(());
}
let cluster_node = self.scan_state.server.clone();
let response = ResponseKind::KeyScan(self.scan_state);
let mut cmd: RedisCommand = (RedisCommandKind::Scan, Vec::new(), response).into();
cmd.cluster_node = cluster_node;
interfaces::default_send_command(&self.inner, cmd)
}
}
pub struct HScanResult {
pub(crate) results: Option<RedisMap>,
pub(crate) inner: RefCount<RedisClientInner>,
pub(crate) scan_state: ValueScanInner,
pub(crate) can_continue: bool,
}
impl Scanner for HScanResult {
type Page = RedisMap;
fn cursor(&self) -> Option<Cow<str>> {
self.scan_state.args[self.scan_state.cursor_idx].as_str()
}
fn has_more(&self) -> bool {
self.can_continue
}
fn results(&self) -> &Option<Self::Page> {
&self.results
}
fn take_results(&mut self) -> Option<Self::Page> {
self.results.take()
}
fn create_client(&self) -> RedisClient {
RedisClient {
inner: self.inner.clone(),
}
}
fn next(self) -> Result<(), RedisError> {
if !self.can_continue {
return Ok(());
}
let response = ResponseKind::ValueScan(self.scan_state);
let cmd: RedisCommand = (RedisCommandKind::Hscan, Vec::new(), response).into();
interfaces::default_send_command(&self.inner, cmd)
}
}
pub struct SScanResult {
pub(crate) results: Option<Vec<RedisValue>>,
pub(crate) inner: RefCount<RedisClientInner>,
pub(crate) scan_state: ValueScanInner,
pub(crate) can_continue: bool,
}
impl Scanner for SScanResult {
type Page = Vec<RedisValue>;
fn cursor(&self) -> Option<Cow<str>> {
self.scan_state.args[self.scan_state.cursor_idx].as_str()
}
fn results(&self) -> &Option<Self::Page> {
&self.results
}
fn take_results(&mut self) -> Option<Self::Page> {
self.results.take()
}
fn has_more(&self) -> bool {
self.can_continue
}
fn create_client(&self) -> RedisClient {
RedisClient {
inner: self.inner.clone(),
}
}
fn next(self) -> Result<(), RedisError> {
if !self.can_continue {
return Ok(());
}
let response = ResponseKind::ValueScan(self.scan_state);
let cmd: RedisCommand = (RedisCommandKind::Sscan, Vec::new(), response).into();
interfaces::default_send_command(&self.inner, cmd)
}
}
pub struct ZScanResult {
pub(crate) results: Option<Vec<(RedisValue, f64)>>,
pub(crate) inner: RefCount<RedisClientInner>,
pub(crate) scan_state: ValueScanInner,
pub(crate) can_continue: bool,
}
impl Scanner for ZScanResult {
type Page = Vec<(RedisValue, f64)>;
fn cursor(&self) -> Option<Cow<str>> {
self.scan_state.args[self.scan_state.cursor_idx].as_str()
}
fn has_more(&self) -> bool {
self.can_continue
}
fn results(&self) -> &Option<Self::Page> {
&self.results
}
fn take_results(&mut self) -> Option<Self::Page> {
self.results.take()
}
fn create_client(&self) -> RedisClient {
RedisClient {
inner: self.inner.clone(),
}
}
fn next(self) -> Result<(), RedisError> {
if !self.can_continue {
return Ok(());
}
let response = ResponseKind::ValueScan(self.scan_state);
let cmd: RedisCommand = (RedisCommandKind::Zscan, Vec::new(), response).into();
interfaces::default_send_command(&self.inner, cmd)
}
}