1use std::collections::HashMap;
2
3use crate::{
4 prepare_command,
5 resp::{
6 cmd, CommandArg, CommandArgs, FromValue, IntoArgs, SingleArgOrCollection, Value,
7 },
8 Error, FlushingMode, PreparedCommand, Result,
9};
10
11pub trait ScriptingCommands {
17 #[must_use]
25 fn eval<R>(&mut self, builder: CallBuilder) -> PreparedCommand<Self, R>
26 where
27 Self: Sized,
28 R: FromValue,
29 {
30 prepare_command(self, cmd("EVAL").arg(builder))
31 }
32
33 #[must_use]
42 fn eval_readonly<R>(&mut self, builder: CallBuilder) -> PreparedCommand<Self, R>
43 where
44 Self: Sized,
45 R: FromValue,
46 {
47 prepare_command(self, cmd("EVAL_RO").arg(builder))
48 }
49
50 #[must_use]
58 fn evalsha<R>(&mut self, builder: CallBuilder) -> PreparedCommand<Self, R>
59 where
60 Self: Sized,
61 R: FromValue,
62 {
63 prepare_command(self, cmd("EVALSHA").arg(builder))
64 }
65
66 #[must_use]
75 fn evalsha_readonly<R>(&mut self, builder: CallBuilder) -> PreparedCommand<Self, R>
76 where
77 Self: Sized,
78 R: FromValue,
79 {
80 prepare_command(self, cmd("EVALSHA_RO").arg(builder))
81 }
82
83 #[must_use]
91 fn fcall<R>(&mut self, builder: CallBuilder) -> PreparedCommand<Self, R>
92 where
93 Self: Sized,
94 R: FromValue,
95 {
96 prepare_command(self, cmd("FCALL").arg(builder))
97 }
98
99 #[must_use]
107 fn fcall_readonly<R>(&mut self, builder: CallBuilder) -> PreparedCommand<Self, R>
108 where
109 Self: Sized,
110 R: FromValue,
111 {
112 prepare_command(self, cmd("FCALL_RO").arg(builder))
113 }
114
115 #[must_use]
120 fn function_delete<L>(&mut self, library_name: L) -> PreparedCommand<Self, ()>
121 where
122 Self: Sized,
123 L: Into<CommandArg>,
124 {
125 prepare_command(self, cmd("FUNCTION").arg("DELETE").arg(library_name))
126 }
127
128 #[must_use]
138 fn function_dump<P>(&mut self) -> PreparedCommand<Self, P>
139 where
140 Self: Sized,
141 P: FromValue,
142 {
143 prepare_command(self, cmd("FUNCTION").arg("DUMP"))
144 }
145
146 #[must_use]
151 fn function_flush(&mut self, flushing_mode: FlushingMode) -> PreparedCommand<Self, ()>
152 where
153 Self: Sized,
154 {
155 prepare_command(self, cmd("FUNCTION").arg("FLUSH").arg(flushing_mode))
156 }
157
158 #[must_use]
163 fn function_kill(&mut self) -> PreparedCommand<Self, ()>
164 where
165 Self: Sized,
166 {
167 prepare_command(self, cmd("FUNCTION").arg("KILL"))
168 }
169
170 #[must_use]
175 fn function_list(
176 &mut self,
177 options: FunctionListOptions,
178 ) -> PreparedCommand<Self, Vec<LibraryInfo>>
179 where
180 Self: Sized,
181 {
182 prepare_command(self, cmd("FUNCTION").arg("LIST").arg(options))
183 }
184
185 #[must_use]
193 fn function_load<F, L>(&mut self, replace: bool, function_code: F) -> PreparedCommand<Self, L>
194 where
195 Self: Sized,
196 F: Into<CommandArg>,
197 L: FromValue,
198 {
199 prepare_command(
200 self,
201 cmd("FUNCTION")
202 .arg("LOAD")
203 .arg_if(replace, "REPLACE")
204 .arg(function_code),
205 )
206 }
207
208 #[must_use]
213 fn function_restore<P>(
214 &mut self,
215 serialized_payload: P,
216 policy: FunctionRestorePolicy,
217 ) -> PreparedCommand<Self, ()>
218 where
219 Self: Sized,
220 P: Into<CommandArg>,
221 {
222 prepare_command(
223 self,
224 cmd("FUNCTION")
225 .arg("RESTORE")
226 .arg(serialized_payload)
227 .arg(policy),
228 )
229 }
230
231 #[must_use]
236 fn function_stats(&mut self) -> PreparedCommand<Self, FunctionStats>
237 where
238 Self: Sized,
239 {
240 prepare_command(self, cmd("FUNCTION").arg("STATS"))
241 }
242
243 #[must_use]
248 fn script_debug(&mut self, debug_mode: ScriptDebugMode) -> PreparedCommand<Self, ()>
249 where
250 Self: Sized,
251 {
252 prepare_command(self, cmd("SCRIPT").arg("DEBUG").arg(debug_mode))
253 }
254
255 #[must_use]
263 fn script_exists<S, C>(&mut self, sha1s: C) -> PreparedCommand<Self, Vec<bool>>
264 where
265 Self: Sized,
266 S: Into<CommandArg>,
267 C: SingleArgOrCollection<S>,
268 {
269 prepare_command(self, cmd("SCRIPT").arg("EXISTS").arg(sha1s))
270 }
271
272 #[must_use]
277 fn script_flush(&mut self, flushing_mode: FlushingMode) -> PreparedCommand<Self, ()>
278 where
279 Self: Sized,
280 {
281 prepare_command(self, cmd("SCRIPT").arg("FLUSH").arg(flushing_mode))
282 }
283
284 #[must_use]
290 fn script_kill(&mut self) -> PreparedCommand<Self, ()>
291 where
292 Self: Sized,
293 {
294 prepare_command(self, cmd("SCRIPT").arg("KILL"))
295 }
296
297 #[must_use]
305 fn script_load<S, V>(&mut self, script: S) -> PreparedCommand<Self, V>
306 where
307 Self: Sized,
308 S: Into<CommandArg>,
309 V: FromValue,
310 {
311 prepare_command(self, cmd("SCRIPT").arg("LOAD").arg(script))
312 }
313}
314
315pub struct CallBuilder {
323 command_args: CommandArgs,
324 keys_added: bool,
325}
326
327impl CallBuilder {
328 #[must_use]
329 pub fn script<S: Into<CommandArg>>(script: S) -> Self {
330 Self {
331 command_args: CommandArgs::default().arg(script),
332 keys_added: false,
333 }
334 }
335
336 #[must_use]
337 pub fn sha1<S: Into<CommandArg>>(sha1: S) -> Self {
338 Self {
339 command_args: CommandArgs::default().arg(sha1),
340 keys_added: false,
341 }
342 }
343
344 #[must_use]
345 pub fn function<F: Into<CommandArg>>(function: F) -> Self {
346 Self {
347 command_args: CommandArgs::default().arg(function),
348 keys_added: false,
349 }
350 }
351
352 #[must_use]
354 pub fn keys<K, C>(self, keys: C) -> Self
355 where
356 K: Into<CommandArg>,
357 C: SingleArgOrCollection<K>,
358 {
359 Self {
360 command_args: self.command_args.arg(keys.num_args()).arg(keys),
361 keys_added: true,
362 }
363 }
364
365 #[must_use]
367 pub fn args<A, C>(self, args: C) -> Self
368 where
369 A: Into<CommandArg>,
370 C: SingleArgOrCollection<A>,
371 {
372 let command_args = if self.keys_added {
373 self.command_args.arg(args)
374 } else {
375 self.command_args.arg(0).arg(args)
377 };
378
379 Self {
380 command_args,
381 keys_added: true,
382 }
383 }
384}
385
386impl IntoArgs for CallBuilder {
387 fn into_args(self, args: CommandArgs) -> CommandArgs {
388 if self.command_args.len() == 1 {
390 args.arg(self.command_args).arg(0)
391 } else {
392 args.arg(self.command_args)
393 }
394 }
395}
396
397pub enum FunctionRestorePolicy {
399 Default,
401 Append,
404 Flush,
406 Replace,
410}
411
412impl Default for FunctionRestorePolicy {
413 fn default() -> Self {
414 Self::Default
415 }
416}
417
418impl IntoArgs for FunctionRestorePolicy {
419 fn into_args(self, args: CommandArgs) -> CommandArgs {
420 match self {
421 FunctionRestorePolicy::Default => args,
422 FunctionRestorePolicy::Append => args.arg("APPEND"),
423 FunctionRestorePolicy::Flush => args.arg("FLUSH"),
424 FunctionRestorePolicy::Replace => args.arg("REPLACE"),
425 }
426 }
427}
428
429#[derive(Debug)]
430pub struct LibraryInfo {
431 pub library_name: String,
432 pub engine: String,
433 pub functions: Vec<FunctionInfo>,
434 pub library_code: Option<String>,
435}
436
437impl FromValue for LibraryInfo {
438 fn from_value(value: Value) -> Result<Self> {
439 match &value {
440 Value::Array(Some(v)) if v.len() == 8 => {
441 fn into_result(values: &mut HashMap<String, Value>) -> Option<LibraryInfo> {
442 Some(LibraryInfo {
443 library_name: values.remove("library_name")?.into().ok()?,
444 engine: values.remove("engine")?.into().ok()?,
445 functions: values.remove("functions")?.into().ok()?,
446 library_code: values.remove("library_code")?.into().ok()?,
447 })
448 }
449
450 into_result(&mut value.into()?)
451 .ok_or_else(|| Error::Client("Cannot parse LibraryInfo".to_owned()))
452 }
453 _ => {
454 fn into_result(values: &mut HashMap<String, Value>) -> Option<LibraryInfo> {
455 Some(LibraryInfo {
456 library_name: values.remove("library_name")?.into().ok()?,
457 engine: values.remove("engine")?.into().ok()?,
458 functions: values.remove("functions")?.into().ok()?,
459 library_code: None,
460 })
461 }
462
463 into_result(&mut value.into()?)
464 .ok_or_else(|| Error::Client("Cannot parse LibraryInfo".to_owned()))
465 }
466 }
467 }
468}
469
470#[derive(Debug)]
471pub struct FunctionInfo {
472 pub name: String,
473 pub description: String,
474 pub flags: Vec<String>,
475}
476
477impl FromValue for FunctionInfo {
478 fn from_value(value: Value) -> Result<Self> {
479 match &value {
480 Value::Array(Some(v)) if v.len() == 6 => {
481 fn into_result(values: &mut HashMap<String, Value>) -> Option<FunctionInfo> {
482 Some(FunctionInfo {
483 name: values.remove("name")?.into().ok()?,
484 description: values.remove("description")?.into().ok()?,
485 flags: values.remove("flags")?.into().ok()?,
486 })
487 }
488
489 into_result(&mut value.into()?)
490 .ok_or_else(|| Error::Client("Cannot parse FunctionInfo".to_owned()))
491 }
492 _ => Err(Error::Client("Cannot parse FunctionInfo".to_owned())),
493 }
494 }
495}
496
497#[derive(Debug)]
498pub struct FunctionStats {
499 pub running_script: Option<RunningScript>,
500 pub engines: HashMap<String, EngineStats>,
501}
502
503impl FromValue for FunctionStats {
504 fn from_value(value: Value) -> Result<Self> {
505 match &value {
506 Value::Array(Some(v)) if v.len() == 4 => {
507 fn into_result(values: &mut HashMap<String, Value>) -> Option<FunctionStats> {
508 Some(FunctionStats {
509 running_script: values.remove("running_script")?.into().ok()?,
510 engines: values.remove("engines")?.into().ok()?,
511 })
512 }
513
514 into_result(&mut value.into()?)
515 .ok_or_else(|| Error::Client("Cannot parse FunctionStats".to_owned()))
516 }
517 _ => Err(Error::Client("Cannot parse FunctionStats".to_owned())),
518 }
519 }
520}
521
522#[derive(Debug)]
523pub struct RunningScript {
524 pub name: String,
525 pub command: Vec<String>,
526 pub duration_ms: u64,
527}
528
529impl FromValue for RunningScript {
530 fn from_value(value: Value) -> Result<Self> {
531 match &value {
532 Value::Array(Some(v)) if v.len() == 6 => {
533 fn into_result(values: &mut HashMap<String, Value>) -> Option<RunningScript> {
534 Some(RunningScript {
535 name: values.remove("name")?.into().ok()?,
536 command: values.remove("command")?.into().ok()?,
537 duration_ms: values.remove("duration_ms")?.into().ok()?,
538 })
539 }
540
541 into_result(&mut value.into()?)
542 .ok_or_else(|| Error::Client("Cannot parse RunningScript".to_owned()))
543 }
544 _ => Err(Error::Client("Cannot parse RunningScript".to_owned())),
545 }
546 }
547}
548
549#[derive(Debug, Default)]
550pub struct EngineStats {
551 pub libraries_count: usize,
552 pub functions_count: usize,
553}
554
555impl FromValue for EngineStats {
556 fn from_value(value: Value) -> Result<Self> {
557 match &value {
558 Value::Array(Some(v)) if v.len() == 4 => {
559 fn into_result(values: &mut HashMap<String, Value>) -> Option<EngineStats> {
560 Some(EngineStats {
561 libraries_count: values.remove("libraries_count")?.into().ok()?,
562 functions_count: values.remove("functions_count")?.into().ok()?,
563 })
564 }
565
566 into_result(&mut value.into()?)
567 .ok_or_else(|| Error::Client("Cannot parse EngineStats".to_owned()))
568 }
569 _ => Err(Error::Client("Cannot parse EngineStats".to_owned())),
570 }
571 }
572}
573
574pub enum ScriptDebugMode {
575 Default,
576 Yes,
577 Sync,
578 No,
579}
580
581impl IntoArgs for ScriptDebugMode {
582 fn into_args(self, args: CommandArgs) -> CommandArgs {
583 match self {
584 ScriptDebugMode::Default => args,
585 ScriptDebugMode::Yes => args.arg("YES"),
586 ScriptDebugMode::Sync => args.arg("SYNC"),
587 ScriptDebugMode::No => args.arg("NO"),
588 }
589 }
590}
591
592#[derive(Default)]
594pub struct FunctionListOptions {
595 command_args: CommandArgs,
596}
597
598impl FunctionListOptions {
599 #[must_use]
600 pub fn library_name_pattern<P: Into<CommandArg>>(self, library_name_pattern: P) -> Self {
601 Self {
602 command_args: self
603 .command_args
604 .arg("LIBRARYNAME")
605 .arg(library_name_pattern),
606 }
607 }
608
609 #[must_use]
610 pub fn with_code(self) -> Self {
611 Self {
612 command_args: self.command_args.arg("WITHCODE"),
613 }
614 }
615}
616
617impl IntoArgs for FunctionListOptions {
618 fn into_args(self, args: CommandArgs) -> CommandArgs {
619 args.arg(self.command_args)
620 }
621}