Skip to main content

kevy_store/
hash_read.rs

1//! `Store` hash read commands — split from `hash.rs` when the SegHash
2//! arms pushed it against the 500-LOC cap.
3
4#[cfg(not(feature = "std"))]
5use crate::nostd_prelude::*;
6use crate::value::{SmallBytes, Value};
7use crate::{Store, StoreError};
8
9/// `(field, value)` pairs collected off any hash encoding.
10pub(crate) type FieldValuePairs = Vec<(Vec<u8>, Vec<u8>)>;
11
12impl Store {
13    /// Read the key's hash immutably (lazily expiring) — returns the
14    /// pairs as a vector. None if absent. Internal helper for read-only
15    /// paths; collects into a new Vec to avoid the encoding match dance
16    /// at every callsite.
17    pub(crate) fn hash_pairs(&mut self, key: &[u8]) -> Result<Option<FieldValuePairs>, StoreError> {
18        match self.tier_serve(key, crate::value::COLD_TAG_HASH)? {
19            None => Ok(None),
20            Some(e) => match &e.value {
21                Value::Hash(h) => Ok(Some(
22                    h.iter().map(|(f, v)| (f.to_vec(), v.to_vec())).collect(),
23                )),
24                Value::SegHash(h) => Ok(Some(
25                    h.iter().map(|(f, v)| (f.to_vec(), v.to_vec())).collect(),
26                )),
27                Value::SmallHashInline(h) => Ok(Some(
28                    h.iter().map(|(f, v)| (f.to_vec(), v.to_vec())).collect(),
29                )),
30                _ => Err(StoreError::WrongType),
31            },
32        }
33    }
34
35    pub fn hget(&mut self, key: &[u8], field: &[u8]) -> Result<Option<&[u8]>, StoreError> {
36        self.purge_hash_ttl(key);
37        match self.tier_serve(key, crate::value::COLD_TAG_HASH)? {
38            None => Ok(None),
39            Some(e) => match &e.value {
40                Value::Hash(h) => Ok(h.get(field).map(SmallBytes::as_slice)),
41                Value::SegHash(h) => Ok(h.get(field).map(SmallBytes::as_slice)),
42                Value::SmallHashInline(h) => Ok(h.get(field)),
43                _ => Err(StoreError::WrongType),
44            },
45        }
46    }
47
48    pub fn hexists(&mut self, key: &[u8], field: &[u8]) -> Result<bool, StoreError> {
49        self.purge_hash_ttl(key);
50        match self.tier_serve(key, crate::value::COLD_TAG_HASH)? {
51            None => Ok(false),
52            Some(e) => match &e.value {
53                Value::Hash(h) => Ok(h.contains_key(field)),
54                Value::SegHash(h) => Ok(h.contains_key(field)),
55                Value::SmallHashInline(h) => Ok(h.contains_key(field)),
56                _ => Err(StoreError::WrongType),
57            },
58        }
59    }
60
61    pub fn hlen(&mut self, key: &[u8]) -> Result<usize, StoreError> {
62        self.purge_hash_ttl(key);
63        match self.tier_serve(key, crate::value::COLD_TAG_HASH)? {
64            None => Ok(0),
65            Some(e) => match &e.value {
66                Value::Hash(h) => Ok(h.len()),
67                Value::SegHash(h) => Ok(h.len()),
68                Value::SmallHashInline(h) => Ok(h.len()),
69                _ => Err(StoreError::WrongType),
70            },
71        }
72    }
73
74    /// `HMGET` — one `Option` per requested field, in input order.
75    pub fn hmget(
76        &mut self,
77        key: &[u8],
78        fields: &[&[u8]],
79    ) -> Result<Vec<Option<Vec<u8>>>, StoreError> {
80        self.purge_hash_ttl(key);
81        match self.tier_serve(key, crate::value::COLD_TAG_HASH)? {
82            None => Ok(fields.iter().map(|_| None).collect()),
83            Some(e) => match &e.value {
84                Value::Hash(h) => {
85                    Ok(fields.iter().map(|f| h.get(*f).map(SmallBytes::to_vec)).collect())
86                }
87                Value::SegHash(h) => {
88                    Ok(fields.iter().map(|f| h.get(f).map(SmallBytes::to_vec)).collect())
89                }
90                Value::SmallHashInline(h) => Ok(fields
91                    .iter()
92                    .map(|f| h.get(f).map(<[u8]>::to_vec))
93                    .collect()),
94                _ => Err(StoreError::WrongType),
95            },
96        }
97    }
98
99    /// `HGETALL` — flat `[field, value, field, value, ...]`.
100    pub fn hgetall(&mut self, key: &[u8]) -> Result<Vec<Vec<u8>>, StoreError> {
101        self.purge_hash_ttl(key);
102        match self.hash_pairs(key)? {
103            None => Ok(Vec::new()),
104            Some(pairs) => {
105                let mut out = Vec::with_capacity(pairs.len() * 2);
106                for (f, v) in pairs {
107                    out.push(f);
108                    out.push(v);
109                }
110                Ok(out)
111            }
112        }
113    }
114
115    pub fn hkeys(&mut self, key: &[u8]) -> Result<Vec<Vec<u8>>, StoreError> {
116        self.purge_hash_ttl(key);
117        match self.tier_serve(key, crate::value::COLD_TAG_HASH)? {
118            None => Ok(Vec::new()),
119            Some(e) => match &e.value {
120                Value::Hash(h) => Ok(h.keys().map(kevy_bytes::SmallBytes::to_vec).collect()),
121                Value::SegHash(h) => Ok(h.keys().map(kevy_bytes::SmallBytes::to_vec).collect()),
122                Value::SmallHashInline(h) => Ok(h.iter().map(|(f, _)| f.to_vec()).collect()),
123                _ => Err(StoreError::WrongType),
124            },
125        }
126    }
127
128    pub fn hvals(&mut self, key: &[u8]) -> Result<Vec<Vec<u8>>, StoreError> {
129        self.purge_hash_ttl(key);
130        match self.tier_serve(key, crate::value::COLD_TAG_HASH)? {
131            None => Ok(Vec::new()),
132            Some(e) => match &e.value {
133                Value::Hash(h) => Ok(h.values().map(SmallBytes::to_vec).collect()),
134                Value::SegHash(h) => Ok(h.values().map(SmallBytes::to_vec).collect()),
135                Value::SmallHashInline(h) => Ok(h.iter().map(|(_, v)| v.to_vec()).collect()),
136                _ => Err(StoreError::WrongType),
137            },
138        }
139    }
140}