use crate::{
api::zset::{
r#impl::{compose_zset_meta_key, get_zset_meta},
opt::{IntoRangeLex, IntoRangeScore},
},
engine::Engine,
error::{Error, Result},
meta::current_now_ms,
wedb::Db,
};
impl<E: Engine> Db<E>
where
Error: From<E::Error>,
{
#[inline]
pub fn zcard<K: AsRef<[u8]>>(&self, key: K) -> Result<u64> {
let kc = self.kc();
let k_bytes = key.as_ref();
let meta_k = compose_zset_meta_key(&kc, k_bytes);
let now_ms = current_now_ms();
match get_zset_meta(self, k_bytes, &meta_k, now_ms)? {
Some(meta) => Ok(meta.base.size),
None => Ok(0),
}
}
#[inline]
pub fn zcount<K: AsRef<[u8]>>(&self, key: K, spec: impl IntoRangeScore) -> Result<u64> {
let spec = spec.into_range_score();
if spec.is_empty() {
return Ok(0);
}
let mut count = 0u64;
self.ziter_range_byscore(key, &spec, |_, _| {
count += 1;
true
})?;
Ok(count)
}
#[inline]
pub fn zlexcount<K: AsRef<[u8]>>(&self, key: K, spec: impl IntoRangeLex) -> Result<u64> {
let spec = spec.into_range_lex();
if spec.is_empty() {
return Ok(0);
}
let mut count = 0u64;
self.ziter_range_bylex(key, &spec, |_, _| {
count += 1;
true
})?;
Ok(count)
}
#[inline]
pub fn zrank<K: AsRef<[u8]>, M: AsRef<[u8]>>(&self, key: K, member: M) -> Result<Option<u64>> {
Ok(self.zrank_with_score(key, member)?.map(|(r, _)| r))
}
#[inline]
pub fn zrank_with_score<K: AsRef<[u8]>, M: AsRef<[u8]>>(
&self,
key: K,
member: M,
) -> Result<Option<(u64, f64)>> {
let target_score = match self.zscore(&key, &member)? {
Some(score) => score,
None => return Ok(None),
};
let m_ref = member.as_ref();
let mut rank = 0u64;
let mut found = false;
self.ziter(key, |m, score| {
if score == target_score && m == m_ref {
found = true;
false
} else if score > target_score || (score == target_score && m > m_ref) {
false
} else {
rank += 1;
true
}
})?;
Ok(if found {
Some((rank, target_score))
} else {
None
})
}
#[inline]
pub fn zrevrank<K: AsRef<[u8]>, M: AsRef<[u8]>>(&self, key: K, member: M) -> Result<Option<u64>> {
Ok(self.zrevrank_with_score(key, member)?.map(|(r, _)| r))
}
#[inline]
pub fn zrevrank_with_score<K: AsRef<[u8]>, M: AsRef<[u8]>>(
&self,
key: K,
member: M,
) -> Result<Option<(u64, f64)>> {
let target_score = match self.zscore(&key, &member)? {
Some(score) => score,
None => return Ok(None),
};
let m_ref = member.as_ref();
let mut rank = 0u64;
let mut found = false;
self.ziter_rev(key, |m, score| {
if score == target_score && m == m_ref {
found = true;
false
} else if score < target_score || (score == target_score && m < m_ref) {
false
} else {
rank += 1;
true
}
})?;
Ok(if found {
Some((rank, target_score))
} else {
None
})
}
}