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}