grus_lib/
reader.rs

1use std::str;
2use chrono::NaiveDateTime;
3use sanakirja::{Env, Error, LoadPage, Txn};
4use sanakirja::btree;
5use super::{invalid_data_error, StoreRw};
6use super::types::{RTriple, Session};
7
8pub type StoreReader<'env> = StoreRw<Txn<&'env Env>>;
9
10impl<T: LoadPage<Error = Error>> StoreRw<T> {
11	pub fn name(&self, id: u64) -> Result<Option<&str>, Error> {
12		match btree::get(&self.txn, &self.names, &id, None)? {
13			Some((&eid, name)) if eid == id => Ok(Some(str::from_utf8(name).map_err(|_| invalid_data_error())?)),
14			_ => Ok(None),
15		}
16	}
17
18	pub fn due_date(&self, id: u64) -> Result<Option<NaiveDateTime>, Error> {
19		match btree::get(&self.txn, &self.due_dates, &id, None)? {
20			Some((&eid, due_date)) if eid == id => Ok(Some(due_date.0)),
21			_ => Ok(None),
22		}
23	}
24
25	pub fn first_session(&self, id: u64) -> Result<Option<Session>, Error> {
26		match btree::get(&self.txn, &self.sessions, &id, None)? {
27			Some((&eid, &session)) if eid == id => Ok(Some(session)),
28			_ => Ok(None)
29		}
30	}
31
32	pub fn child_ids(&self, id: u64) -> Result<ChildIdIter<'_, T>, Error> {
33		Ok(ChildIdIter {
34			reader: self,
35			child_ids: ChildIds::new(self, id)?,
36		})
37	}
38
39	pub fn sessions<'r>(&'r self, id: u64) -> Result<impl Iterator<Item = Result<(&'r u64, &'r Session), Error>>, Error> {
40		let iter = btree::iter(&self.txn, &self.sessions, Some((&id, None)))?;
41		Ok(iter.take_while(move |entry| match entry {
42			Ok((&eid, _)) if eid > id => false,
43			_ => true,
44		}))
45	}
46
47	pub fn all_names<'r>(&'r self) -> Result<impl Iterator<Item = Result<(&'r u64, &'r str), Error>>, Error> {
48		Ok(
49			btree::iter(&self.txn, &self.names, None)?
50			.map(|item| item.and_then(|(id, name)| Ok((
51				id, str::from_utf8(name).map_err(|_| invalid_data_error())?
52			))))
53		)
54	}
55
56	pub fn all_sessions<'s>(&'s self) -> Result<impl Iterator<Item = Result<(&'s Session, &'s u64), Error>>, Error> {
57		btree::iter(&self.txn, &self.rsessions, None)
58	}
59
60	pub(crate) fn get_child(&self, id: u64) -> Result<Option<u64>, Error> {
61		match btree::get(&self.txn, &self.links, &id, None)? {
62			Some((&eid, &child)) if eid == id => Ok(Some(child)),
63			_ => Ok(None)
64		}
65	}
66
67	pub(crate) fn get_rt(&self, id: u64, pid: u64) -> Result<Option<RTriple>, Error> {
68		match btree::get(&self.txn, &self.rlinks, &id, Some(&RTriple { pid, next: 0, prev: 0 }))? {
69			Some((&eid, &rt)) if eid == id && rt.pid == pid => Ok(Some(rt)),
70			_ => Ok(None)
71		}
72	}
73}
74
75pub struct ChildIdIter<'reader, T: LoadPage<Error = Error>> {
76	reader: &'reader StoreRw<T>,
77	child_ids: ChildIds,
78}
79
80impl<'reader, T: LoadPage<Error = Error>> Iterator for ChildIdIter<'reader, T> {
81	type Item = Result<u64, Error>;
82
83	fn next(&mut self) -> Option<Self::Item> {
84		self.child_ids.next(self.reader).transpose()
85	}
86}
87
88pub(crate) struct ChildIds {
89	pid: u64,
90	id: u64,
91}
92
93impl ChildIds {
94	pub(crate) fn new<T: LoadPage<Error = Error>>(reader: &StoreRw<T>, id: u64) -> Result<Self, Error> {
95		Ok(ChildIds { pid: id, id: reader.get_child(id)?.unwrap_or(0) })
96	}
97
98	pub(crate) fn next<T: LoadPage<Error = Error>>(&mut self, reader: &StoreRw<T>) -> Result<Option<u64>, Error> {
99		let id = self.id;
100		if id == 0 { return Ok(None) };
101		let RTriple { next, .. } = reader.get_rt(id, self.pid)?.ok_or_else(invalid_data_error)?;
102		self.id = next;
103		Ok(Some(id))
104	}
105}