sqlite_collections/ds/map/iter/
key_value.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 (self.front.as_ref(), self.back.as_ref()) {
63            (None, None) => self
64                .connection
65                .as_connection()
66                .prepare_cached(&format!(
67                    "SELECT {selection} FROM {database}.{table} {order} LIMIT 1"
68                ))?
69                .query_row([], f),
70            (Some(front), None) => self
71                .connection
72                .as_connection()
73                .prepare_cached(&format!(
74                    "SELECT {selection} FROM {database}.{table} WHERE key > ? {order} LIMIT 1"
75                ))?
76                .query_row(params![front], f),
77            (None, Some(back)) => self
78                .connection
79                .as_connection()
80                .prepare_cached(&format!(
81                    "SELECT {selection} FROM {database}.{table} WHERE key < ? {order} LIMIT 1"
82                ))?
83                .query_row(params![back], f),
84            (Some(front), Some(back)) => self
85                .connection
86                .as_connection()
87                .prepare_cached(&format!(
88                    "SELECT {selection} FROM {database}.{table} WHERE key > ? AND key < ? {order} LIMIT 1"
89                ))?
90                .query_row(params![front, back], f),
91        }
92    }
93
94    fn inner_next(&mut self, key: &K::Buffer, value: &V::Buffer) -> <Self as Iterator>::Item {
95        let key = K::deserialize(key).map_err(Error::KeyDeserialize)?;
96        let value = V::deserialize(value).map_err(Error::ValueDeserialize)?;
97        Ok((key, value))
98    }
99}
100
101impl<'db, 'tbl, K, V, C> Iterator for Iter<'db, 'tbl, K, V, C>
102where
103    K: Format,
104    V: Format,
105    C: AsConnection,
106{
107    type Item = Result<(K::Out, V::Out), Error<K, V>>;
108
109    fn next(&mut self) -> Option<Self::Item> {
110        let next: rusqlite::Result<Option<(K::Buffer, V::Buffer)>> = self
111            .select("key, value", "ORDER BY key ASC", |row| {
112                Ok((row.get(0)?, row.get(1)?))
113            })
114            .optional();
115        match next {
116            Ok(Some((key, value))) => {
117                let res = self.inner_next(&key, &value);
118                self.front = Some(key);
119                Some(self.update_size().map_err(Into::into).and(res))
120            }
121            Ok(None) => {
122                self.size = 0;
123                None
124            }
125            Err(e) => Some(Err(e.into())),
126        }
127    }
128
129    /// return how many elements are in left in the iterator as of this call.
130    /// This can change during iteration if you are iterating in autocommit
131    /// mode, or hold the iterator across transactions. This is why this
132    /// iterator doesn't implement ExactSizeIterator
133    fn size_hint(&self) -> (usize, Option<usize>) {
134        (self.size, Some(self.size))
135    }
136}
137
138impl<'db, 'tbl, K, V, C> DoubleEndedIterator for Iter<'db, 'tbl, K, V, C>
139where
140    K: Format,
141    V: Format,
142    C: AsConnection,
143{
144    fn next_back(&mut self) -> Option<Self::Item> {
145        let next: rusqlite::Result<Option<(K::Buffer, V::Buffer)>> = self
146            .select("key, value", "ORDER BY key DESC", |row| {
147                Ok((row.get(0)?, row.get(1)?))
148            })
149            .optional();
150        match next {
151            Ok(Some((key, value))) => {
152                let res = self.inner_next(&key, &value);
153                self.back = Some(key);
154                Some(self.update_size().map_err(Into::into).and(res))
155            }
156            Ok(None) => {
157                self.size = 0;
158                None
159            }
160            Err(e) => Some(Err(e.into())),
161        }
162    }
163}