sqlite_collections/ds/map/iter/
key.rs

1use crate::ds::map::Error;
2use crate::format::Format;
3use crate::{identifier::Identifier, AsConnection};
4use rusqlite::{params, OptionalExtension};
5
6use std::marker::PhantomData;
7
8#[derive(Debug)]
9pub struct Iter<'db, 'tbl, K, V, C>
10where
11    K: Format,
12    V: Format,
13    C: AsConnection,
14{
15    connection: C,
16    database: Identifier<'db>,
17    table: Identifier<'tbl>,
18    front: Option<K::Buffer>,
19    back: Option<K::Buffer>,
20    size: usize,
21    key_serializer: PhantomData<K>,
22    value_serializer: PhantomData<V>,
23}
24
25impl<'db, 'tbl, K, V, C> Iter<'db, 'tbl, K, V, C>
26where
27    K: Format,
28    V: Format,
29    C: AsConnection,
30{
31    pub fn new(
32        connection: C,
33        database: Identifier<'db>,
34        table: Identifier<'tbl>,
35    ) -> rusqlite::Result<Self> {
36        let mut new = Self {
37            connection,
38            database,
39            table,
40            size: 0,
41            front: None,
42            back: None,
43            key_serializer: PhantomData,
44            value_serializer: PhantomData,
45        };
46        new.update_size()?;
47        Ok(new)
48    }
49
50    fn update_size(&mut self) -> rusqlite::Result<usize> {
51        self.size = self.select("COUNT(*)", "", |row| row.get(0))?;
52        Ok(self.size)
53    }
54
55    fn select<U, F>(&self, selection: &str, order: &str, f: F) -> rusqlite::Result<U>
56    where
57        F: FnOnce(&rusqlite::Row<'_>) -> rusqlite::Result<U>,
58    {
59        let database = &self.database;
60        let table = &self.table;
61
62        match (
63            self.front.as_ref(),
64            self.back.as_ref(),
65        ) {
66            (None, None) => self
67                .connection
68                .as_connection()
69                .prepare_cached(&format!(
70                    "SELECT {selection} FROM {database}.{table} {order} LIMIT 1"
71                ))?
72                .query_row([], f),
73            (Some(front), None) => self
74                .connection
75                .as_connection()
76                .prepare_cached(&format!(
77                    "SELECT {selection} FROM {database}.{table} WHERE key > ? {order} LIMIT 1"
78                ))?
79                .query_row(params![front], f),
80            (None, Some(back)) => self
81                .connection
82                .as_connection()
83                .prepare_cached(&format!(
84                    "SELECT {selection} FROM {database}.{table} WHERE key < ? {order} LIMIT 1"
85                ))?
86                .query_row(params![back], f),
87            (Some(front), Some(back)) => self
88                .connection
89                .as_connection()
90                .prepare_cached(&format!(
91                    "SELECT {selection} FROM {database}.{table} WHERE key > ? AND key < ? {order} LIMIT 1"
92                ))?
93                .query_row(params![front, back], f),
94        }
95    }
96}
97
98impl<'db, 'tbl, K, V, C> Iterator for Iter<'db, 'tbl, K, V, C>
99where
100    K: Format,
101    V: Format,
102    C: AsConnection,
103{
104    type Item = Result<K::Out, Error<K, V>>;
105
106    fn next(&mut self) -> Option<Self::Item> {
107        let next: rusqlite::Result<Option<K::Buffer>> = self
108            .select("key", "ORDER BY key ASC", |row| row.get(0))
109            .optional();
110        match next {
111            Ok(Some(serialized)) => {
112                let ret = K::deserialize(&serialized).map_err(Error::KeyDeserialize);
113                self.front = Some(serialized);
114                Some(self.update_size().map_err(Into::into).and(ret))
115            }
116            Ok(None) => {
117                self.size = 0;
118                None
119            }
120            Err(e) => Some(Err(e.into())),
121        }
122    }
123
124    /// return how many elements are in left in the iterator as of this call.
125    /// This can change during iteration if you are iterating in autocommit
126    /// mode, or hold the iterator across transactions. This is why this
127    /// iterator doesn't implement ExactSizeIterator
128    fn size_hint(&self) -> (usize, Option<usize>) {
129        (self.size, Some(self.size))
130    }
131}
132
133impl<'db, 'tbl, K, V, C> DoubleEndedIterator for Iter<'db, 'tbl, K, V, C>
134where
135    K: Format,
136    V: Format,
137    C: AsConnection,
138{
139    fn next_back(&mut self) -> Option<Self::Item> {
140        let next: rusqlite::Result<Option<K::Buffer>> = self
141            .select("key", "ORDER BY key DESC", |row| row.get(0))
142            .optional();
143        match next {
144            Ok(Some(serialized)) => {
145                let ret = K::deserialize(&serialized).map_err(Error::KeyDeserialize);
146                self.back = Some(serialized);
147                Some(self.update_size().map_err(Into::into).and(ret))
148            }
149            Ok(None) => {
150                self.size = 0;
151                None
152            }
153            Err(e) => Some(Err(e.into())),
154        }
155    }
156}