redis_driver/commands/server_commands.rs
1use std::{collections::HashMap, str::FromStr};
2
3use crate::{
4 prepare_command,
5 resp::{
6 cmd, CommandArg, CommandArgs, FromKeyValueValueArray, FromSingleValueArray, FromValue,
7 HashMapExt, IntoArgs, KeyValueArgOrCollection, SingleArgOrCollection, Value,
8 },
9 Error, PreparedCommand, Result,
10};
11
12/// A group of Redis commands related to Server Management
13/// # See Also
14/// [Redis Server Management Commands](https://redis.io/commands/?group=server)
15/// [ACL guide](https://redis.io/docs/manual/security/acl/)
16pub trait ServerCommands {
17 /// The command shows the available ACL categories if called without arguments.
18 /// If a category name is given, the command shows all the Redis commands in the specified category.
19 ///
20 /// # Return
21 /// A collection of ACL categories or a collection of commands inside a given category.
22 ///
23 /// # Errors
24 /// The command may return an error if an invalid category name is given as argument.
25 ///
26 /// # See Also
27 /// [<https://redis.io/commands/acl-cat/>](https://redis.io/commands/acl-cat/)
28 fn acl_cat<C, CC>(&mut self, options: AclCatOptions) -> PreparedCommand<Self, CC>
29 where
30 Self: Sized,
31 C: FromValue,
32 CC: FromSingleValueArray<C>,
33 {
34 prepare_command(self, cmd("ACL").arg("CAT").arg(options))
35 }
36
37 /// Delete all the specified ACL users and terminate all
38 /// the connections that are authenticated with such users.
39 ///
40 /// # Return
41 /// The number of users that were deleted.
42 /// This number will not always match the number of arguments since certain users may not exist.
43 ///
44 /// # See Also
45 /// [<https://redis.io/commands/acl-deluser/>](https://redis.io/commands/acl-deluser/)
46 fn acl_deluser<U, UU>(&mut self, usernames: UU) -> PreparedCommand<Self, usize>
47 where
48 Self: Sized,
49 U: Into<CommandArg>,
50 UU: SingleArgOrCollection<U>,
51 {
52 prepare_command(self, cmd("ACL").arg("DELUSER").arg(usernames))
53 }
54
55 /// Simulate the execution of a given command by a given user.
56 ///
57 /// # Return
58 /// OK on success.
59 /// An error describing why the user can't execute the command.
60 ///
61 /// # See Also
62 /// [<https://redis.io/commands/acl-dryrun/>](https://redis.io/commands/acl-dryrun/)
63 fn acl_dryrun<U, C, R>(
64 &mut self,
65 username: U,
66 command: C,
67 options: AclDryRunOptions,
68 ) -> PreparedCommand<Self, R>
69 where
70 Self: Sized,
71 U: Into<CommandArg>,
72 C: Into<CommandArg>,
73 R: FromValue,
74 {
75 prepare_command(
76 self,
77 cmd("ACL")
78 .arg("DRYRUN")
79 .arg(username)
80 .arg(command)
81 .arg(options),
82 )
83 }
84
85 /// Generates a password starting from /dev/urandom if available,
86 /// otherwise (in systems without /dev/urandom) it uses a weaker
87 /// system that is likely still better than picking a weak password by hand.
88 ///
89 /// # Return
90 /// by default 64 bytes string representing 256 bits of pseudorandom data.
91 /// Otherwise if an argument if needed, the output string length is the number
92 /// of specified bits (rounded to the next multiple of 4) divided by 4.
93 ///
94 /// # See Also
95 /// [<https://redis.io/commands/acl-genpass/>](https://redis.io/commands/acl-genpass/)
96 fn acl_genpass<R: FromValue>(&mut self, options: AclGenPassOptions) -> PreparedCommand<Self, R>
97 where
98 Self: Sized,
99 {
100 prepare_command(self, cmd("ACL").arg("GENPASS").arg(options))
101 }
102
103 /// The command returns all the rules defined for an existing ACL user.
104 ///
105 /// # Return
106 /// A collection of ACL rule definitions for the user.
107 ///
108 /// # See Also
109 /// [<https://redis.io/commands/acl-getuser/>](https://redis.io/commands/acl-getuser/)
110 fn acl_getuser<U, RR>(&mut self, username: U) -> PreparedCommand<Self, RR>
111 where
112 Self: Sized,
113 U: Into<CommandArg>,
114 RR: FromKeyValueValueArray<String, Value>,
115 {
116 prepare_command(self, cmd("ACL").arg("GETUSER").arg(username))
117 }
118
119 /// The command shows the currently active ACL rules in the Redis server.
120 ///
121 /// # Return
122 /// An array of strings.
123 /// Each line in the returned array defines a different user, and the
124 /// format is the same used in the redis.conf file or the external ACL file
125 ///
126 /// # See Also
127 /// [<https://redis.io/commands/acl-list/>](https://redis.io/commands/acl-list/)
128 fn acl_list(&mut self) -> PreparedCommand<Self, Vec<String>>
129 where
130 Self: Sized,
131 {
132 prepare_command(self, cmd("ACL").arg("LIST"))
133 }
134
135 /// When Redis is configured to use an ACL file (with the aclfile configuration option),
136 /// this command will reload the ACLs from the file, replacing all the current ACL rules
137 /// with the ones defined in the file.
138 ///
139 /// # Return
140 /// An array of strings.
141 /// Each line in the returned array defines a different user, and the
142 /// format is the same used in the redis.conf file or the external ACL file
143 ///
144 /// # Errors
145 /// The command may fail with an error for several reasons:
146 /// - if the file is not readable,
147 /// - if there is an error inside the file, and in such case the error will be reported to the user in the error.
148 /// - Finally the command will fail if the server is not configured to use an external ACL file.
149 ///
150 /// # See Also
151 /// [<https://redis.io/commands/acl-load/>](https://redis.io/commands/acl-load/)
152 fn acl_load(&mut self) -> PreparedCommand<Self, ()>
153 where
154 Self: Sized,
155 {
156 prepare_command(self, cmd("ACL").arg("LOAD"))
157 }
158
159 /// The command shows a list of recent ACL security events
160 ///
161 /// # Return
162 /// A key/value collection of ACL security events.
163 /// Empty collection when called with the [`reset`](crate::AclLogOptions::reset) option
164 ///
165 /// # See Also
166 /// [<https://redis.io/commands/acl-log/>](https://redis.io/commands/acl-log/)
167 fn acl_log<EE>(&mut self, options: AclLogOptions) -> PreparedCommand<Self, Vec<EE>>
168 where
169 Self: Sized,
170 EE: FromKeyValueValueArray<String, Value>,
171 {
172 prepare_command(self, cmd("ACL").arg("LOG").arg(options))
173 }
174
175 /// When Redis is configured to use an ACL file (with the aclfile configuration option),
176 /// this command will save the currently defined ACLs from the server memory to the ACL file.
177 ///
178 /// # Errors
179 /// The command may fail with an error for several reasons:
180 /// - if the file cannot be written
181 /// - if the server is not configured to use an external ACL file.
182 ///
183 /// # See Also
184 /// [<https://redis.io/commands/acl-save/>](https://redis.io/commands/acl-save/)
185 fn acl_save(&mut self) -> PreparedCommand<Self, ()>
186 where
187 Self: Sized,
188 {
189 prepare_command(self, cmd("ACL").arg("SAVE"))
190 }
191
192 /// Create an ACL user with the specified rules or modify the rules of an existing user.
193 ///
194 /// # Errors
195 /// If the rules contain errors, the error is returned.
196 ///
197 /// # See Also
198 /// [<https://redis.io/commands/acl-setuser/>](https://redis.io/commands/acl-setuser/)
199 fn acl_setuser<U, R, RR>(&mut self, username: U, rules: RR) -> PreparedCommand<Self, ()>
200 where
201 Self: Sized,
202 U: Into<CommandArg>,
203 R: Into<CommandArg>,
204 RR: SingleArgOrCollection<R>,
205 {
206 prepare_command(self, cmd("ACL").arg("SETUSER").arg(username).arg(rules))
207 }
208
209 /// The command shows a list of all the usernames of the currently configured users in the Redis ACL system.
210 ///
211 /// # Return
212 /// A collection of usernames
213 ///
214 /// # See Also
215 /// [<https://redis.io/commands/acl-users/>](https://redis.io/commands/acl-users/)
216 fn acl_users<U, UU>(&mut self) -> PreparedCommand<Self, UU>
217 where
218 Self: Sized,
219 U: FromValue,
220 UU: FromSingleValueArray<U>,
221 {
222 prepare_command(self, cmd("ACL").arg("USERS"))
223 }
224
225 /// Return the username the current connection is authenticated with.
226 ///
227 /// # Return
228 /// The username of the current connection.
229 ///
230 /// # See Also
231 /// [<https://redis.io/commands/acl-whoami/>](https://redis.io/commands/acl-whoami/)
232 fn acl_whoami<U: FromValue>(&mut self) -> PreparedCommand<Self, U>
233 where
234 Self: Sized,
235 {
236 prepare_command(self, cmd("ACL").arg("WHOAMI"))
237 }
238
239 /// Return an array with details about every Redis command.
240 ///
241 /// # Return
242 /// A nested list of command details.
243 /// The order of commands in the array is random.
244 ///
245 /// # See Also
246 /// [<https://redis.io/commands/command/>](https://redis.io/commands/command/)
247 fn command(&mut self) -> PreparedCommand<Self, Vec<CommandInfo>>
248 where
249 Self: Sized,
250 {
251 prepare_command(self, cmd("COMMAND"))
252 }
253
254 /// Number of total commands in this Redis server.
255 ///
256 /// # Return
257 /// number of commands returned by [`command`](crate::ServerCommands::command)
258 ///
259 /// # See Also
260 /// [<https://redis.io/commands/command-count/>](https://redis.io/commands/command-count/)
261 fn command_count(&mut self) -> PreparedCommand<Self, usize>
262 where
263 Self: Sized,
264 {
265 prepare_command(self, cmd("COMMAND").arg("COUNT"))
266 }
267
268 /// Number of total commands in this Redis server.
269 ///
270 /// # Return
271 /// map key=command name, value=command doc
272 ///
273 /// # See Also
274 /// [<https://redis.io/commands/command-docs/>](https://redis.io/commands/command-docs/)
275 fn command_docs<N, NN, DD>(&mut self, command_names: NN) -> PreparedCommand<Self, DD>
276 where
277 Self: Sized,
278 N: Into<CommandArg>,
279 NN: SingleArgOrCollection<N>,
280 DD: FromKeyValueValueArray<String, CommandDoc>,
281 {
282 prepare_command(self, cmd("COMMAND").arg("DOCS").arg(command_names))
283 }
284
285 /// A helper command to let you find the keys from a full Redis command.
286 ///
287 /// # Return
288 /// list of keys from your command.
289 ///
290 /// # See Also
291 /// [<https://redis.io/commands/command-_getkeys/>](https://redis.io/commands/command-_getkeys/)
292 fn command_getkeys<A, AA, KK>(&mut self, args: AA) -> PreparedCommand<Self, KK>
293 where
294 Self: Sized,
295 A: Into<CommandArg>,
296 AA: SingleArgOrCollection<A>,
297 KK: FromSingleValueArray<String>,
298 {
299 prepare_command(self, cmd("COMMAND").arg("GETKEYS").arg(args))
300 }
301
302 /// A helper command to let you find the keys from a full Redis command together with flags indicating what each key is used for.
303 ///
304 /// # Return
305 /// map of keys with their flags from your command.
306 ///
307 /// # See Also
308 /// [<https://redis.io/commands/command-getkeysandflags/>](https://redis.io/commands/command-getkeysandflags/)
309 fn command_getkeysandflags<A, AA, KK>(&mut self, args: AA) -> PreparedCommand<Self, KK>
310 where
311 Self: Sized,
312 A: Into<CommandArg>,
313 AA: SingleArgOrCollection<A>,
314 KK: FromKeyValueValueArray<String, Vec<String>>,
315 {
316 prepare_command(self, cmd("COMMAND").arg("GETKEYSANDFLAGS").arg(args))
317 }
318
319 /// Return an array with details about multiple Redis command.
320 ///
321 /// # Return
322 /// A nested list of command details.
323 ///
324 /// # See Also
325 /// [<https://redis.io/commands/command-info/>](https://redis.io/commands/command-info/)
326 fn command_info<N, NN>(&mut self, command_names: NN) -> PreparedCommand<Self, Vec<CommandInfo>>
327 where
328 Self: Sized,
329 N: Into<CommandArg>,
330 NN: SingleArgOrCollection<N>,
331 {
332 prepare_command(self, cmd("COMMAND").arg("INFO").arg(command_names))
333 }
334
335 /// Return an array of the server's command names based on optional filters
336 ///
337 /// # Return
338 /// an array of the server's command names.
339 ///
340 /// # See Also
341 /// [<https://redis.io/commands/command-list/>](https://redis.io/commands/command-list/)
342 fn command_list<CC>(&mut self, options: CommandListOptions) -> PreparedCommand<Self, CC>
343 where
344 Self: Sized,
345 CC: FromSingleValueArray<String>,
346 {
347 prepare_command(self, cmd("COMMAND").arg("LIST").arg(options))
348 }
349
350 /// Used to read the configuration parameters of a running Redis server.
351 ///
352 /// For every key that does not hold a string value or does not exist,
353 /// the special value nil is returned. Because of this, the operation never fails.
354 ///
355 /// # Return
356 /// Array reply: collection of the requested params with their matching values.
357 ///
358 /// # See Also
359 /// [<https://redis.io/commands/config-get/>](https://redis.io/commands/config-get/)
360 #[must_use]
361 fn config_get<P, PP, V, VV>(&mut self, params: PP) -> PreparedCommand<Self, VV>
362 where
363 Self: Sized,
364 P: Into<CommandArg>,
365 PP: SingleArgOrCollection<P>,
366 V: FromValue,
367 VV: FromKeyValueValueArray<String, V>,
368 {
369 prepare_command(self, cmd("CONFIG").arg("GET").arg(params))
370 }
371
372 /// Resets the statistics reported by Redis using the [`info`](crate::ServerCommands::info) command.
373 ///
374 /// # See Also
375 /// [<https://redis.io/commands/config-resetstat/>](https://redis.io/commands/config-resetstat/)
376 #[must_use]
377 fn config_resetstat(&mut self) -> PreparedCommand<Self, ()>
378 where
379 Self: Sized,
380 {
381 prepare_command(self, cmd("CONFIG").arg("RESETSTAT"))
382 }
383
384 /// Rewrites the redis.conf file the server was started with,
385 /// applying the minimal changes needed to make it reflect the configuration currently used by the server,
386 /// which may be different compared to the original one because of the use of the
387 /// [`config_set`](crate::ServerCommands::config_set) command.
388 ///
389 /// # See Also
390 /// [<https://redis.io/commands/config-rewrite/>](https://redis.io/commands/config-rewrite/)
391 #[must_use]
392 fn config_rewrite(&mut self) -> PreparedCommand<Self, ()>
393 where
394 Self: Sized,
395 {
396 prepare_command(self, cmd("CONFIG").arg("REWRITE"))
397 }
398
399 /// Used in order to reconfigure the server at run time without the need to restart Redis.
400 ///
401 /// # See Also
402 /// [<https://redis.io/commands/config-set/>](https://redis.io/commands/config-set/)
403 #[must_use]
404 fn config_set<P, V, C>(&mut self, configs: C) -> PreparedCommand<Self, ()>
405 where
406 Self: Sized,
407 P: Into<CommandArg>,
408 V: Into<CommandArg>,
409 C: KeyValueArgOrCollection<P, V>,
410 {
411 prepare_command(self, cmd("CONFIG").arg("SET").arg(configs))
412 }
413
414 /// Return the number of keys in the currently-selected database.
415 ///
416 /// # See Also
417 /// [<https://redis.io/commands/dbsize/>](https://redis.io/commands/dbsize/)
418 #[must_use]
419 fn dbsize(&mut self) -> PreparedCommand<Self, usize>
420 where
421 Self: Sized,
422 {
423 prepare_command(self, cmd("DBSIZE"))
424 }
425
426 /// This command will start a coordinated failover between
427 /// the currently-connected-to master and one of its replicas.
428 ///
429 /// # See Also
430 /// [<https://redis.io/commands/failover/>](https://redis.io/commands/failover/)
431 #[must_use]
432 fn failover(&mut self, options: FailOverOptions) -> PreparedCommand<Self, ()>
433 where
434 Self: Sized,
435 {
436 prepare_command(self, cmd("FAILOVER").arg(options))
437 }
438
439 /// Delete all the keys of the currently selected DB.
440 ///
441 /// # See Also
442 /// [<https://redis.io/commands/flushdb/>](https://redis.io/commands/flushdb/)
443 #[must_use]
444 fn flushdb(&mut self, flushing_mode: FlushingMode) -> PreparedCommand<Self, ()>
445 where
446 Self: Sized,
447 {
448 prepare_command(self, cmd("FLUSHDB").arg(flushing_mode))
449 }
450
451 /// Delete all the keys of all the existing databases, not just the currently selected one.
452 ///
453 /// # See Also
454 /// [<https://redis.io/commands/flushall/>](https://redis.io/commands/flushall/)
455 #[must_use]
456 fn flushall(&mut self, flushing_mode: FlushingMode) -> PreparedCommand<Self, ()>
457 where
458 Self: Sized,
459 {
460 prepare_command(self, cmd("FLUSHALL").arg(flushing_mode))
461 }
462
463 /// This command returns information and statistics about the server
464 /// in a format that is simple to parse by computers and easy to read by humans.
465 ///
466 /// # See Also
467 /// [<https://redis.io/commands/info/>](https://redis.io/commands/info/)
468 #[must_use]
469 fn info<SS>(&mut self, sections: SS) -> PreparedCommand<Self, String>
470 where
471 Self: Sized,
472 SS: SingleArgOrCollection<InfoSection>,
473 {
474 prepare_command(self, cmd("INFO").arg(sections))
475 }
476
477 /// Return the UNIX TIME of the last DB save executed with success.
478 ///
479 /// # See Also
480 /// [<https://redis.io/commands/lastsave/>](https://redis.io/commands/lastsave/)
481 #[must_use]
482 fn lastsave(&mut self) -> PreparedCommand<Self, u64>
483 where
484 Self: Sized,
485 {
486 prepare_command(self, cmd("LASTSAVE"))
487 }
488
489 /// This command reports about different latency-related issues and advises about possible remedies.
490 ///
491 /// # Return
492 /// String report
493 ///
494 /// # See Also
495 /// [<https://redis.io/commands/latency-doctor/>](https://redis.io/commands/latency-doctor/)
496 #[must_use]
497 fn latency_doctor(&mut self) -> PreparedCommand<Self, String>
498 where
499 Self: Sized,
500 {
501 prepare_command(self, cmd("LATENCY").arg("DOCTOR"))
502 }
503
504 /// Produces an ASCII-art style graph for the specified event.
505 ///
506 /// # Return
507 /// String graph
508 ///
509 /// # See Also
510 /// [<https://redis.io/commands/latency-graph/>](https://redis.io/commands/latency-graph/)
511 #[must_use]
512 fn latency_graph(&mut self, event: LatencyHistoryEvent) -> PreparedCommand<Self, String>
513 where
514 Self: Sized,
515 {
516 prepare_command(self, cmd("LATENCY").arg("GRAPH").arg(event))
517 }
518
519 /// This command reports a cumulative distribution of latencies
520 /// in the format of a histogram for each of the specified command names.
521 ///
522 /// # Return
523 /// The command returns a map where each key is a command name, and each value is a CommandHistogram instance.
524 ///
525 /// # See Also
526 /// [<https://redis.io/commands/latency-histogram/>](https://redis.io/commands/latency-histogram/)
527 #[must_use]
528 fn latency_histogram<C, CC, RR>(&mut self, commands: CC) -> PreparedCommand<Self, RR>
529 where
530 Self: Sized,
531 C: Into<CommandArg>,
532 CC: SingleArgOrCollection<C>,
533 RR: FromKeyValueValueArray<String, CommandHistogram>,
534 {
535 prepare_command(self, cmd("LATENCY").arg("HISTOGRAM").arg(commands))
536 }
537
538 /// This command returns the raw data of the event's latency spikes time series.
539 ///
540 /// # Return
541 /// The command returns a collection where each element is a two elements tuple representing
542 /// - the unix timestamp in seconds
543 /// - the latency of the event in milliseconds
544 ///
545 /// # See Also
546 /// [<https://redis.io/commands/latency-history/>](https://redis.io/commands/latency-history/)
547 #[must_use]
548 fn latency_history<RR>(&mut self, event: LatencyHistoryEvent) -> PreparedCommand<Self, RR>
549 where
550 Self: Sized,
551 RR: FromSingleValueArray<(u32, u32)>,
552 {
553 prepare_command(self, cmd("LATENCY").arg("HISTORY").arg(event))
554 }
555
556 /// This command reports the latest latency events logged.
557 ///
558 /// # Return
559 /// A collection of the latest latency events logged.
560 /// Each reported event has the following fields:
561 /// - Event name.
562 /// - Unix timestamp of the latest latency spike for the event.
563 /// - Latest event latency in millisecond.
564 /// - All-time maximum latency for this event.
565 ///
566 /// "All-time" means the maximum latency since the Redis instance was started,
567 /// or the time that events were [`reset`](crate::ConnectionCommands::reset).
568 ///
569 /// # See Also
570 /// [<https://redis.io/commands/latency-latest/>](https://redis.io/commands/latency-latest/)
571 #[must_use]
572 fn latency_latest<RR>(&mut self) -> PreparedCommand<Self, RR>
573 where
574 Self: Sized,
575 RR: FromSingleValueArray<(String, u32, u32, u32)>,
576 {
577 prepare_command(self, cmd("LATENCY").arg("LATEST"))
578 }
579
580 /// This command resets the latency spikes time series of all, or only some, events.
581 ///
582 /// # Return
583 /// the number of event time series that were reset.
584 ///
585 /// # See Also
586 /// [<https://redis.io/commands/latency-latest/>](https://redis.io/commands/latency-latest/)
587 #[must_use]
588 fn latency_reset<EE>(&mut self, events: EE) -> PreparedCommand<Self, usize>
589 where
590 Self: Sized,
591 EE: SingleArgOrCollection<LatencyHistoryEvent>,
592 {
593 prepare_command(self, cmd("LATENCY").arg("RESET").arg(events))
594 }
595
596 /// The LOLWUT command displays the Redis version: however as a side effect of doing so,
597 /// it also creates a piece of generative computer art that is different with each version of Redis.
598 ///
599 /// # Return
600 /// the string containing the generative computer art, and a text with the Redis version.
601 ///
602 /// # See Also
603 /// [<https://redis.io/commands/lolwut/>](https://redis.io/commands/lolwut/)
604 #[must_use]
605 fn lolwut(&mut self, options: LolWutOptions) -> PreparedCommand<Self, String>
606 where
607 Self: Sized,
608 {
609 prepare_command(self, cmd("LOLWUT").arg(options))
610 }
611
612 /// This command reports about different memory-related issues that
613 /// the Redis server experiences, and advises about possible remedies.
614 ///
615 /// # Return
616 /// the string report.
617 ///
618 /// # See Also
619 /// [<https://redis.io/commands/memory-doctor/>](https://redis.io/commands/memory-doctor/)
620 #[must_use]
621 fn memory_doctor(&mut self) -> PreparedCommand<Self, String>
622 where
623 Self: Sized,
624 {
625 prepare_command(self, cmd("MEMORY").arg("DOCTOR"))
626 }
627
628 /// This command provides an internal statistics report from the memory allocator.
629 ///
630 /// # Return
631 /// the memory allocator's internal statistics report.
632 ///
633 /// # See Also
634 /// [<https://redis.io/commands/memory-malloc-stats/>](https://redis.io/commands/memory-malloc-stats/)
635 #[must_use]
636 fn memory_malloc_stats(&mut self) -> PreparedCommand<Self, String>
637 where
638 Self: Sized,
639 {
640 prepare_command(self, cmd("MEMORY").arg("MALLOC-STATS"))
641 }
642
643 /// This command attempts to purge dirty pages so these can be reclaimed by the allocator.
644 ///
645 /// # See Also
646 /// [<https://redis.io/commands/memory-purge/>](https://redis.io/commands/memory-purge/)
647 #[must_use]
648 fn memory_purge(&mut self) -> PreparedCommand<Self, ()>
649 where
650 Self: Sized,
651 {
652 prepare_command(self, cmd("MEMORY").arg("PURGE"))
653 }
654
655 /// This command returns information about the memory usage of the server.
656 ///
657 /// # Return
658 /// the memory allocator's internal statistics report.
659 ///
660 /// # See Also
661 /// [<https://redis.io/commands/memory-stats/>](https://redis.io/commands/memory-stats/)
662 #[must_use]
663 fn memory_stats(&mut self) -> PreparedCommand<Self, MemoryStats>
664 where
665 Self: Sized,
666 {
667 prepare_command(self, cmd("MEMORY").arg("STATS"))
668 }
669
670 /// This command reports the number of bytes that a key and its value require to be stored in RAM.
671 ///
672 /// # Return
673 /// the memory usage in bytes, or None when the key does not exist.
674 ///
675 /// # See Also
676 /// [<https://redis.io/commands/memory-usage/>](https://redis.io/commands/memory-usage/)
677 #[must_use]
678 fn memory_usage<K>(
679 &mut self,
680 key: K,
681 options: MemoryUsageOptions,
682 ) -> PreparedCommand<Self, Option<usize>>
683 where
684 Self: Sized,
685 K: Into<CommandArg>,
686 {
687 prepare_command(self, cmd("MEMORY").arg("USAGE").arg(key).arg(options))
688 }
689
690 /// Returns information about the modules loaded to the server.
691 ///
692 /// # Return
693 /// list of loaded modules.
694 /// Each element in the list represents a module as an instance of [`ModuleInfo`](crate::ModuleInfo)
695 ///
696 /// # See Also
697 /// [<https://redis.io/commands/module-list/>](https://redis.io/commands/module-list/)
698 #[must_use]
699 fn module_list<MM>(&mut self) -> PreparedCommand<Self, MM>
700 where
701 Self: Sized,
702 MM: FromSingleValueArray<ModuleInfo>,
703 {
704 prepare_command(self, cmd("MODULE").arg("LIST"))
705 }
706
707 /// Loads a module from a dynamic library at runtime.
708 ///
709 /// # See Also
710 /// [<https://redis.io/commands/module-load/>](https://redis.io/commands/module-load/)
711 #[must_use]
712 fn module_load<P>(&mut self, path: P, options: ModuleLoadOptions) -> PreparedCommand<Self, ()>
713 where
714 Self: Sized,
715 P: Into<CommandArg>,
716 {
717 prepare_command(self, cmd("MODULE").arg("LOADEX").arg(path).arg(options))
718 }
719
720 /// Unloads a module.
721 ///
722 /// # See Also
723 /// [<https://redis.io/commands/module-unload/>](https://redis.io/commands/module-unload/)
724 #[must_use]
725 fn module_unload<N>(&mut self, name: N) -> PreparedCommand<Self, ()>
726 where
727 Self: Sized,
728 N: Into<CommandArg>,
729 {
730 prepare_command(self, cmd("MODULE").arg("UNLOAD").arg(name))
731 }
732
733 /// This command can change the replication settings of a replica on the fly.
734 ///
735 /// # See Also
736 /// [<https://redis.io/commands/replicaof/>](https://redis.io/commands/replicaof/)
737 #[must_use]
738 fn replicaof(&mut self, options: ReplicaOfOptions) -> PreparedCommand<Self, ()>
739 where
740 Self: Sized,
741 {
742 prepare_command(self, cmd("REPLICAOF").arg(options))
743 }
744
745 /// Provide information on the role of a Redis instance in the context of replication,
746 /// by returning if the instance is currently a `master`, `slave`, or `sentinel`.
747 ///
748 /// # See Also
749 /// [<https://redis.io/commands/role/>](https://redis.io/commands/role/)
750 #[must_use]
751 fn role(&mut self) -> PreparedCommand<Self, RoleResult>
752 where
753 Self: Sized,
754 {
755 prepare_command(self, cmd("ROLE"))
756 }
757
758 /// This command performs a synchronous save of the dataset producing a point in time snapshot
759 /// of all the data inside the Redis instance, in the form of an RDB file.
760 ///
761 /// # See Also
762 /// [<https://redis.io/commands/save/>](https://redis.io/commands/save/)
763 #[must_use]
764 fn save(&mut self) -> PreparedCommand<Self, ()>
765 where
766 Self: Sized,
767 {
768 prepare_command(self, cmd("SAVE"))
769 }
770
771 /// Shutdown the server
772 ///
773 /// # See Also
774 /// [<https://redis.io/commands/shutdown/>](https://redis.io/commands/shutdown/)
775 #[must_use]
776 fn shutdown(&mut self, options: ShutdownOptions) -> PreparedCommand<Self, ()>
777 where
778 Self: Sized,
779 {
780 prepare_command(self, cmd("SHUTDOWN").arg(options))
781 }
782
783 /// This command returns entries from the slow log in chronological order.
784 ///
785 /// # See Also
786 /// [<https://redis.io/commands/slowlog-get/>](https://redis.io/commands/slowlog-get/)
787 #[must_use]
788 fn slowlog_get(&mut self, options: SlowLogOptions) -> PreparedCommand<Self, Vec<SlowLogEntry>>
789 where
790 Self: Sized,
791 {
792 prepare_command(self, cmd("SLOWLOG").arg("GET").arg(options))
793 }
794
795 /// This command returns the current number of entries in the slow log.
796 ///
797 /// # See Also
798 /// [<https://redis.io/commands/slowlog-len/>](https://redis.io/commands/slowlog-len/)
799 #[must_use]
800 fn slowlog_len(&mut self) -> PreparedCommand<Self, usize>
801 where
802 Self: Sized,
803 {
804 prepare_command(self, cmd("SLOWLOG").arg("LEN"))
805 }
806
807 /// This command resets the slow log, clearing all entries in it.
808 ///
809 /// # See Also
810 /// [<https://redis.io/commands/slowlog-reset/>](https://redis.io/commands/slowlog-reset/)
811 #[must_use]
812 fn slowlog_reset(&mut self) -> PreparedCommand<Self, ()>
813 where
814 Self: Sized,
815 {
816 prepare_command(self, cmd("SLOWLOG").arg("RESET"))
817 }
818
819 /// This command swaps two Redis databases,
820 /// so that immediately all the clients connected to a given database
821 /// will see the data of the other database, and the other way around.
822 ///
823 /// # See Also
824 /// [<https://redis.io/commands/swapdb/>](https://redis.io/commands/swapdb/)
825 #[must_use]
826 fn swapdb(&mut self, index1: usize, index2: usize) -> PreparedCommand<Self, ()>
827 where
828 Self: Sized,
829 {
830 prepare_command(self, cmd("SWAPDB").arg(index1).arg(index2))
831 }
832
833 /// The TIME command returns the current server time as a two items lists:
834 /// a Unix timestamp and the amount of microseconds already elapsed in the current second.
835 ///
836 /// # See Also
837 /// [<https://redis.io/commands/time/>](https://redis.io/commands/time/)
838 #[must_use]
839 fn time(&mut self) -> PreparedCommand<Self, (u32, u32)>
840 where
841 Self: Sized,
842 {
843 prepare_command(self, cmd("TIME"))
844 }
845}
846
847/// Database flushing mode
848pub enum FlushingMode {
849 Default,
850 /// Flushes the database(s) asynchronously
851 Async,
852 /// Flushed the database(s) synchronously
853 Sync,
854}
855
856impl Default for FlushingMode {
857 fn default() -> Self {
858 FlushingMode::Default
859 }
860}
861
862impl IntoArgs for FlushingMode {
863 fn into_args(self, args: CommandArgs) -> CommandArgs {
864 match self {
865 FlushingMode::Default => args,
866 FlushingMode::Async => args.arg("ASYNC"),
867 FlushingMode::Sync => args.arg("SYNC"),
868 }
869 }
870}
871
872/// Options for the [`acl_cat`](crate::ServerCommands::acl_cat) command
873#[derive(Default)]
874pub struct AclCatOptions {
875 command_args: CommandArgs,
876}
877
878impl AclCatOptions {
879 #[must_use]
880 pub fn category_name<C: Into<CommandArg>>(self, category_name: C) -> Self {
881 Self {
882 command_args: self.command_args.arg(category_name),
883 }
884 }
885}
886
887impl IntoArgs for AclCatOptions {
888 fn into_args(self, args: CommandArgs) -> CommandArgs {
889 args.arg(self.command_args)
890 }
891}
892
893/// Options for the [`acl_dryrun`](crate::ServerCommands::acl_dryrun) command
894#[derive(Default)]
895pub struct AclDryRunOptions {
896 command_args: CommandArgs,
897}
898
899impl AclDryRunOptions {
900 #[must_use]
901 pub fn arg<A, AA>(self, args: AA) -> Self
902 where
903 A: Into<CommandArg>,
904 AA: SingleArgOrCollection<A>,
905 {
906 Self {
907 command_args: self.command_args.arg(args),
908 }
909 }
910}
911
912impl IntoArgs for AclDryRunOptions {
913 fn into_args(self, args: CommandArgs) -> CommandArgs {
914 args.arg(self.command_args)
915 }
916}
917
918/// Options for the [`acl_genpass`](crate::ServerCommands::acl_genpass) command
919#[derive(Default)]
920pub struct AclGenPassOptions {
921 command_args: CommandArgs,
922}
923
924impl AclGenPassOptions {
925 /// The command output is a hexadecimal representation of a binary string.
926 /// By default it emits 256 bits (so 64 hex characters).
927 /// The user can provide an argument in form of number of bits to emit from 1 to 1024 to change the output length.
928 /// Note that the number of bits provided is always rounded to the next multiple of 4.
929 /// So for instance asking for just 1 bit password will result in 4 bits to be emitted, in the form of a single hex character.
930 #[must_use]
931 pub fn bits(self, bits: usize) -> Self {
932 Self {
933 command_args: self.command_args.arg(bits),
934 }
935 }
936}
937
938impl IntoArgs for AclGenPassOptions {
939 fn into_args(self, args: CommandArgs) -> CommandArgs {
940 args.arg(self.command_args)
941 }
942}
943
944/// Options for the [`acl_log`](crate::ServerCommands::acl_log) command
945#[derive(Default)]
946pub struct AclLogOptions {
947 command_args: CommandArgs,
948}
949
950impl AclLogOptions {
951 /// This optional argument specifies how many entries to show.
952 /// By default up to ten failures are returned.
953 #[must_use]
954 pub fn count(self, count: usize) -> Self {
955 Self {
956 command_args: self.command_args.arg(count),
957 }
958 }
959
960 /// The special RESET argument clears the log.
961 #[must_use]
962 pub fn reset(self) -> Self {
963 Self {
964 command_args: self.command_args.arg("RESET"),
965 }
966 }
967}
968
969impl IntoArgs for AclLogOptions {
970 fn into_args(self, args: CommandArgs) -> CommandArgs {
971 args.arg(self.command_args)
972 }
973}
974
975/// Command info result for the [`command`](crate::ServerCommands::command) command.
976#[derive(Debug, Clone)]
977pub struct CommandInfo {
978 /// This is the command's name in lowercase.
979 pub name: String,
980 /// Arity is the number of arguments a command expects. It follows a simple pattern:
981 /// - A positive integer means a fixed number of arguments.
982 /// - A negative integer means a minimal number of arguments.
983 pub arity: isize,
984 /// Command flags are an array.
985 /// See [COMMAND documentation](https://redis.io/commands/command/) for the list of flags
986 pub flags: Vec<String>,
987 /// The position of the command's first key name argument.
988 /// For most commands, the first key's position is 1. Position 0 is always the command name itself.
989 pub first_key: usize,
990 /// The position of the command's last key name argument.
991 pub last_key: isize,
992 /// The step, or increment, between the first key and the position of the next key.
993 pub step: usize,
994 /// [From Redis 6.0] This is an array of simple strings that are the ACL categories to which the command belongs.
995 pub acl_categories: Vec<String>,
996 /// [From Redis 7.0] Helpful information about the command. To be used by clients/proxies.
997 /// See [<https://redis.io/docs/reference/command-tips/>](https://redis.io/docs/reference/command-tips/)
998 pub command_tips: Vec<CommandTip>,
999 /// [From Redis 7.0] This is an array consisting of the command's key specifications.
1000 /// See [<https://redis.io/docs/reference/key-specs/>](https://redis.io/docs/reference/key-specs/)
1001 pub key_specifications: Vec<KeySpecification>,
1002 pub sub_commands: Vec<CommandInfo>,
1003}
1004
1005impl FromValue for CommandInfo {
1006 fn from_value(value: Value) -> Result<Self> {
1007 let values: Vec<Value> = value.into()?;
1008 let mut iter = values.into_iter();
1009
1010 match (
1011 iter.next(),
1012 iter.next(),
1013 iter.next(),
1014 iter.next(),
1015 iter.next(),
1016 iter.next(),
1017 iter.next(),
1018 iter.next(),
1019 iter.next(),
1020 iter.next(),
1021 ) {
1022 (
1023 Some(name),
1024 Some(arity),
1025 Some(flags),
1026 Some(first_key),
1027 Some(last_key),
1028 Some(step),
1029 Some(acl_categories),
1030 Some(command_tips),
1031 Some(key_specifications),
1032 Some(sub_commands),
1033 ) => Ok(Self {
1034 name: name.into()?,
1035 arity: arity.into()?,
1036 flags: flags.into()?,
1037 first_key: first_key.into()?,
1038 last_key: last_key.into()?,
1039 step: step.into()?,
1040 acl_categories: acl_categories.into()?,
1041 command_tips: command_tips.into()?,
1042 key_specifications: key_specifications.into()?,
1043 sub_commands: sub_commands.into()?,
1044 }),
1045 (
1046 Some(name),
1047 Some(arity),
1048 Some(flags),
1049 Some(first_key),
1050 Some(last_key),
1051 Some(step),
1052 Some(acl_categories),
1053 None,
1054 None,
1055 None,
1056 ) => Ok(Self {
1057 name: name.into()?,
1058 arity: arity.into()?,
1059 flags: flags.into()?,
1060 first_key: first_key.into()?,
1061 last_key: last_key.into()?,
1062 step: step.into()?,
1063 acl_categories: acl_categories.into()?,
1064 command_tips: Vec::new(),
1065 key_specifications: Vec::new(),
1066 sub_commands: Vec::new(),
1067 }),
1068 (
1069 Some(name),
1070 Some(arity),
1071 Some(flags),
1072 Some(first_key),
1073 Some(last_key),
1074 Some(step),
1075 None,
1076 None,
1077 None,
1078 None,
1079 ) => Ok(Self {
1080 name: name.into()?,
1081 arity: arity.into()?,
1082 flags: flags.into()?,
1083 first_key: first_key.into()?,
1084 last_key: last_key.into()?,
1085 step: step.into()?,
1086 acl_categories: Vec::new(),
1087 command_tips: Vec::new(),
1088 key_specifications: Vec::new(),
1089 sub_commands: Vec::new(),
1090 }),
1091 _ => Err(Error::Client(
1092 "Cannot parse CommandInfo from result".to_owned(),
1093 )),
1094 }
1095
1096 //let (name, arity, flags, first_key, last_key, step, acl_categories, command_tips, key_specifications, sub_commands)
1097 }
1098}
1099
1100/// Get additional information about a command
1101///
1102/// See <https://redis.io/docs/reference/command-tips/>
1103#[derive(Debug, Clone)]
1104pub enum CommandTip {
1105 NonDeterministricOutput,
1106 NonDeterministricOutputOrder,
1107 RequestPolicy(RequestPolicy),
1108 ResponsePolicy(ResponsePolicy),
1109}
1110
1111impl FromValue for CommandTip {
1112 fn from_value(value: Value) -> Result<Self> {
1113 let tip: String = value.into()?;
1114 match tip.as_str() {
1115 "nondeterministic_output" => Ok(CommandTip::NonDeterministricOutput),
1116 "nondeterministic_output_order" => Ok(CommandTip::NonDeterministricOutputOrder),
1117 _ => {
1118 let mut parts = tip.split(':');
1119 match (parts.next(), parts.next(), parts.next()) {
1120 (Some("request_policy"), Some(policy), None) => {
1121 Ok(CommandTip::RequestPolicy(RequestPolicy::from_str(policy)?))
1122 }
1123 (Some("response_policy"), Some(policy), None) => Ok(
1124 CommandTip::ResponsePolicy(ResponsePolicy::from_str(policy)?),
1125 ),
1126 _ => Err(Error::Client(
1127 "Cannot parse CommandTip from result".to_owned(),
1128 )),
1129 }
1130 }
1131 }
1132 }
1133}
1134
1135/// This tip can help clients determine the shards to send the command in clustering mode.
1136///
1137/// The default behavior a client should implement for commands without the request_policy tip is as follows:
1138/// 1. The command doesn't accept key name arguments: the client can execute the command on an arbitrary shard.
1139/// 2. For commands that accept one or more key name arguments: the client should route the command to a single shard,
1140/// as determined by the hash slot of the input keys.
1141#[derive(Debug, Clone)]
1142pub enum RequestPolicy {
1143 /// the client should execute the command on all nodes - masters and replicas alike.
1144 ///
1145 /// An example is the [`config_set`](crate::ServerCommands::config_set) command.
1146 /// This tip is in-use by commands that don't accept key name arguments. The command operates atomically per shard.
1147 AllNodes,
1148 /// the client should execute the command on all master shards (e.g., the [`dbsize`](crate::ServerCommands::dbsize) command).
1149 ///
1150 /// This tip is in-use by commands that don't accept key name arguments. The command operates atomically per shard.
1151 AllShards,
1152 /// the client should execute the command on several shards.
1153 ///
1154 /// The shards that execute the command are determined by the hash slots of its input key name arguments.
1155 /// Examples for such commands include [`mset`](crate::StringCommands::mset), [`mget`](crate::StringCommands::mget)
1156 /// and [`del`](crate::GenericCommands::del).
1157 /// However, note that [`sunionstore`](crate::SetCommands::sunionstore) isn't considered
1158 /// as multi_shard because all of its keys must belong to the same hash slot.
1159 MultiShard,
1160 /// indicates a non-trivial form of the client's request policy, such as the [`scan`](crate::GenericCommands::scan) command.
1161 Special,
1162}
1163
1164impl FromStr for RequestPolicy {
1165 type Err = Error;
1166
1167 fn from_str(str: &str) -> Result<Self> {
1168 match str {
1169 "all_nodes" => Ok(RequestPolicy::AllNodes),
1170 "all_shards" => Ok(RequestPolicy::AllShards),
1171 "multi_shard" => Ok(RequestPolicy::MultiShard),
1172 "special" => Ok(RequestPolicy::Special),
1173 _ => Err(Error::Client(
1174 "Cannot parse RequestPolicy from result".to_owned(),
1175 )),
1176 }
1177 }
1178}
1179
1180/// This tip can help clients determine the aggregate they need to compute from the replies of multiple shards in a cluster.
1181///
1182/// The default behavior for commands without a request_policy tip only applies to replies with of nested types
1183/// (i.e., an array, a set, or a map).
1184/// The client's implementation for the default behavior should be as follows:
1185/// 1. The command doesn't accept key name arguments: the client can aggregate all replies within a single nested data structure.
1186/// For example, the array replies we get from calling [`keys`](crate::GenericCommands::keys) against all shards.
1187/// These should be packed in a single in no particular order.
1188/// 2. For commands that accept one or more key name arguments: the client needs to retain the same order of replies as the input key names.
1189/// For example, [`mget`](crate::StringCommands::mget)'s aggregated reply.
1190#[derive(Debug, Clone)]
1191pub enum ResponsePolicy {
1192 /// the clients should return success if at least one shard didn't reply with an error.
1193 ///
1194 /// The client should reply with the first non-error reply it obtains.
1195 /// If all shards return an error, the client can reply with any one of these.
1196 /// For example, consider a [`script_kill`](crate::ScriptingCommands::script_kill) command that's sent to all shards.
1197 /// Although the script should be loaded in all of the cluster's shards,
1198 /// the [`script_kill`](crate::ScriptingCommands::script_kill) will typically run only on one at a given time.
1199 OneSucceeded,
1200 /// the client should return successfully only if there are no error replies.
1201 ///
1202 /// Even a single error reply should disqualify the aggregate and be returned.
1203 /// Otherwise, the client should return one of the non-error replies.
1204 /// As an example, consider the [`config_set`](crate::ServerCommands::config_set),
1205 /// [`script_flush`](crate::ScriptingCommands::script_flush) and
1206 /// [`script_load`](crate::ScriptingCommands::script_load) commands.
1207 AllSucceeded,
1208 /// the client should return the result of a logical `AND` operation on all replies
1209 /// (only applies to integer replies, usually from commands that return either 0 or 1).
1210 ///
1211 /// Consider the [`script_exists`](crate::ScriptingCommands::script_exists) command as an example.
1212 /// It returns an array of 0's and 1's that denote the existence of its given SHA1 sums in the script cache.
1213 /// The aggregated response should be 1 only when all shards had reported that a given script SHA1 sum is in their respective cache.
1214 AggLogicalAnd,
1215 /// the client should return the result of a logical `OR` operation on all replies
1216 /// (only applies to integer replies, usually from commands that return either 0 or 1).
1217 AggLogicalOr,
1218 /// the client should return the minimal value from the replies (only applies to numerical replies).
1219 ///
1220 /// The aggregate reply from a cluster-wide [`wait`](crate::GenericCommands::wait) command, for example,
1221 /// should be the minimal value (number of synchronized replicas) from all shards
1222 AggMin,
1223 /// the client should return the maximal value from the replies (only applies to numerical replies).
1224 AggMax,
1225 /// the client should return the sum of replies (only applies to numerical replies).
1226 ///
1227 /// Example: [`dbsize`](crate::ServerCommands::dbsize).
1228 AggSum,
1229 /// this type of tip indicates a non-trivial form of reply policy.
1230 ///
1231 /// [`info`](crate::ServerCommands::info) is an excellent example of that.
1232 Special,
1233}
1234
1235impl FromStr for ResponsePolicy {
1236 type Err = Error;
1237
1238 fn from_str(str: &str) -> Result<Self> {
1239 match str {
1240 "one_succeeded" => Ok(ResponsePolicy::OneSucceeded),
1241 "all_succeeded" => Ok(ResponsePolicy::AllSucceeded),
1242 "agg_logical_and" => Ok(ResponsePolicy::AggLogicalAnd),
1243 "agg_logical_or" => Ok(ResponsePolicy::AggLogicalOr),
1244 "agg_min" => Ok(ResponsePolicy::AggMin),
1245 "agg_max" => Ok(ResponsePolicy::AggMax),
1246 "agg_sum" => Ok(ResponsePolicy::AggSum),
1247 "special" => Ok(ResponsePolicy::Special),
1248 _ => Err(Error::Client(
1249 "Cannot parse ResponsePolicy from result".to_owned(),
1250 )),
1251 }
1252 }
1253}
1254
1255/// Key specifications of a command for the [`command`](crate::ServerCommands::command) command.
1256#[derive(Debug, Clone)]
1257pub struct KeySpecification {
1258 pub begin_search: BeginSearch,
1259 pub find_keys: FindKeys,
1260 pub flags: Vec<String>,
1261 pub notes: String,
1262}
1263
1264impl FromValue for KeySpecification {
1265 fn from_value(value: Value) -> Result<Self> {
1266 let mut values: HashMap<String, Value> = value.into()?;
1267
1268 let notes: String = match values.remove("notes") {
1269 Some(notes) => notes.into()?,
1270 None => "".to_owned(),
1271 };
1272
1273 Ok(Self {
1274 begin_search: values.remove_with_result("begin_search")?.into()?,
1275 find_keys: values.remove_with_result("find_keys")?.into()?,
1276 flags: values.remove_with_result("flags")?.into()?,
1277 notes,
1278 })
1279 }
1280}
1281
1282#[derive(Debug, Clone)]
1283pub enum BeginSearch {
1284 Index(usize),
1285 Keyword { keyword: String, start_from: isize },
1286 Unknown,
1287}
1288
1289impl FromValue for BeginSearch {
1290 fn from_value(value: Value) -> Result<Self> {
1291 let mut values: HashMap<String, Value> = value.into()?;
1292
1293 let type_: String = values.remove_with_result("type")?.into()?;
1294 match type_.as_str() {
1295 "index" => {
1296 let mut spec: HashMap<String, Value> = values.remove_with_result("spec")?.into()?;
1297 Ok(BeginSearch::Index(
1298 spec.remove_with_result("index")?.into()?,
1299 ))
1300 }
1301 "keyword" => {
1302 let mut spec: HashMap<String, Value> = values.remove_with_result("spec")?.into()?;
1303 Ok(BeginSearch::Keyword {
1304 keyword: spec.remove_with_result("keyword")?.into()?,
1305 start_from: spec.remove_with_result("startfrom")?.into()?,
1306 })
1307 }
1308 "unknown" => Ok(BeginSearch::Unknown),
1309 _ => Err(Error::Client(
1310 "Cannot parse BeginSearch from result".to_owned(),
1311 )),
1312 }
1313 }
1314}
1315
1316#[derive(Debug, Clone)]
1317pub enum FindKeys {
1318 Range {
1319 last_key: isize,
1320 key_step: usize,
1321 limit: usize,
1322 },
1323 KeyEnum {
1324 key_num_idx: usize,
1325 first_key: usize,
1326 key_step: usize,
1327 },
1328 Unknown,
1329}
1330
1331impl FromValue for FindKeys {
1332 fn from_value(value: Value) -> Result<Self> {
1333 let mut values: HashMap<String, Value> = value.into()?;
1334
1335 let type_: String = values.remove_with_result("type")?.into()?;
1336 match type_.as_str() {
1337 "range" => {
1338 let mut spec: HashMap<String, Value> = values.remove_with_result("spec")?.into()?;
1339 Ok(FindKeys::Range {
1340 last_key: spec.remove_with_result("lastkey")?.into()?,
1341 key_step: spec.remove_with_result("keystep")?.into()?,
1342 limit: spec.remove_with_result("limit")?.into()?,
1343 })
1344 }
1345 "keynum" => {
1346 let mut spec: HashMap<String, Value> = values.remove_with_result("spec")?.into()?;
1347 Ok(FindKeys::KeyEnum {
1348 key_num_idx: spec.remove_with_result("keynumidx")?.into()?,
1349 first_key: spec.remove_with_result("firstkey")?.into()?,
1350 key_step: spec.remove_with_result("keystep")?.into()?,
1351 })
1352 }
1353 "unknown" => Ok(FindKeys::Unknown),
1354 _ => Err(Error::Client(
1355 "Cannot parse BeginSearch from result".to_owned(),
1356 )),
1357 }
1358 }
1359}
1360
1361/// Command doc result for the [`command_docs`](crate::ServerCommands::command_docs) command
1362#[derive(Debug, Default)]
1363pub struct CommandDoc {
1364 /// short command description.
1365 pub summary: String,
1366 /// the Redis version that added the command (or for module commands, the module version).
1367 pub since: String,
1368 /// he functional group to which the command belongs.
1369 pub group: String,
1370 /// a short explanation about the command's time complexity.
1371 pub complexity: String,
1372 /// an array of documentation flags. Possible values are:
1373 /// - `deprecated`: the command is deprecated.
1374 /// - `syscmd`: a system command that isn't meant to be called by users.
1375 pub doc_flags: Vec<CommandDocFlag>,
1376 /// the Redis version that deprecated the command (or for module commands, the module version).
1377 pub deprecated_since: String,
1378 /// the alternative for a deprecated command.
1379 pub replaced_by: String,
1380 /// an array of historical notes describing changes to the command's behavior or arguments.
1381 pub history: Vec<HistoricalNote>,
1382 /// an array of [`command arguments`](https://redis.io/docs/reference/command-arguments/)
1383 pub arguments: Vec<CommandArgument>,
1384}
1385
1386impl FromValue for CommandDoc {
1387 fn from_value(value: Value) -> Result<Self> {
1388 let mut values: HashMap<String, Value> = value.into()?;
1389
1390 Ok(Self {
1391 summary: values.remove_with_result("summary")?.into()?,
1392 since: values.remove_with_result("since")?.into()?,
1393 group: values.remove_with_result("group")?.into()?,
1394 complexity: values.remove_with_result("complexity")?.into()?,
1395 doc_flags: values.remove_or_default("doc_flags").into()?,
1396 deprecated_since: values.remove_or_default("deprecated_since").into()?,
1397 replaced_by: values.remove_or_default("replaced_by").into()?,
1398 history: values.remove_or_default("history").into()?,
1399 arguments: values.remove_with_result("arguments")?.into()?,
1400 })
1401 }
1402}
1403
1404/// Command documenation flag
1405#[derive(Debug)]
1406pub enum CommandDocFlag {
1407 /// the command is deprecated.
1408 Deprecated,
1409 /// a system command that isn't meant to be called by users.
1410 SystemCommand,
1411}
1412
1413impl FromValue for CommandDocFlag {
1414 fn from_value(value: Value) -> Result<Self> {
1415 let f: String = value.into()?;
1416
1417 match f.as_str() {
1418 "deprecated" => Ok(CommandDocFlag::Deprecated),
1419 "syscmd" => Ok(CommandDocFlag::SystemCommand),
1420 _ => Err(Error::Client(
1421 "Cannot parse CommandDocFlag from result".to_owned(),
1422 )),
1423 }
1424 }
1425}
1426
1427#[derive(Debug)]
1428pub struct HistoricalNote {
1429 pub version: String,
1430 pub description: String,
1431}
1432
1433impl FromValue for HistoricalNote {
1434 fn from_value(value: Value) -> Result<Self> {
1435 let (version, description): (String, String) = value.into()?;
1436
1437 Ok(Self {
1438 version,
1439 description,
1440 })
1441 }
1442}
1443
1444/// [`command argument`](https://redis.io/docs/reference/command-arguments/)
1445#[derive(Debug)]
1446pub struct CommandArgument {
1447 /// the argument's name, always present.
1448 pub name: String,
1449 /// the argument's display string, present in arguments that have a displayable representation
1450 pub display_text: String,
1451 /// the argument's type, always present.
1452 pub type_: CommandArgumentType,
1453 /// this value is available for every argument of the `key` type.
1454 /// t is a 0-based index of the specification in the command's [`key specifications`](https://redis.io/topics/key-specs)
1455 /// that corresponds to the argument.
1456 pub key_spec_index: usize,
1457 /// a constant literal that precedes the argument (user input) itself.
1458 pub token: String,
1459 /// a short description of the argument.
1460 pub summary: String,
1461 /// the debut Redis version of the argument (or for module commands, the module version).
1462 pub since: String,
1463 /// the Redis version that deprecated the command (or for module commands, the module version).
1464 pub deprecated_since: String,
1465 /// an array of argument flags.
1466 pub flags: Vec<ArgumentFlag>,
1467 /// the argument's value.
1468 pub value: Vec<String>,
1469}
1470
1471impl FromValue for CommandArgument {
1472 fn from_value(value: Value) -> Result<Self> {
1473 let mut values: HashMap<String, Value> = value.into()?;
1474
1475 Ok(Self {
1476 name: values.remove_with_result("name")?.into()?,
1477 display_text: values.remove_or_default("display_text").into()?,
1478 type_: values.remove_with_result("type")?.into()?,
1479 key_spec_index: values.remove_or_default("key_spec_index").into()?,
1480 token: values.remove_or_default("token").into()?,
1481 summary: values.remove_or_default("summary").into()?,
1482 since: values.remove_or_default("since").into()?,
1483 deprecated_since: values.remove_or_default("deprecated_since").into()?,
1484 flags: values.remove_or_default("flags").into()?,
1485 value: match values.remove_or_default("value") {
1486 value @ Value::BulkString(_) => vec![value.into()?],
1487 value @ Value::Array(_) => value.into()?,
1488 _ => {
1489 return Err(Error::Client(
1490 "Cannot parse CommandArgument from result".to_owned(),
1491 ))
1492 }
1493 },
1494 })
1495 }
1496}
1497
1498/// An argument must have one of the following types:
1499#[derive(Debug)]
1500pub enum CommandArgumentType {
1501 /// a string argument.
1502 String,
1503 /// an integer argument.
1504 Integer,
1505 /// a double-precision argument.
1506 Double,
1507 /// a string that represents the name of a key.
1508 Key,
1509 /// a string that represents a glob-like pattern.
1510 Pattern,
1511 /// an integer that represents a Unix timestamp.
1512 UnixTime,
1513 /// a token, i.e. a reserved keyword, which may or may not be provided.
1514 /// Not to be confused with free-text user input.
1515 PureToken,
1516 /// the argument is a container for nested arguments.
1517 /// This type enables choice among several nested arguments
1518 OneOf,
1519 /// the argument is a container for nested arguments.
1520 /// This type enables grouping arguments and applying a property (such as optional) to all
1521 Block,
1522}
1523
1524impl FromValue for CommandArgumentType {
1525 fn from_value(value: Value) -> Result<Self> {
1526 let t: String = value.into()?;
1527
1528 match t.as_str() {
1529 "string" => Ok(CommandArgumentType::String),
1530 "integer" => Ok(CommandArgumentType::Integer),
1531 "double" => Ok(CommandArgumentType::Double),
1532 "key" => Ok(CommandArgumentType::Key),
1533 "pattern" => Ok(CommandArgumentType::Pattern),
1534 "unix-time" => Ok(CommandArgumentType::UnixTime),
1535 "pure-token" => Ok(CommandArgumentType::PureToken),
1536 "oneof" => Ok(CommandArgumentType::OneOf),
1537 "block" => Ok(CommandArgumentType::Block),
1538 _ => Err(Error::Client(
1539 "Cannot parse CommandArgumentType from result".to_owned(),
1540 )),
1541 }
1542 }
1543}
1544
1545/// Flag for a command argument
1546#[derive(Debug)]
1547pub enum ArgumentFlag {
1548 /// denotes that the argument is optional (for example, the GET clause of the SET command).
1549 Optional,
1550 /// denotes that the argument may be repeated (such as the key argument of DEL).
1551 Multiple,
1552 /// denotes the possible repetition of the argument with its preceding token (see SORT's GET pattern clause).
1553 MultipleToken,
1554}
1555
1556impl FromValue for ArgumentFlag {
1557 fn from_value(value: Value) -> Result<Self> {
1558 let f: String = value.into()?;
1559
1560 match f.as_str() {
1561 "optional" => Ok(ArgumentFlag::Optional),
1562 "multiple" => Ok(ArgumentFlag::Multiple),
1563 "multiple-token" => Ok(ArgumentFlag::MultipleToken),
1564 _ => Err(Error::Client(
1565 "Cannot parse ArgumentFlag from result".to_owned(),
1566 )),
1567 }
1568 }
1569}
1570
1571/// Options for the [`command_list`](crate::ServerCommands::command_list) command.
1572#[derive(Default)]
1573pub struct CommandListOptions {
1574 command_args: CommandArgs,
1575}
1576
1577impl CommandListOptions {
1578 /// get the commands that belong to the module specified by `module-name`.
1579 #[must_use]
1580 pub fn filter_by_module_name<M: Into<CommandArg>>(self, module_name: M) -> Self {
1581 Self {
1582 command_args: self
1583 .command_args
1584 .arg("FILTERBY")
1585 .arg("MODULE")
1586 .arg(module_name),
1587 }
1588 }
1589
1590 /// get the commands in the [`ACL category`](https://redis.io/docs/manual/security/acl/#command-categories) specified by `category`.
1591 #[must_use]
1592 pub fn filter_by_acl_category<C: Into<CommandArg>>(self, category: C) -> Self {
1593 Self {
1594 command_args: self
1595 .command_args
1596 .arg("FILTERBY")
1597 .arg("ACLCAT")
1598 .arg(category),
1599 }
1600 }
1601
1602 /// get the commands that match the given glob-like `pattern`.
1603 #[must_use]
1604 pub fn filter_by_pattern<P: Into<CommandArg>>(self, pattern: P) -> Self {
1605 Self {
1606 command_args: self
1607 .command_args
1608 .arg("FILTERBY")
1609 .arg("PATTERN")
1610 .arg(pattern),
1611 }
1612 }
1613}
1614
1615impl IntoArgs for CommandListOptions {
1616 fn into_args(self, args: CommandArgs) -> CommandArgs {
1617 args.arg(self.command_args)
1618 }
1619}
1620
1621/// Options for the [`failover`](crate::ServerCommands::failover) command.
1622#[derive(Default)]
1623pub struct FailOverOptions {
1624 command_args: CommandArgs,
1625}
1626
1627impl FailOverOptions {
1628 /// This option allows designating a specific replica, by its host and port, to failover to.
1629 #[must_use]
1630 pub fn to<H: Into<CommandArg>>(self, host: H, port: u16) -> Self {
1631 Self {
1632 command_args: self.command_args.arg("TO").arg(host).arg(port),
1633 }
1634 }
1635
1636 /// This option allows specifying a maximum time a master will wait in the waiting-for-sync state
1637 /// before aborting the failover attempt and rolling back.
1638 #[must_use]
1639 pub fn timeout(self, milliseconds: u64) -> Self {
1640 Self {
1641 command_args: self.command_args.arg("TIMEOUT").arg(milliseconds),
1642 }
1643 }
1644
1645 /// If both the [`timeout`](crate::FailOverOptions::timeout) and [`to`](crate::FailOverOptions::to) options are set,
1646 /// the force flag can also be used to designate that that once the timeout has elapsed,
1647 /// the master should failover to the target replica instead of rolling back.
1648 #[must_use]
1649 pub fn force(self) -> Self {
1650 Self {
1651 command_args: self.command_args.arg("FORCE"),
1652 }
1653 }
1654
1655 /// This command will abort an ongoing failover and return the master to its normal state.
1656 #[must_use]
1657 pub fn abort(self) -> Self {
1658 Self {
1659 command_args: self.command_args.arg("ABORT"),
1660 }
1661 }
1662}
1663
1664impl IntoArgs for FailOverOptions {
1665 fn into_args(self, args: CommandArgs) -> CommandArgs {
1666 args.arg(self.command_args)
1667 }
1668}
1669
1670/// Section for the [`info`](crate::ServerCommands::info) command.
1671pub enum InfoSection {
1672 Server,
1673 Clients,
1674 Memory,
1675 Persistence,
1676 Stats,
1677 Replication,
1678 Cpu,
1679 Commandstats,
1680 Latencystats,
1681 Cluster,
1682 Keyspace,
1683 Modules,
1684 Errorstats,
1685 All,
1686 Default,
1687 Everything,
1688}
1689
1690impl From<InfoSection> for CommandArg {
1691 fn from(s: InfoSection) -> Self {
1692 match s {
1693 InfoSection::Server => CommandArg::Str("server"),
1694 InfoSection::Clients => CommandArg::Str("clients"),
1695 InfoSection::Memory => CommandArg::Str("memory"),
1696 InfoSection::Persistence => CommandArg::Str("persistence"),
1697 InfoSection::Stats => CommandArg::Str("stats"),
1698 InfoSection::Replication => CommandArg::Str("replication"),
1699 InfoSection::Cpu => CommandArg::Str("cpu"),
1700 InfoSection::Commandstats => CommandArg::Str("commandstats"),
1701 InfoSection::Latencystats => CommandArg::Str("latencystats"),
1702 InfoSection::Cluster => CommandArg::Str("cluster"),
1703 InfoSection::Keyspace => CommandArg::Str("keyspace"),
1704 InfoSection::Modules => CommandArg::Str("modules"),
1705 InfoSection::Errorstats => CommandArg::Str("errorstats"),
1706 InfoSection::All => CommandArg::Str("all"),
1707 InfoSection::Default => CommandArg::Str("default"),
1708 InfoSection::Everything => CommandArg::Str("everything"),
1709 }
1710 }
1711}
1712
1713/// Latency history event for the [`latency_graph`](crate::ServerCommands::latency_graph)
1714/// & [`latency_history`](crate::ServerCommands::latency_history) commands.
1715pub enum LatencyHistoryEvent {
1716 ActiveDefragCycle,
1717 AofFsyncAlways,
1718 AofStat,
1719 AofRewriteDiffWrite,
1720 AofRename,
1721 AofWrite,
1722 AofWriteActiveChild,
1723 AofWriteAlone,
1724 AofWritePendingFsync,
1725 Command,
1726 ExpireCycle,
1727 EvictionCycle,
1728 EvictionDel,
1729 FastCommand,
1730 Fork,
1731 RdbUnlinkTempFile,
1732}
1733
1734impl From<LatencyHistoryEvent> for CommandArg {
1735 fn from(e: LatencyHistoryEvent) -> Self {
1736 match e {
1737 LatencyHistoryEvent::ActiveDefragCycle => "active-defrag-cycle".into(),
1738 LatencyHistoryEvent::AofFsyncAlways => "aof-fsync-always".into(),
1739 LatencyHistoryEvent::AofStat => "aof-stat".into(),
1740 LatencyHistoryEvent::AofRewriteDiffWrite => "aof-rewrite-diff-write".into(),
1741 LatencyHistoryEvent::AofRename => "aof-rename".into(),
1742 LatencyHistoryEvent::AofWrite => "aof-write".into(),
1743 LatencyHistoryEvent::AofWriteActiveChild => "aof-write-active-child".into(),
1744 LatencyHistoryEvent::AofWriteAlone => "aof-write-alone".into(),
1745 LatencyHistoryEvent::AofWritePendingFsync => "aof-write-pending-fsync".into(),
1746 LatencyHistoryEvent::Command => "command".into(),
1747 LatencyHistoryEvent::ExpireCycle => "expire-cycle".into(),
1748 LatencyHistoryEvent::EvictionCycle => "eviction-cycle".into(),
1749 LatencyHistoryEvent::EvictionDel => "eviction-del".into(),
1750 LatencyHistoryEvent::FastCommand => "fast-command".into(),
1751 LatencyHistoryEvent::Fork => "fork".into(),
1752 LatencyHistoryEvent::RdbUnlinkTempFile => "rdb-unlink-temp-file".into(),
1753 }
1754 }
1755}
1756
1757/// Command Histogram for the [`latency_histogram`](crate::ServerCommands::latency_histogram) commands.
1758#[derive(Default)]
1759pub struct CommandHistogram {
1760 /// The total calls for that command.
1761 pub calls: usize,
1762
1763 /// A map of time buckets:
1764 /// - Each bucket represents a latency range.
1765 /// - Each bucket covers twice the previous bucket's range.
1766 /// - Empty buckets are not printed.
1767 /// - The tracked latencies are between 1 microsecond and roughly 1 second.
1768 /// - Everything above 1 sec is considered +Inf.
1769 /// - At max there will be log2(1000000000)=30 buckets.
1770 pub histogram_usec: HashMap<u32, u32>,
1771}
1772
1773impl FromValue for CommandHistogram {
1774 fn from_value(value: Value) -> Result<Self> {
1775 let mut values: HashMap<String, Value> = value.into()?;
1776
1777 Ok(Self {
1778 calls: values.remove_with_result("calls")?.into()?,
1779 histogram_usec: values.remove_with_result("histogram_usec")?.into()?,
1780 })
1781 }
1782}
1783
1784/// Options for the [`lolwut`](crate::ServerCommands::lolwut) command
1785#[derive(Default)]
1786pub struct LolWutOptions {
1787 command_args: CommandArgs,
1788}
1789
1790impl LolWutOptions {
1791 #[must_use]
1792 pub fn version(self, version: usize) -> Self {
1793 Self {
1794 command_args: self.command_args.arg("VERSION").arg(version),
1795 }
1796 }
1797
1798 #[must_use]
1799 pub fn optional_arg<A: Into<CommandArg>>(self, arg: A) -> Self {
1800 Self {
1801 command_args: self.command_args.arg(arg),
1802 }
1803 }
1804}
1805
1806impl IntoArgs for LolWutOptions {
1807 fn into_args(self, args: CommandArgs) -> CommandArgs {
1808 args.arg(self.command_args)
1809 }
1810}
1811
1812/// Result for the [`memory_stats`](crate::ServerCommands::memory_stats) command.
1813#[derive(Debug)]
1814pub struct MemoryStats {
1815 /// Peak memory consumed by Redis in bytes
1816 /// (see [`INFO`](https://redis.io/commands/info)'s used_memory_peak)
1817 pub peak_allocated: usize,
1818
1819 /// Total number of bytes allocated by Redis using its allocator
1820 /// (see [`INFO`](https://redis.io/commands/info)'s used_memory)
1821 pub total_allocated: usize,
1822
1823 /// Initial amount of memory consumed by Redis at startup in bytes
1824 /// (see [`INFO`](https://redis.io/commands/info)'s used_memory_startup)
1825 pub startup_allocated: usize,
1826
1827 /// Size in bytes of the replication backlog
1828 /// (see [`INFO`](https://redis.io/commands/info)'s repl_backlog_active)
1829 pub replication_backlog: usize,
1830
1831 /// The total size in bytes of all replicas overheads
1832 /// (output and query buffers, connection contexts)
1833 pub clients_slaves: usize,
1834
1835 /// The total size in bytes of all clients overheads
1836 /// (output and query buffers, connection contexts)
1837 pub clients_normal: usize,
1838
1839 /// Memory usage by cluster links
1840 /// (Added in Redis 7.0, see [`INFO`](https://redis.io/commands/info)'s mem_cluster_links).
1841 pub cluster_links: usize,
1842
1843 /// The summed size in bytes of AOF related buffers.
1844 pub aof_buffer: usize,
1845
1846 /// the summed size in bytes of the overheads of the Lua scripts' caches
1847 pub lua_caches: usize,
1848
1849 /// the summed size in bytes of the overheads of the functions' caches
1850 pub functions_caches: usize,
1851
1852 /// For each of the server's databases (key = db index),
1853 /// the overheads of the main and expiry dictionaries are reported in bytes
1854 pub databases: HashMap<usize, DatabaseOverhead>,
1855
1856 /// The sum of all overheads, i.e. `startup.allocated`, `replication.backlog`,
1857 /// `clients.slaves`, `clients.normal`, `aof.buffer` and those of the internal data structures
1858 /// that are used in managing the Redis keyspace (see [`INFO`](https://redis.io/commands/info)'s used_memory_overhead)
1859 pub overhead_total: usize,
1860
1861 /// The total number of keys stored across all databases in the server
1862 pub keys_count: usize,
1863
1864 /// The ratio between net memory usage (`total.allocated` minus `startup.allocated`) and `keys.count`
1865 pub keys_bytes_per_key: usize,
1866
1867 /// The size in bytes of the dataset, i.e. `overhead.total` subtracted from `total.allocated`
1868 /// (see [`INFO`](https://redis.io/commands/info)'s used_memory_dataset)
1869 pub dataset_bytes: usize,
1870
1871 /// The percentage of `dataset.bytes` out of the net memory usage
1872 pub dataset_percentage: f64,
1873
1874 /// The percentage of `peak.allocated` out of `total.allocated`
1875 pub peak_percentage: f64,
1876
1877 pub allocator_allocated: usize,
1878
1879 pub allocator_active: usize,
1880
1881 pub allocator_resident: usize,
1882
1883 pub allocator_fragmentation_ratio: f64,
1884
1885 pub allocator_fragmentation_bytes: usize,
1886
1887 pub allocator_rss_ratio: f64,
1888
1889 pub allocator_rss_bytes: usize,
1890
1891 pub rss_overhead_ratio: f64,
1892
1893 pub rss_overhead_bytes: usize,
1894
1895 /// See [`INFO`](https://redis.io/commands/info)'s mem_fragmentation_ratio
1896 pub fragmentation: f64,
1897
1898 pub fragmentation_bytes: usize,
1899
1900 pub additional_stats: HashMap<String, Value>,
1901}
1902
1903impl FromValue for MemoryStats {
1904 fn from_value(value: Value) -> Result<Self> {
1905 let mut values: HashMap<String, Value> = value.into()?;
1906
1907 Ok(Self {
1908 peak_allocated: values.remove_or_default("peak.allocated").into()?,
1909 total_allocated: values.remove_or_default("total.allocated").into()?,
1910 startup_allocated: values.remove_or_default("startup.allocated").into()?,
1911 replication_backlog: values.remove_or_default("replication.backlog").into()?,
1912 clients_slaves: values.remove_or_default("clients.slaves").into()?,
1913 clients_normal: values.remove_or_default("clients.normal").into()?,
1914 cluster_links: values.remove_or_default("cluster.links").into()?,
1915 aof_buffer: values.remove_or_default("aof.buffer").into()?,
1916 lua_caches: values.remove_or_default("lua.caches").into()?,
1917 functions_caches: values.remove_or_default("functions.caches").into()?,
1918 databases: (0..16)
1919 .into_iter()
1920 .filter_map(|i| {
1921 values
1922 .remove(&format!("db.{i}"))
1923 .map(|v| DatabaseOverhead::from_value(v).map(|o| (i, o)))
1924 })
1925 .collect::<Result<HashMap<usize, DatabaseOverhead>>>()?,
1926 overhead_total: values.remove_or_default("overhead.total").into()?,
1927 keys_count: values.remove_or_default("keys.count").into()?,
1928 keys_bytes_per_key: values.remove_or_default("keys.bytes-per-key").into()?,
1929 dataset_bytes: values.remove_or_default("dataset.bytes").into()?,
1930 dataset_percentage: values.remove_or_default("dataset.percentage").into()?,
1931 peak_percentage: values.remove_or_default("peak.percentage").into()?,
1932 allocator_allocated: values.remove_or_default("allocator.allocated").into()?,
1933 allocator_active: values.remove_or_default("allocator.active").into()?,
1934 allocator_resident: values.remove_or_default("allocator.resident").into()?,
1935 allocator_fragmentation_ratio: values
1936 .remove_or_default("allocator-fragmentation.ratio")
1937 .into()?,
1938 allocator_fragmentation_bytes: values
1939 .remove_or_default("allocator-fragmentation.bytes")
1940 .into()?,
1941 allocator_rss_ratio: values.remove_or_default("allocator-rss.ratio").into()?,
1942 allocator_rss_bytes: values.remove_or_default("allocator-rss.bytes").into()?,
1943 rss_overhead_ratio: values.remove_or_default("rss-overhead.ratio").into()?,
1944 rss_overhead_bytes: values.remove_or_default("rss-overhead.bytes").into()?,
1945 fragmentation: values.remove_or_default("fragmentation").into()?,
1946 fragmentation_bytes: values.remove_or_default("fragmentation.bytes").into()?,
1947 additional_stats: values,
1948 })
1949 }
1950}
1951
1952#[derive(Debug)]
1953pub struct DatabaseOverhead {
1954 pub overhead_hashtable_main: usize,
1955 pub overhead_hashtable_expires: usize,
1956 pub overhead_hashtable_slot_to_keys: usize,
1957}
1958
1959impl FromValue for DatabaseOverhead {
1960 fn from_value(value: Value) -> Result<Self> {
1961 let mut values: HashMap<String, Value> = value.into()?;
1962
1963 Ok(Self {
1964 overhead_hashtable_main: values.remove_or_default("overhead.hashtable.main").into()?,
1965 overhead_hashtable_expires: values
1966 .remove_or_default("overhead.hashtable.expires")
1967 .into()?,
1968 overhead_hashtable_slot_to_keys: values
1969 .remove_or_default("overhead.hashtable.slot-to-keys")
1970 .into()?,
1971 })
1972 }
1973}
1974
1975/// Options for the [`memory_usage`](crate::ServerCommands::memory_usage) command
1976#[derive(Default)]
1977pub struct MemoryUsageOptions {
1978 command_args: CommandArgs,
1979}
1980
1981impl MemoryUsageOptions {
1982 /// For nested data types, the optional `samples` option can be provided,
1983 /// where count is the number of sampled nested values.
1984 /// By default, this option is set to 5.
1985 /// To sample the all of the nested values, use samples(0).
1986 #[must_use]
1987 pub fn samples(self, count: usize) -> Self {
1988 Self {
1989 command_args: self.command_args.arg("SAMPLES").arg(count),
1990 }
1991 }
1992}
1993
1994impl IntoArgs for MemoryUsageOptions {
1995 fn into_args(self, args: CommandArgs) -> CommandArgs {
1996 args.arg(self.command_args)
1997 }
1998}
1999
2000/// Module information result for the [`module_list`](crate::ServerCommands::module_list) command.
2001pub struct ModuleInfo {
2002 /// Name of the module
2003 pub name: String,
2004 /// Version of the module
2005 pub version: String,
2006}
2007
2008impl FromValue for ModuleInfo {
2009 fn from_value(value: Value) -> Result<Self> {
2010 let mut values: HashMap<String, Value> = value.into()?;
2011
2012 Ok(Self {
2013 name: values.remove_or_default("name").into()?,
2014 version: values.remove_or_default("ver").into()?,
2015 })
2016 }
2017}
2018
2019/// Options for the [`module_load`](crate::ServerCommands::module_load) command
2020#[derive(Default)]
2021pub struct ModuleLoadOptions {
2022 command_args: CommandArgs,
2023 args_added: bool,
2024}
2025
2026impl ModuleLoadOptions {
2027 /// You can use this optional method to provide the module with configuration directives.
2028 /// This method can be called multiple times
2029 #[must_use]
2030 pub fn config<N, V>(self, name: N, value: V) -> Self
2031 where
2032 N: Into<CommandArg>,
2033 V: Into<CommandArg>,
2034 {
2035 if self.args_added {
2036 panic!("method config should be called before method arg");
2037 }
2038
2039 Self {
2040 command_args: self.command_args.arg("CONFIG").arg(name).arg(value),
2041 args_added: false,
2042 }
2043 }
2044
2045 /// Any additional arguments are passed unmodified to the module.
2046 /// This method can be called multiple times
2047 #[must_use]
2048 pub fn arg<A: Into<CommandArg>>(self, arg: A) -> Self {
2049 if !self.args_added {
2050 Self {
2051 command_args: self.command_args.arg("ARGS").arg(arg),
2052 args_added: true,
2053 }
2054 } else {
2055 Self {
2056 command_args: self.command_args.arg(arg),
2057 args_added: false,
2058 }
2059 }
2060 }
2061}
2062
2063impl IntoArgs for ModuleLoadOptions {
2064 fn into_args(self, args: CommandArgs) -> CommandArgs {
2065 args.arg(self.command_args)
2066 }
2067}
2068
2069/// options for the [`replicaof`](crate::ServerCommands::replicaof) command.
2070pub struct ReplicaOfOptions {
2071 command_args: CommandArgs,
2072}
2073
2074impl ReplicaOfOptions {
2075 /// If a Redis server is already acting as replica,
2076 /// the command REPLICAOF NO ONE will turn off the replication,
2077 /// turning the Redis server into a MASTER.
2078 #[must_use]
2079 pub fn no_one() -> Self {
2080 Self {
2081 command_args: CommandArgs::Empty.arg("NO").arg("ONE"),
2082 }
2083 }
2084
2085 /// In the proper form REPLICAOF hostname port will make the server
2086 /// a replica of another server listening at the specified hostname and port.
2087 #[must_use]
2088 pub fn master<H: Into<CommandArg>>(host: H, port: u16) -> Self {
2089 Self {
2090 command_args: CommandArgs::Empty.arg(host).arg(port),
2091 }
2092 }
2093}
2094
2095impl IntoArgs for ReplicaOfOptions {
2096 fn into_args(self, args: CommandArgs) -> CommandArgs {
2097 args.arg(self.command_args)
2098 }
2099}
2100
2101/// Result for the [`role`](crate::ServerCommands::role) command.
2102pub enum RoleResult {
2103 Master {
2104 /// The current master replication offset,
2105 /// which is an offset that masters and replicas share to understand,
2106 /// in partial resynchronizations,
2107 /// the part of the replication stream the replicas needs to fetch to continue.
2108 master_replication_offset: usize,
2109 /// information av=bout the connected replicas
2110 replica_infos: Vec<ReplicaInfo>,
2111 },
2112 Replica {
2113 /// The IP of the master.
2114 master_ip: String,
2115 /// The port number of the master.
2116 master_port: u16,
2117 /// The state of the replication from the point of view of the master
2118 state: ReplicationState,
2119 /// The amount of data received from the replica
2120 /// so far in terms of master replication offset.
2121 amount_data_received: isize,
2122 },
2123 Sentinel {
2124 /// An array of master names monitored by this Sentinel instance.
2125 master_names: Vec<String>,
2126 },
2127}
2128
2129impl FromValue for RoleResult {
2130 fn from_value(value: Value) -> Result<Self> {
2131 let values: Vec<Value> = value.into()?;
2132 let mut iter = values.into_iter();
2133
2134 match (
2135 iter.next(),
2136 iter.next(),
2137 iter.next(),
2138 iter.next(),
2139 iter.next(),
2140 iter.next(),
2141 ) {
2142 (
2143 Some(Value::BulkString(Some(s))),
2144 Some(master_replication_offset),
2145 Some(replica_infos),
2146 None,
2147 None,
2148 None,
2149 ) if s == b"master" => Ok(Self::Master {
2150 master_replication_offset: master_replication_offset.into()?,
2151 replica_infos: replica_infos.into()?,
2152 }),
2153 (
2154 Some(Value::BulkString(Some(s))),
2155 Some(master_ip),
2156 Some(master_port),
2157 Some(state),
2158 Some(amount_data_received),
2159 None,
2160 ) if s == b"slave" => Ok(Self::Replica {
2161 master_ip: master_ip.into()?,
2162 master_port: master_port.into()?,
2163 state: state.into()?,
2164 amount_data_received: amount_data_received.into()?,
2165 }),
2166 (
2167 Some(Value::BulkString(Some(s))),
2168 Some(master_names),
2169 None,
2170 None,
2171 None,
2172 None,
2173 ) if s == b"sentinel" => Ok(Self::Sentinel {
2174 master_names: master_names.into()?,
2175 }),
2176 _ => Err(Error::Client(
2177 "Cannot parse RoleResult from result".to_string(),
2178 )),
2179 }
2180 }
2181}
2182
2183/// Represents a connected replicas to a master
2184///
2185/// returned by the [`role`](crate::ServerCommands::role) command.
2186pub struct ReplicaInfo {
2187 /// the replica IP
2188 pub ip: String,
2189 /// the replica port
2190 pub port: u16,
2191 /// the last acknowledged replication offset.
2192 pub last_ack_offset: usize,
2193}
2194
2195impl FromValue for ReplicaInfo {
2196 fn from_value(value: Value) -> Result<Self> {
2197 let (ip, port, last_ack_offset) = value.into()?;
2198 Ok(Self {
2199 ip,
2200 port,
2201 last_ack_offset,
2202 })
2203 }
2204}
2205
2206/// The state of the replication from the point of view of the master,
2207///
2208/// returned by the [`role`](crate::ServerCommands::role) command.
2209pub enum ReplicationState {
2210 /// the instance needs to connect to its master
2211 Connect,
2212 /// the master-replica connection is in progress
2213 Connecting,
2214 /// the master and replica are trying to perform the synchronization
2215 Sync,
2216 /// the replica is online
2217 Connected,
2218}
2219
2220impl FromValue for ReplicationState {
2221 fn from_value(value: Value) -> Result<Self> {
2222 let str: String = value.into()?;
2223
2224 match str.as_str() {
2225 "connect" => Ok(Self::Connect),
2226 "connecting" => Ok(Self::Connecting),
2227 "sync" => Ok(Self::Sync),
2228 "connected" => Ok(Self::Connected),
2229 _ => Err(Error::Client(format!(
2230 "Cannot parse {str} to ReplicationState"
2231 ))),
2232 }
2233 }
2234}
2235
2236/// options for the [`shutdown`](crate::ServerCommands::shutdown) command.
2237#[derive(Default)]
2238pub struct ShutdownOptions {
2239 command_args: CommandArgs,
2240}
2241
2242impl ShutdownOptions {
2243 /// - if save is true, will force a DB saving operation even if no save points are configured
2244 /// - if save is false, will prevent a DB saving operation even if one or more save points are configured.
2245 #[must_use]
2246 pub fn save(self, save: bool) -> Self {
2247 Self {
2248 command_args: self.command_args.arg(if save { "SAVE" } else { "NOSAVE" }),
2249 }
2250 }
2251
2252 /// skips waiting for lagging replicas, i.e. it bypasses the first step in the shutdown sequence.
2253 #[must_use]
2254 pub fn now(self) -> Self {
2255 Self {
2256 command_args: self.command_args.arg("NOW"),
2257 }
2258 }
2259
2260 /// ignores any errors that would normally prevent the server from exiting.
2261 #[must_use]
2262 pub fn force(self) -> Self {
2263 Self {
2264 command_args: self.command_args.arg("FORCE"),
2265 }
2266 }
2267
2268 /// cancels an ongoing shutdown and cannot be combined with other flags.
2269 #[must_use]
2270 pub fn abort(self) -> Self {
2271 Self {
2272 command_args: self.command_args.arg("ABORT"),
2273 }
2274 }
2275}
2276
2277impl IntoArgs for ShutdownOptions {
2278 fn into_args(self, args: CommandArgs) -> CommandArgs {
2279 args.arg(self.command_args)
2280 }
2281}
2282
2283/// options for the [`slowlog_get`](crate::ServerCommands::slowlog_get) command.
2284#[derive(Default)]
2285pub struct SlowLogOptions {
2286 command_args: CommandArgs,
2287}
2288
2289impl SlowLogOptions {
2290 /// limits the number of returned entries, so the command returns at most up to `count` entries.
2291 #[must_use]
2292 pub fn count(self, count: usize) -> Self {
2293 Self {
2294 command_args: self.command_args.arg(count),
2295 }
2296 }
2297}
2298
2299impl IntoArgs for SlowLogOptions {
2300 fn into_args(self, args: CommandArgs) -> CommandArgs {
2301 args.arg(self.command_args)
2302 }
2303}
2304
2305/// Result [`slowlog_get`](crate::ServerCommands::slowlog_get) for the command.
2306pub struct SlowLogEntry {
2307 /// A unique progressive identifier for every slow log entry.
2308 pub id: i64,
2309 /// A unique progressive identifier for every slow log entry.
2310 pub unix_timestamp: u32,
2311 /// The amount of time needed for its execution, in microseconds.
2312 pub execution_time_micros: u64,
2313 /// The array composing the arguments of the command.
2314 pub command: Vec<String>,
2315 /// Client IP address and port.
2316 pub client_address: String,
2317 /// Client name if set via the CLIENT SETNAME command.
2318 pub client_name: String,
2319}
2320
2321impl FromValue for SlowLogEntry {
2322 fn from_value(value: Value) -> Result<Self> {
2323 let (id, unix_timestamp, execution_time_micros, command, client_address, client_name) =
2324 value.into()?;
2325
2326 Ok(Self {
2327 id,
2328 unix_timestamp,
2329 execution_time_micros,
2330 command,
2331 client_address,
2332 client_name,
2333 })
2334 }
2335}