use crate::ValkeyResult;
use crate::cmd::Cmd;
use crate::commands::options::{Limit, MigrateOptions, OrderBy, RestoreOptions};
use crate::executor::CommandExecutor;
use crate::value::FromValkeyValue;
use crate::value::ValkeyValue;
use crate::value::to_glide_error;
use crate::write::ToValkeyArgs;
use async_trait::async_trait;
use bytes::Bytes;
#[async_trait]
pub trait GenericCommands: CommandExecutor {
async fn randomkey(&self) -> ValkeyResult<Option<Bytes>> {
let mut cmd = Cmd::new();
cmd.arg("RANDOMKEY");
Option::<Bytes>::from_owned_valkey_value(self.execute_command(cmd, None).await?)
}
async fn dump<K: ToValkeyArgs + Send>(&self, key: K) -> ValkeyResult<Option<Bytes>> {
let mut cmd = Cmd::new();
cmd.arg("DUMP").arg(key);
Option::<Bytes>::from_owned_valkey_value(self.execute_command(cmd, None).await?)
}
async fn touch<K: ToValkeyArgs + Send + Sync>(&self, keys: &[K]) -> ValkeyResult<i64> {
let mut cmd = Cmd::new();
cmd.arg("TOUCH");
for k in keys {
cmd.arg(k);
}
i64::from_owned_valkey_value(self.execute_command(cmd, None).await?)
}
async fn sort<K: ToValkeyArgs + Send>(
&self,
key: K,
order: Option<OrderBy>,
limit: Option<Limit>,
alpha: bool,
) -> ValkeyResult<Vec<Bytes>> {
let mut cmd = Cmd::new();
cmd.arg("SORT").arg(key);
if let Some(l) = limit {
cmd.arg("LIMIT").arg(l.offset).arg(l.count);
}
if let Some(o) = order {
cmd.arg(o.as_arg());
}
if alpha {
cmd.arg("ALPHA");
}
match self.execute_command(cmd, None).await? {
ValkeyValue::Array(items) => items
.into_iter()
.map(Bytes::from_owned_valkey_value)
.collect(),
ValkeyValue::Nil => Ok(Vec::new()),
other => Ok(vec![Bytes::from_owned_valkey_value(other)?]),
}
}
async fn restore<K: ToValkeyArgs + Send, V: ToValkeyArgs + Send>(
&self,
key: K,
ttl_ms: i64,
serialized: V,
options: RestoreOptions,
) -> ValkeyResult<()> {
let mut cmd = Cmd::new();
cmd.arg("RESTORE")
.arg(key)
.arg(ttl_ms)
.arg(serialized)
.arg(options);
<()>::from_owned_valkey_value(self.execute_command(cmd, None).await?)
}
async fn wait(&self, numreplicas: i64, timeout_ms: i64) -> ValkeyResult<i64> {
let mut cmd = Cmd::new();
cmd.arg("WAIT").arg(numreplicas).arg(timeout_ms);
i64::from_owned_valkey_value(self.execute_command(cmd, None).await?)
}
async fn sort_store<K: ToValkeyArgs + Send, D: ToValkeyArgs + Send>(
&self,
key: K,
destination: D,
order: Option<OrderBy>,
limit: Option<Limit>,
alpha: bool,
) -> ValkeyResult<i64> {
let mut cmd = Cmd::new();
cmd.arg("SORT").arg(key);
if let Some(l) = limit {
cmd.arg("LIMIT").arg(l.offset).arg(l.count);
}
if let Some(o) = order {
cmd.arg(o.as_arg());
}
if alpha {
cmd.arg("ALPHA");
}
cmd.arg("STORE").arg(destination);
i64::from_owned_valkey_value(self.execute_command(cmd, None).await?)
}
async fn sort_ro<K: ToValkeyArgs + Send>(
&self,
key: K,
order: Option<OrderBy>,
limit: Option<Limit>,
alpha: bool,
) -> ValkeyResult<Vec<Bytes>> {
let mut cmd = Cmd::new();
cmd.arg("SORT_RO").arg(key);
if let Some(l) = limit {
cmd.arg("LIMIT").arg(l.offset).arg(l.count);
}
if let Some(o) = order {
cmd.arg(o.as_arg());
}
if alpha {
cmd.arg("ALPHA");
}
match self.execute_command(cmd, None).await? {
ValkeyValue::Array(items) => items
.into_iter()
.map(Bytes::from_owned_valkey_value)
.collect(),
ValkeyValue::Nil => Ok(Vec::new()),
other => Ok(vec![Bytes::from_owned_valkey_value(other)?]),
}
}
async fn move_key<K: ToValkeyArgs + Send>(&self, key: K, db: i64) -> ValkeyResult<bool> {
let mut cmd = Cmd::new();
cmd.arg("MOVE").arg(key).arg(db);
bool::from_owned_valkey_value(self.execute_command(cmd, None).await?)
}
async fn migrate<H: ToValkeyArgs + Send, K: ToValkeyArgs + Send>(
&self,
host: H,
port: i64,
key: K,
destination_db: i64,
timeout_ms: i64,
options: MigrateOptions,
) -> ValkeyResult<()> {
let mut cmd = Cmd::new();
cmd.arg("MIGRATE")
.arg(host)
.arg(port)
.arg(key)
.arg(destination_db)
.arg(timeout_ms)
.arg(options);
<()>::from_owned_valkey_value(self.execute_command(cmd, None).await?)
}
async fn watch<K: ToValkeyArgs + Send + Sync>(&self, keys: &[K]) -> ValkeyResult<()> {
let mut cmd = Cmd::new();
cmd.arg("WATCH");
for k in keys {
cmd.arg(k);
}
<()>::from_owned_valkey_value(self.execute_command(cmd, None).await?)
}
async fn unwatch(&self) -> ValkeyResult<()> {
let mut cmd = Cmd::new();
cmd.arg("UNWATCH");
<()>::from_owned_valkey_value(self.execute_command(cmd, None).await?)
}
}
pub(crate) fn parse_scan_reply(reply: ValkeyValue) -> ValkeyResult<(String, Vec<Bytes>)> {
match reply {
ValkeyValue::Array(mut items) if items.len() == 2 => {
let keys_val = items.pop().unwrap();
let cursor_val = items.pop().unwrap();
let cursor = String::from_owned_valkey_value(cursor_val)?;
let keys = match keys_val {
ValkeyValue::Array(elems) => elems
.into_iter()
.map(Bytes::from_owned_valkey_value)
.collect::<ValkeyResult<Vec<_>>>()?,
ValkeyValue::Nil => Vec::new(),
other => {
return Err(to_glide_error(other, "Unexpected SCAN keys shape."));
}
};
Ok((cursor, keys))
}
other => Err(to_glide_error(other, "Unexpected SCAN reply shape.")),
}
}
impl<T: CommandExecutor + ?Sized> GenericCommands for T {}