use crate::{ client::{prepare_command, PreparedCommand}, resp::{ cmd, CollectionResponse, CommandArgs, PrimitiveResponse, SingleArg, SingleArgCollection, ToArgs, }, }; use serde::de::DeserializeOwned; /// A group of Redis commands related to [`Lists`](https://redis.io/docs/data-types/lists/) /// /// # See Also /// [Redis List Commands](https://redis.io/commands/?group=list) pub trait ListCommands<'a> { /// Returns the element at index index in the list stored at key. /// /// # Return /// The requested element, or nil when index is out of range. /// /// # See Also /// [](https://redis.io/commands/lindex/) #[must_use] fn lindex(self, key: K, index: isize) -> PreparedCommand<'a, Self, E> where Self: Sized, K: SingleArg, E: PrimitiveResponse, { prepare_command(self, cmd("LINDEX").arg(key).arg(index)) } /// Inserts element in the list stored at key either before or after the reference value pivot. /// /// # Return /// The length of the list after the insert operation, or -1 when the value pivot was not found. /// /// # See Also /// [](https://redis.io/commands/linsert/) #[must_use] fn linsert( self, key: K, where_: LInsertWhere, pivot: E, element: E, ) -> PreparedCommand<'a, Self, usize> where Self: Sized, K: SingleArg, E: SingleArg, { prepare_command( self, cmd("LINSERT").arg(key).arg(where_).arg(pivot).arg(element), ) } /// Inserts element in the list stored at key either before or after the reference value pivot. /// /// # Return /// The length of the list at key. /// /// # See Also /// [](https://redis.io/commands/llen/) #[must_use] fn llen(self, key: K) -> PreparedCommand<'a, Self, usize> where Self: Sized, K: SingleArg, { prepare_command(self, cmd("LLEN").arg(key)) } /// Atomically returns and removes the first/last element (head/tail depending on the wherefrom argument) /// of the list stored at source, and pushes the element at the first/last element /// (head/tail depending on the whereto argument) of the list stored at destination. /// /// # Return /// The element being popped and pushed. /// /// # See Also /// [](https://redis.io/commands/lmove/) #[must_use] fn lmove( self, source: S, destination: D, where_from: LMoveWhere, where_to: LMoveWhere, ) -> PreparedCommand<'a, Self, E> where Self: Sized, S: SingleArg, D: SingleArg, E: PrimitiveResponse, { prepare_command( self, cmd("LMOVE") .arg(source) .arg(destination) .arg(where_from) .arg(where_to), ) } /// Pops one or more elements from the first non-empty list key from the list of provided key names. /// /// # Return /// Tuple composed by the name of the key from which elements were popped and the list of popped element /// /// # See Also /// [](https://redis.io/commands/lmpop/) #[must_use] fn lmpop( self, keys: C, where_: LMoveWhere, count: usize, ) -> PreparedCommand<'a, Self, (String, Vec)> where Self: Sized, K: SingleArg, E: PrimitiveResponse + DeserializeOwned, C: SingleArgCollection, { prepare_command( self, cmd("LMPOP") .arg(keys.num_args()) .arg(keys) .arg(where_) .arg("COUNT") .arg(count), ) } /// Removes and returns the first elements of the list stored at key. /// /// # Return /// The list of popped elements, or empty collection when key does not exist. /// /// # See Also /// [](https://redis.io/commands/lpop/) #[must_use] fn lpop(self, key: K, count: usize) -> PreparedCommand<'a, Self, A> where Self: Sized, K: SingleArg, E: PrimitiveResponse + DeserializeOwned, A: CollectionResponse + DeserializeOwned, { prepare_command(self, cmd("LPOP").arg(key).arg(count)) } /// Returns the index of matching elements inside a Redis list. /// /// # Return /// The integer representing the matching element, or nil if there is no match. /// /// # See Also /// [](https://redis.io/commands/lpos/) #[must_use] fn lpos( self, key: K, element: E, rank: Option, max_len: Option, ) -> PreparedCommand<'a, Self, Option> where Self: Sized, K: SingleArg, E: SingleArg, { prepare_command( self, cmd("LPOS") .arg(key) .arg(element) .arg(rank.map(|r| ("RANK", r))) .arg(max_len.map(|l| ("MAXLEN", l))), ) } /// Returns the index of matching elements inside a Redis list. /// /// # Return /// An array of integers representing the matching elements. /// (empty if there are no matches). /// /// # See Also /// [](https://redis.io/commands/lpos/) #[must_use] fn lpos_with_count( self, key: K, element: E, num_matches: usize, rank: Option, max_len: Option, ) -> PreparedCommand<'a, Self, A> where Self: Sized, K: SingleArg, E: SingleArg, A: CollectionResponse, { prepare_command( self, cmd("LPOS") .arg(key) .arg(element) .arg(rank.map(|r| ("RANK", r))) .arg("COUNT") .arg(num_matches) .arg(max_len.map(|l| ("MAXLEN", l))), ) } /// Insert all the specified values at the head of the list stored at key /// /// # Return /// The length of the list after the push operations. /// /// # See Also /// [](https://redis.io/commands/lpush/) #[must_use] fn lpush(self, key: K, elements: C) -> PreparedCommand<'a, Self, usize> where Self: Sized, K: SingleArg, E: SingleArg, C: SingleArgCollection, { prepare_command(self, cmd("LPUSH").arg(key).arg(elements)) } /// Inserts specified values at the head of the list stored at key, /// only if key already exists and holds a list. /// /// # Return /// The length of the list after the push operation. /// /// # See Also /// [](https://redis.io/commands/lpushx/) #[must_use] fn lpushx(self, key: K, elements: C) -> PreparedCommand<'a, Self, usize> where Self: Sized, K: SingleArg, E: SingleArg, C: SingleArgCollection, { prepare_command(self, cmd("LPUSHX").arg(key).arg(elements)) } /// Returns the specified elements of the list stored at key. /// /// # Return /// The list of elements in the specified range. /// /// # See Also /// [](https://redis.io/commands/lrange/) #[must_use] fn lrange(self, key: K, start: isize, stop: isize) -> PreparedCommand<'a, Self, A> where Self: Sized, K: SingleArg, E: PrimitiveResponse + DeserializeOwned, A: CollectionResponse + DeserializeOwned, { prepare_command(self, cmd("LRANGE").arg(key).arg(start).arg(stop)) } /// Removes the first count occurrences of elements equal to element from the list stored at key. /// /// # Return /// The number of removed elements. /// /// # See Also /// [](https://redis.io/commands/lrem/) #[must_use] fn lrem(self, key: K, count: isize, element: E) -> PreparedCommand<'a, Self, usize> where Self: Sized, K: SingleArg, E: SingleArg, { prepare_command(self, cmd("LREM").arg(key).arg(count).arg(element)) } /// Sets the list element at index to element. /// /// # See Also /// [](https://redis.io/commands/lset/) #[must_use] fn lset(self, key: K, index: isize, element: E) -> PreparedCommand<'a, Self, ()> where Self: Sized, K: SingleArg, E: SingleArg, { prepare_command(self, cmd("LSET").arg(key).arg(index).arg(element)) } /// Trim an existing list so that it will contain only the specified range of elements specified. /// /// # See Also /// [](https://redis.io/commands/ltrim/) #[must_use] fn ltrim(self, key: K, start: isize, stop: isize) -> PreparedCommand<'a, Self, ()> where Self: Sized, K: SingleArg, { prepare_command(self, cmd("LTRIM").arg(key).arg(start).arg(stop)) } /// Removes and returns the first elements of the list stored at key. /// /// # Return /// The list of popped elements, or empty collection when key does not exist. /// /// # See Also /// [](https://redis.io/commands/rpop/) #[must_use] fn rpop(self, key: K, count: usize) -> PreparedCommand<'a, Self, C> where Self: Sized, K: SingleArg, E: PrimitiveResponse + DeserializeOwned, C: CollectionResponse + DeserializeOwned, { prepare_command(self, cmd("RPOP").arg(key).arg(count)) } /// Insert all the specified values at the tail of the list stored at key /// /// # Return /// The length of the list after the push operations. /// /// # See Also /// [](https://redis.io/commands/rpush/) #[must_use] fn rpush(self, key: K, elements: C) -> PreparedCommand<'a, Self, usize> where Self: Sized, K: SingleArg, E: SingleArg, C: SingleArgCollection, { prepare_command(self, cmd("RPUSH").arg(key).arg(elements)) } /// Inserts specified values at the tail of the list stored at key, /// only if key already exists and holds a list. /// /// # Return /// The length of the list after the push operations. /// /// # See Also /// [](https://redis.io/commands/rpushx/) #[must_use] fn rpushx(self, key: K, elements: C) -> PreparedCommand<'a, Self, usize> where Self: Sized, K: SingleArg, E: SingleArg, C: SingleArgCollection, { prepare_command(self, cmd("RPUSHX").arg(key).arg(elements)) } } /// Where option for the [`linsert`](ListCommands::linsert) command. pub enum LInsertWhere { Before, After, } impl ToArgs for LInsertWhere { fn write_args(&self, args: &mut CommandArgs) { args.arg(match self { LInsertWhere::Before => "BEFORE", LInsertWhere::After => "AFTER", }); } } /// Where option for the [`lmove`](ListCommands::lmove) command. pub enum LMoveWhere { Left, Right, } impl ToArgs for LMoveWhere { fn write_args(&self, args: &mut CommandArgs) { args.arg(match self { LMoveWhere::Left => "LEFT", LMoveWhere::Right => "RIGHT", }); } }