1use crate::ValkeyResult;
5use crate::cmd::Cmd;
6use crate::executor::CommandExecutor;
7use crate::value::FromValkeyValue;
8use crate::value::ValkeyValue;
9use crate::write::ToValkeyArgs;
10use async_trait::async_trait;
11use bytes::Bytes;
12
13#[async_trait]
15pub trait HashCommands: CommandExecutor {
16 async fn hstrlen<K: ToValkeyArgs + Send, F: ToValkeyArgs + Send>(
21 &self,
22 key: K,
23 field: F,
24 ) -> ValkeyResult<i64> {
25 let mut cmd = Cmd::new();
26 cmd.arg("HSTRLEN").arg(key).arg(field);
27 i64::from_owned_valkey_value(self.execute_command(cmd, None).await?)
28 }
29
30 async fn hrandfield<K: ToValkeyArgs + Send>(&self, key: K) -> ValkeyResult<Option<Bytes>> {
32 let mut cmd = Cmd::new();
33 cmd.arg("HRANDFIELD").arg(key);
34 Option::<Bytes>::from_owned_valkey_value(self.execute_command(cmd, None).await?)
35 }
36
37 async fn hrandfield_count<K: ToValkeyArgs + Send>(
39 &self,
40 key: K,
41 count: i64,
42 ) -> ValkeyResult<Vec<Bytes>> {
43 let mut cmd = Cmd::new();
44 cmd.arg("HRANDFIELD").arg(key).arg(count);
45 collect_bytes(self.execute_command(cmd, None).await?)
46 }
47
48 async fn hrandfield_withvalues<K: ToValkeyArgs + Send>(
51 &self,
52 key: K,
53 count: i64,
54 ) -> ValkeyResult<Vec<(Bytes, Bytes)>> {
55 let mut cmd = Cmd::new();
56 cmd.arg("HRANDFIELD").arg(key).arg(count).arg("WITHVALUES");
57 collect_pairs(self.execute_command(cmd, None).await?)
58 }
59
60 async fn hscan_novalues<K: ToValkeyArgs + Send>(
63 &self,
64 key: K,
65 cursor: &str,
66 pattern: Option<&[u8]>,
67 count: Option<i64>,
68 ) -> ValkeyResult<(String, Vec<Bytes>)> {
69 let mut cmd = Cmd::new();
70 cmd.arg("HSCAN").arg(key).arg(cursor);
71 if let Some(p) = pattern {
72 cmd.arg("MATCH").arg(p);
73 }
74 if let Some(c) = count {
75 cmd.arg("COUNT").arg(c);
76 }
77 cmd.arg("NOVALUES");
78 crate::commands::generic::parse_scan_reply(self.execute_command(cmd, None).await?)
79 }
80}
81
82fn collect_pairs(v: ValkeyValue) -> ValkeyResult<Vec<(Bytes, Bytes)>> {
84 match v {
85 ValkeyValue::Nil => Ok(Vec::new()),
86 ValkeyValue::Map(pairs) => pairs
87 .into_iter()
88 .map(|(a, b)| {
89 Ok((
90 Bytes::from_owned_valkey_value(a)?,
91 Bytes::from_owned_valkey_value(b)?,
92 ))
93 })
94 .collect(),
95 ValkeyValue::Array(items) => {
96 if items
97 .iter()
98 .all(|it| matches!(it, ValkeyValue::Array(inner) if inner.len() == 2))
99 {
100 let mut out = Vec::with_capacity(items.len());
101 for it in items {
102 if let ValkeyValue::Array(mut pair) = it {
103 let b = Bytes::from_owned_valkey_value(pair.pop().unwrap())?;
104 let a = Bytes::from_owned_valkey_value(pair.pop().unwrap())?;
105 out.push((a, b));
106 }
107 }
108 Ok(out)
109 } else {
110 let mut out = Vec::with_capacity(items.len() / 2);
111 let mut iter = items.into_iter();
112 while let (Some(a), Some(b)) = (iter.next(), iter.next()) {
113 out.push((
114 Bytes::from_owned_valkey_value(a)?,
115 Bytes::from_owned_valkey_value(b)?,
116 ));
117 }
118 Ok(out)
119 }
120 }
121 other => Ok(vec![(Bytes::from_owned_valkey_value(other)?, Bytes::new())]),
122 }
123}
124
125fn collect_bytes(v: ValkeyValue) -> ValkeyResult<Vec<Bytes>> {
126 match v {
127 ValkeyValue::Array(items) => items
128 .into_iter()
129 .map(Bytes::from_owned_valkey_value)
130 .collect(),
131 ValkeyValue::Nil => Ok(Vec::new()),
132 other => Ok(vec![Bytes::from_owned_valkey_value(other)?]),
133 }
134}
135
136impl<T: CommandExecutor + ?Sized> HashCommands for T {}