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) => {
22                    Ok(Some(h.iter().map(|(f, v)| (f.to_vec(), v.to_vec())).collect()))
23                }
24                Value::SegHash(h) => {
25                    Ok(Some(h.iter().map(|(f, v)| (f.to_vec(), v.to_vec())).collect()))
26                }
27                Value::SmallHashInline(h) => {
28                    Ok(Some(h.iter().map(|(f, v)| (f.to_vec(), v.to_vec())).collect()))
29                }
30                Value::PackedRow(r) => {
31                    Ok(Some(r.fields().map(|(f, v)| (f.to_vec(), v.to_vec())).collect()))
32                }
33                _ => Err(StoreError::WrongType),
34            },
35        }
36    }
37
38    /// One field's value, borrowed from the store. `Ok(None)` for a
39    /// missing key or a missing field — the two are indistinguishable to
40    /// HGET by design; `Err` only when `key` holds something that is not a
41    /// hash.
42    pub fn hget(&mut self, key: &[u8], field: &[u8]) -> Result<Option<&[u8]>, StoreError> {
43        self.purge_hash_ttl(key);
44        match self.tier_serve(key, crate::value::COLD_TAG_HASH)? {
45            None => Ok(None),
46            Some(e) => match &e.value {
47                Value::Hash(h) => Ok(h.get(field).map(SmallBytes::as_slice)),
48                Value::SegHash(h) => Ok(h.get(field).map(SmallBytes::as_slice)),
49                Value::SmallHashInline(h) => Ok(h.get(field)),
50                Value::PackedRow(r) => Ok(r.get_named(field)),
51                _ => Err(StoreError::WrongType),
52            },
53        }
54    }
55
56    /// Whether `field` is present. A missing key is `false`, not an
57    /// error; a wrong-typed key is an error.
58    pub fn hexists(&mut self, key: &[u8], field: &[u8]) -> Result<bool, StoreError> {
59        self.purge_hash_ttl(key);
60        match self.tier_serve(key, crate::value::COLD_TAG_HASH)? {
61            None => Ok(false),
62            Some(e) => match &e.value {
63                Value::Hash(h) => Ok(h.contains_key(field)),
64                Value::SegHash(h) => Ok(h.contains_key(field)),
65                Value::SmallHashInline(h) => Ok(h.contains_key(field)),
66                Value::PackedRow(r) => Ok(r.has_named(field)),
67                _ => Err(StoreError::WrongType),
68            },
69        }
70    }
71
72    /// Field count. A missing key is 0, matching HLEN.
73    pub fn hlen(&mut self, key: &[u8]) -> Result<usize, StoreError> {
74        self.purge_hash_ttl(key);
75        match self.tier_serve(key, crate::value::COLD_TAG_HASH)? {
76            None => Ok(0),
77            Some(e) => match &e.value {
78                Value::Hash(h) => Ok(h.len()),
79                Value::SegHash(h) => Ok(h.len()),
80                Value::SmallHashInline(h) => Ok(h.len()),
81                Value::PackedRow(r) => Ok(r.len()),
82                _ => Err(StoreError::WrongType),
83            },
84        }
85    }
86
87    /// `HMGET` — one `Option` per requested field, in input order.
88    pub fn hmget(
89        &mut self,
90        key: &[u8],
91        fields: &[&[u8]],
92    ) -> Result<Vec<Option<Vec<u8>>>, StoreError> {
93        self.purge_hash_ttl(key);
94        match self.tier_serve(key, crate::value::COLD_TAG_HASH)? {
95            None => Ok(fields.iter().map(|_| None).collect()),
96            Some(e) => match &e.value {
97                Value::Hash(h) => {
98                    Ok(fields.iter().map(|f| h.get(*f).map(SmallBytes::to_vec)).collect())
99                }
100                Value::SegHash(h) => {
101                    Ok(fields.iter().map(|f| h.get(f).map(SmallBytes::to_vec)).collect())
102                }
103                Value::SmallHashInline(h) => {
104                    Ok(fields.iter().map(|f| h.get(f).map(<[u8]>::to_vec)).collect())
105                }
106                Value::PackedRow(r) => {
107                    Ok(fields.iter().map(|f| r.get_named(f).map(<[u8]>::to_vec)).collect())
108                }
109                _ => Err(StoreError::WrongType),
110            },
111        }
112    }
113
114    /// `HGETALL` — flat `[field, value, field, value, ...]`.
115    pub fn hgetall(&mut self, key: &[u8]) -> Result<Vec<Vec<u8>>, StoreError> {
116        self.purge_hash_ttl(key);
117        match self.hash_pairs(key)? {
118            None => Ok(Vec::new()),
119            Some(pairs) => {
120                let mut out = Vec::with_capacity(pairs.len() * 2);
121                for (f, v) in pairs {
122                    out.push(f);
123                    out.push(v);
124                }
125                Ok(out)
126            }
127        }
128    }
129
130    /// Every field name, copied out. Unordered: a hash has no field
131    /// order to preserve, so two calls may differ in sequence.
132    pub fn hkeys(&mut self, key: &[u8]) -> Result<Vec<Vec<u8>>, StoreError> {
133        self.purge_hash_ttl(key);
134        match self.tier_serve(key, crate::value::COLD_TAG_HASH)? {
135            None => Ok(Vec::new()),
136            Some(e) => match &e.value {
137                Value::Hash(h) => Ok(h.keys().map(kevy_bytes::SmallBytes::to_vec).collect()),
138                Value::SegHash(h) => Ok(h.keys().map(kevy_bytes::SmallBytes::to_vec).collect()),
139                Value::SmallHashInline(h) => Ok(h.iter().map(|(f, _)| f.to_vec()).collect()),
140                Value::PackedRow(r) => Ok(r.fields().map(|(f, _)| f.to_vec()).collect()),
141                _ => Err(StoreError::WrongType),
142            },
143        }
144    }
145
146    /// Every value, copied out, in the same unordered sequence `hkeys`
147    /// would return its fields.
148    pub fn hvals(&mut self, key: &[u8]) -> Result<Vec<Vec<u8>>, StoreError> {
149        self.purge_hash_ttl(key);
150        match self.tier_serve(key, crate::value::COLD_TAG_HASH)? {
151            None => Ok(Vec::new()),
152            Some(e) => match &e.value {
153                Value::Hash(h) => Ok(h.values().map(SmallBytes::to_vec).collect()),
154                Value::SegHash(h) => Ok(h.values().map(SmallBytes::to_vec).collect()),
155                Value::SmallHashInline(h) => Ok(h.iter().map(|(_, v)| v.to_vec()).collect()),
156                Value::PackedRow(r) => Ok(r.fields().map(|(_, v)| v.to_vec()).collect()),
157                _ => Err(StoreError::WrongType),
158            },
159        }
160    }
161}