use std::time::SystemTime;
use crate::engine::{Tx, group_key, ns};
use crate::{Result, Store, to_ms};
pub struct Tasks<'a> {
store: &'a Store,
}
impl<'a> Tasks<'a> {
pub(crate) fn new(store: &'a Store) -> Self {
Self { store }
}
pub fn kv_get(&self, key: impl AsRef<[u8]>) -> Result<Option<Vec<u8>>> {
Ok(self.store.get(ns::KV, key.as_ref())?.map(|(_, v)| v))
}
pub fn kv_put(&self, key: impl AsRef<[u8]>, value: &[u8]) -> Result<()> {
self.store
.put(ns::KV, key.as_ref(), value, now_ms())
.map(drop)
}
pub fn kv_delete(&self, key: impl AsRef<[u8]>) -> Result<bool> {
self.store.delete(ns::KV, key.as_ref())
}
pub fn kv_keys(&self, prefix: impl AsRef<[u8]>) -> Result<Vec<Vec<u8>>> {
let p = prefix.as_ref();
self.store.keys(ns::KV, |k| k.starts_with(p))
}
pub fn list_push(&self, list: impl AsRef<[u8]>, item: &[u8]) -> Result<u64> {
let r = list_push(
&mut self.store.tx(),
ns::LIST_ITEM,
list.as_ref(),
item,
now_ms(),
);
self.store.finish();
r
}
pub fn list_pop_front(&self, list: impl AsRef<[u8]>) -> Result<Option<Vec<u8>>> {
let list = list.as_ref();
let mut tx = self.store.tx();
let Some((seq, item)) = list_front(&tx, ns::LIST_ITEM, list)? else {
return Ok(None);
};
tx.delete(ns::LIST_ITEM, &group_key(list, &seq.to_be_bytes())?)?;
drop(tx);
self.store.finish();
Ok(Some(item))
}
pub fn list_front(&self, list: impl AsRef<[u8]>) -> Result<Option<Vec<u8>>> {
let tx = self.store.tx();
Ok(list_front(&tx, ns::LIST_ITEM, list.as_ref())?.map(|(_, v)| v))
}
pub fn list_len(&self, list: impl AsRef<[u8]>) -> u64 {
self.store
.group(ns::LIST_ITEM, list.as_ref())
.map_or(0, |g| g.live)
}
pub fn list_items(&self, list: impl AsRef<[u8]>, limit: usize) -> Result<Vec<Vec<u8>>> {
Ok(list_scan(self.store, ns::LIST_ITEM, list.as_ref(), limit)?
.into_iter()
.map(|(_, _, v)| v)
.collect())
}
pub fn list_range(
&self,
list: impl AsRef<[u8]>,
from: u64,
limit: usize,
) -> Result<Vec<Vec<u8>>> {
let list = list.as_ref();
let mut out = Vec::new();
let Some(g) = self.store.group(ns::LIST_ITEM, list) else {
return Ok(out);
};
for seq in from.max(g.head)..g.next {
if out.len() >= limit {
break;
}
if let Some((_, v)) = self
.store
.get(ns::LIST_ITEM, &group_key(list, &seq.to_be_bytes())?)?
{
out.push(v);
}
}
Ok(out)
}
pub fn list_clear(&self, list: impl AsRef<[u8]>) -> Result<u64> {
let list = list.as_ref();
let mut tx = self.store.tx();
let mut n = 0;
if let Some(g) = tx.group(ns::LIST_ITEM, list) {
for seq in g.head..g.next {
if tx.delete(ns::LIST_ITEM, &group_key(list, &seq.to_be_bytes())?)? {
n += 1;
}
}
}
drop(tx);
self.store.finish();
Ok(n)
}
pub fn set_insert(&self, set: impl AsRef<[u8]>, member: impl AsRef<[u8]>) -> Result<bool> {
let key = group_key(set.as_ref(), member.as_ref())?;
let mut tx = self.store.tx();
if tx.contains(ns::SET_MEMBER, &key)? {
return Ok(false);
}
tx.put(ns::SET_MEMBER, &key, &[], now_ms())?;
drop(tx);
self.store.finish();
Ok(true)
}
pub fn set_contains(&self, set: impl AsRef<[u8]>, member: impl AsRef<[u8]>) -> Result<bool> {
let key = group_key(set.as_ref(), member.as_ref())?;
self.store.contains(ns::SET_MEMBER, &key)
}
pub fn set_remove(&self, set: impl AsRef<[u8]>, member: impl AsRef<[u8]>) -> Result<bool> {
let key = group_key(set.as_ref(), member.as_ref())?;
self.store.delete(ns::SET_MEMBER, &key)
}
pub fn set_len(&self, set: impl AsRef<[u8]>) -> u64 {
self.store
.group(ns::SET_MEMBER, set.as_ref())
.map_or(0, |g| g.live)
}
pub fn set_members(&self, set: impl AsRef<[u8]>) -> Result<Vec<Vec<u8>>> {
let prefix = group_key(set.as_ref(), &[])?;
Ok(self
.store
.keys(ns::SET_MEMBER, |k| k.starts_with(&prefix))?
.into_iter()
.map(|k| k[prefix.len()..].to_vec())
.collect())
}
pub fn set_clear(&self, set: impl AsRef<[u8]>) -> Result<u64> {
let set = set.as_ref();
let mut n = 0;
for m in self.set_members(set)? {
if self.set_remove(set, &m)? {
n += 1;
}
}
Ok(n)
}
}
fn now_ms() -> u64 {
to_ms(SystemTime::now())
}
pub(crate) fn list_push(tx: &mut Tx<'_>, n: u8, list: &[u8], item: &[u8], ts: u64) -> Result<u64> {
let seq = tx.group(n, list).map_or(0, |g| g.next);
tx.put(n, &group_key(list, &seq.to_be_bytes())?, item, ts)?;
Ok(seq)
}
fn list_front(tx: &Tx<'_>, n: u8, list: &[u8]) -> Result<Option<(u64, Vec<u8>)>> {
let Some(g) = tx.group(n, list) else {
return Ok(None);
};
for seq in g.head..g.next {
if let Some((_, v)) = tx.get(n, &group_key(list, &seq.to_be_bytes())?)? {
if seq != g.head {
tx.set_head(n, list, seq);
}
return Ok(Some((seq, v)));
}
}
Ok(None)
}
pub(crate) fn list_scan(
store: &Store,
n: u8,
list: &[u8],
limit: usize,
) -> Result<Vec<(u64, u64, Vec<u8>)>> {
let mut out = Vec::new();
let Some(g) = store.group(n, list) else {
return Ok(out);
};
for seq in g.head..g.next {
if out.len() >= limit || out.len() as u64 >= g.live {
break;
}
if let Some((ts, v)) = store.get(n, &group_key(list, &seq.to_be_bytes())?)? {
out.push((seq, ts, v));
}
}
Ok(out)
}