Skip to main content

hematite/catalog/
cursor.rs

1//! Relational cursors.
2
3use super::record::StoredRow;
4
5#[derive(Debug, Clone)]
6pub struct TableCursor {
7    rows: Vec<StoredRow>,
8    position: Option<usize>,
9}
10
11impl TableCursor {
12    pub fn new(mut rows: Vec<StoredRow>) -> Self {
13        rows.sort_by_key(|row| row.row_id);
14        Self {
15            rows,
16            position: None,
17        }
18    }
19
20    pub fn first(&mut self) -> bool {
21        if self.rows.is_empty() {
22            self.position = None;
23            return false;
24        }
25        self.position = Some(0);
26        true
27    }
28
29    pub fn next(&mut self) -> bool {
30        let Some(position) = self.position else {
31            return false;
32        };
33        let next = position + 1;
34        if next < self.rows.len() {
35            self.position = Some(next);
36            true
37        } else {
38            self.position = None;
39            false
40        }
41    }
42
43    pub fn seek_rowid(&mut self, rowid: u64) -> bool {
44        let found = self
45            .rows
46            .binary_search_by_key(&rowid, |row| row.row_id)
47            .ok();
48        self.position = found;
49        found.is_some()
50    }
51
52    pub fn current(&self) -> Option<&StoredRow> {
53        self.position.and_then(|index| self.rows.get(index))
54    }
55
56    pub fn is_valid(&self) -> bool {
57        self.current().is_some()
58    }
59}
60
61#[derive(Debug, Clone, PartialEq, Eq)]
62pub struct IndexEntry {
63    pub key: Vec<u8>,
64    pub row_id: u64,
65}
66
67#[derive(Debug, Clone)]
68pub struct IndexCursor {
69    entries: Vec<IndexEntry>,
70    position: Option<usize>,
71}
72
73impl IndexCursor {
74    pub fn new(mut entries: Vec<IndexEntry>) -> Self {
75        entries.sort_by(|l, r| l.key.cmp(&r.key).then(l.row_id.cmp(&r.row_id)));
76        Self {
77            entries,
78            position: None,
79        }
80    }
81
82    pub fn first(&mut self) -> bool {
83        if self.entries.is_empty() {
84            self.position = None;
85            return false;
86        }
87        self.position = Some(0);
88        true
89    }
90
91    pub fn next(&mut self) -> bool {
92        let Some(position) = self.position else {
93            return false;
94        };
95        let next = position + 1;
96        if next < self.entries.len() {
97            self.position = Some(next);
98            true
99        } else {
100            self.position = None;
101            false
102        }
103    }
104
105    pub fn seek_key(&mut self, key: &[u8]) -> bool {
106        let mut left = 0usize;
107        let mut right = self.entries.len();
108
109        while left < right {
110            let mid = left + (right - left) / 2;
111            if self.entries[mid].key.as_slice() < key {
112                left = mid + 1;
113            } else {
114                right = mid;
115            }
116        }
117
118        let found = self
119            .entries
120            .get(left)
121            .filter(|entry| entry.key.as_slice() == key)
122            .map(|_| left);
123        self.position = found;
124        found.is_some()
125    }
126
127    pub fn current(&self) -> Option<&IndexEntry> {
128        self.position.and_then(|index| self.entries.get(index))
129    }
130
131    pub fn is_valid(&self) -> bool {
132        self.current().is_some()
133    }
134}