use crate::commands::options::{FlushMode, FunctionRestorePolicy};
use crate::error::Result;
use crate::executor::CommandExecutor;
use crate::routes::Route;
use crate::value;
use async_trait::async_trait;
use bytes::Bytes;
use redis::{Cmd, ToRedisArgs, Value};
#[async_trait]
pub trait ScriptingCommands: CommandExecutor {
async fn eval<K: ToRedisArgs + Send + Sync, A: ToRedisArgs + Send + Sync>(
&self,
script: &str,
keys: &[K],
args: &[A],
) -> Result<Value> {
let mut cmd = Cmd::new();
cmd.arg("EVAL").arg(script).arg(keys.len());
for k in keys {
cmd.arg(k);
}
for a in args {
cmd.arg(a);
}
self.execute_command(cmd, None).await
}
async fn evalsha<K: ToRedisArgs + Send + Sync, A: ToRedisArgs + Send + Sync>(
&self,
sha1: &str,
keys: &[K],
args: &[A],
) -> Result<Value> {
let mut cmd = Cmd::new();
cmd.arg("EVALSHA").arg(sha1).arg(keys.len());
for k in keys {
cmd.arg(k);
}
for a in args {
cmd.arg(a);
}
self.execute_command(cmd, None).await
}
async fn script_load(&self, script: &str) -> Result<String> {
let mut cmd = Cmd::new();
cmd.arg("SCRIPT").arg("LOAD").arg(script);
value::to_string(self.execute_command(cmd, None).await?)
}
async fn script_exists(&self, sha1s: &[&str]) -> Result<Vec<bool>> {
let mut cmd = Cmd::new();
cmd.arg("SCRIPT").arg("EXISTS");
for s in sha1s {
cmd.arg(*s);
}
match self.execute_command(cmd, None).await? {
Value::Array(items) => items.into_iter().map(value::to_bool).collect(),
other => Ok(vec![value::to_bool(other)?]),
}
}
async fn script_flush(&self) -> Result<()> {
let mut cmd = Cmd::new();
cmd.arg("SCRIPT").arg("FLUSH");
value::to_unit(self.execute_command(cmd, None).await?)
}
async fn fcall<K: ToRedisArgs + Send + Sync, A: ToRedisArgs + Send + Sync>(
&self,
function: &str,
keys: &[K],
args: &[A],
) -> Result<Value> {
let mut cmd = Cmd::new();
cmd.arg("FCALL").arg(function).arg(keys.len());
for k in keys {
cmd.arg(k);
}
for a in args {
cmd.arg(a);
}
self.execute_command(cmd, None).await
}
async fn fcall_ro<K: ToRedisArgs + Send + Sync, A: ToRedisArgs + Send + Sync>(
&self,
function: &str,
keys: &[K],
args: &[A],
) -> Result<Value> {
let mut cmd = Cmd::new();
cmd.arg("FCALL_RO").arg(function).arg(keys.len());
for k in keys {
cmd.arg(k);
}
for a in args {
cmd.arg(a);
}
self.execute_command(cmd, None).await
}
async fn fcall_route<K: ToRedisArgs + Send + Sync, A: ToRedisArgs + Send + Sync>(
&self,
function: &str,
keys: &[K],
args: &[A],
route: Route,
) -> Result<Value> {
let mut cmd = Cmd::new();
cmd.arg("FCALL").arg(function).arg(keys.len());
for k in keys {
cmd.arg(k);
}
for a in args {
cmd.arg(a);
}
let routing = route.to_routing_info(Some(&cmd));
self.execute_command(cmd, Some(routing)).await
}
async fn fcall_ro_route<K: ToRedisArgs + Send + Sync, A: ToRedisArgs + Send + Sync>(
&self,
function: &str,
keys: &[K],
args: &[A],
route: Route,
) -> Result<Value> {
let mut cmd = Cmd::new();
cmd.arg("FCALL_RO").arg(function).arg(keys.len());
for k in keys {
cmd.arg(k);
}
for a in args {
cmd.arg(a);
}
let routing = route.to_routing_info(Some(&cmd));
self.execute_command(cmd, Some(routing)).await
}
async fn function_load(&self, code: &str, replace: bool) -> Result<String> {
let mut cmd = Cmd::new();
cmd.arg("FUNCTION").arg("LOAD");
if replace {
cmd.arg("REPLACE");
}
cmd.arg(code);
value::to_string(self.execute_command(cmd, None).await?)
}
async fn function_delete(&self, library_name: &str) -> Result<()> {
let mut cmd = Cmd::new();
cmd.arg("FUNCTION").arg("DELETE").arg(library_name);
value::to_unit(self.execute_command(cmd, None).await?)
}
async fn function_flush(&self) -> Result<()> {
let mut cmd = Cmd::new();
cmd.arg("FUNCTION").arg("FLUSH");
value::to_unit(self.execute_command(cmd, None).await?)
}
async fn function_flush_mode(&self, mode: FlushMode) -> Result<()> {
let mut cmd = Cmd::new();
cmd.arg("FUNCTION").arg("FLUSH").arg(mode.as_arg());
value::to_unit(self.execute_command(cmd, None).await?)
}
async fn function_list(&self, library_name: Option<&str>, with_code: bool) -> Result<Value> {
let mut cmd = Cmd::new();
cmd.arg("FUNCTION").arg("LIST");
if let Some(n) = library_name {
cmd.arg("LIBRARYNAME").arg(n);
}
if with_code {
cmd.arg("WITHCODE");
}
self.execute_command(cmd, None).await
}
async fn function_dump(&self) -> Result<Bytes> {
let mut cmd = Cmd::new();
cmd.arg("FUNCTION").arg("DUMP");
value::to_bytes(self.execute_command(cmd, None).await?)
}
async fn function_restore<P: ToRedisArgs + Send>(
&self,
payload: P,
policy: FunctionRestorePolicy,
) -> Result<()> {
let mut cmd = Cmd::new();
cmd.arg("FUNCTION")
.arg("RESTORE")
.arg(payload)
.arg(policy.as_arg());
value::to_unit(self.execute_command(cmd, None).await?)
}
async fn function_stats(&self) -> Result<Value> {
let mut cmd = Cmd::new();
cmd.arg("FUNCTION").arg("STATS");
self.execute_command(cmd, None).await
}
async fn function_kill(&self) -> Result<()> {
let mut cmd = Cmd::new();
cmd.arg("FUNCTION").arg("KILL");
value::to_unit(self.execute_command(cmd, None).await?)
}
async fn script_kill(&self) -> Result<()> {
let mut cmd = Cmd::new();
cmd.arg("SCRIPT").arg("KILL");
value::to_unit(self.execute_command(cmd, None).await?)
}
async fn script_show(&self, sha1: &str) -> Result<Bytes> {
let mut cmd = Cmd::new();
cmd.arg("SCRIPT").arg("SHOW").arg(sha1);
value::to_bytes(self.execute_command(cmd, None).await?)
}
}
impl<T: CommandExecutor + ?Sized> ScriptingCommands for T {}