sqlite_collections/ds/map/iter/
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
95impl<'db, 'tbl, K, V, C> Iterator for Iter<'db, 'tbl, K, V, C>
96where
97    K: Format,
98    V: Format,
99    C: AsConnection,
100{
101    type Item = Result<V::Out, Error<K, V>>;
102
103    fn next(&mut self) -> Option<Self::Item> {
104        let next: rusqlite::Result<Option<(K::Buffer, V::Buffer)>> = self
105            .select("key, value", "ORDER BY key ASC", |row| {
106                Ok((row.get(0)?, row.get(1)?))
107            })
108            .optional();
109        match next {
110            Ok(Some((key, value))) => {
111                let ret = V::deserialize(&value).map_err(Error::ValueDeserialize);
112                self.front = Some(key);
113                Some(self.update_size().map_err(Into::into).and(ret))
114            }
115            Ok(None) => {
116                self.size = 0;
117                None
118            }
119            Err(e) => Some(Err(e.into())),
120        }
121    }
122
123    /// return how many elements are in left in the iterator as of this call.
124    /// This can change during iteration if you are iterating in autocommit
125    /// mode, or hold the iterator across transactions. This is why this
126    /// iterator doesn't implement ExactSizeIterator
127    fn size_hint(&self) -> (usize, Option<usize>) {
128        (self.size, Some(self.size))
129    }
130}
131
132impl<'db, 'tbl, K, V, C> DoubleEndedIterator for Iter<'db, 'tbl, K, V, C>
133where
134    K: Format,
135    V: Format,
136    C: AsConnection,
137{
138    fn next_back(&mut self) -> Option<Self::Item> {
139        let next: rusqlite::Result<Option<(K::Buffer, V::Buffer)>> = self
140            .select("key, value", "ORDER BY key DESC", |row| {
141                Ok((row.get(0)?, row.get(1)?))
142            })
143            .optional();
144        match next {
145            Ok(Some((key, value))) => {
146                let ret = V::deserialize(&value).map_err(Error::ValueDeserialize);
147                self.back = Some(key);
148                Some(self.update_size().map_err(Into::into).and(ret))
149            }
150            Ok(None) => {
151                self.size = 0;
152                None
153            }
154            Err(e) => Some(Err(e.into())),
155        }
156    }
157}