use crate::ds::map::Error;
use crate::format::Format;
use crate::{identifier::Identifier, AsConnection};
use rusqlite::{params, OptionalExtension};
use std::marker::PhantomData;
#[derive(Debug)]
pub struct Iter<'db, 'tbl, K, V, C>
where
K: Format,
V: Format,
C: AsConnection,
{
connection: C,
database: Identifier<'db>,
table: Identifier<'tbl>,
front: Option<K::Buffer>,
back: Option<K::Buffer>,
size: usize,
key_serializer: PhantomData<K>,
value_serializer: PhantomData<V>,
}
impl<'db, 'tbl, K, V, C> Iter<'db, 'tbl, K, V, C>
where
K: Format,
V: Format,
C: AsConnection,
{
pub fn new(
connection: C,
database: Identifier<'db>,
table: Identifier<'tbl>,
) -> rusqlite::Result<Self> {
let mut new = Self {
connection,
database,
table,
size: 0,
front: None,
back: None,
key_serializer: PhantomData,
value_serializer: PhantomData,
};
new.update_size()?;
Ok(new)
}
fn update_size(&mut self) -> rusqlite::Result<usize> {
self.size = self.select("COUNT(*)", "", |row| row.get(0))?;
Ok(self.size)
}
fn select<U, F>(&self, selection: &str, order: &str, f: F) -> rusqlite::Result<U>
where
F: FnOnce(&rusqlite::Row<'_>) -> rusqlite::Result<U>,
{
let database = &self.database;
let table = &self.table;
match (
self.front.as_ref(),
self.back.as_ref(),
) {
(None, None) => self
.connection
.as_connection()
.prepare_cached(&format!(
"SELECT {selection} FROM {database}.{table} {order} LIMIT 1"
))?
.query_row([], f),
(Some(front), None) => self
.connection
.as_connection()
.prepare_cached(&format!(
"SELECT {selection} FROM {database}.{table} WHERE key > ? {order} LIMIT 1"
))?
.query_row(params![front], f),
(None, Some(back)) => self
.connection
.as_connection()
.prepare_cached(&format!(
"SELECT {selection} FROM {database}.{table} WHERE key < ? {order} LIMIT 1"
))?
.query_row(params![back], f),
(Some(front), Some(back)) => self
.connection
.as_connection()
.prepare_cached(&format!(
"SELECT {selection} FROM {database}.{table} WHERE key > ? AND key < ? {order} LIMIT 1"
))?
.query_row(params![front, back], f),
}
}
}
impl<'db, 'tbl, K, V, C> Iterator for Iter<'db, 'tbl, K, V, C>
where
K: Format,
V: Format,
C: AsConnection,
{
type Item = Result<K::Out, Error<K, V>>;
fn next(&mut self) -> Option<Self::Item> {
let next: rusqlite::Result<Option<K::Buffer>> = self
.select("key", "ORDER BY key ASC", |row| row.get(0))
.optional();
match next {
Ok(Some(serialized)) => {
let ret = K::deserialize(&serialized).map_err(Error::KeyDeserialize);
self.front = Some(serialized);
Some(self.update_size().map_err(Into::into).and(ret))
}
Ok(None) => {
self.size = 0;
None
}
Err(e) => Some(Err(e.into())),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(self.size, Some(self.size))
}
}
impl<'db, 'tbl, K, V, C> DoubleEndedIterator for Iter<'db, 'tbl, K, V, C>
where
K: Format,
V: Format,
C: AsConnection,
{
fn next_back(&mut self) -> Option<Self::Item> {
let next: rusqlite::Result<Option<K::Buffer>> = self
.select("key", "ORDER BY key DESC", |row| row.get(0))
.optional();
match next {
Ok(Some(serialized)) => {
let ret = K::deserialize(&serialized).map_err(Error::KeyDeserialize);
self.back = Some(serialized);
Some(self.update_size().map_err(Into::into).and(ret))
}
Ok(None) => {
self.size = 0;
None
}
Err(e) => Some(Err(e.into())),
}
}
}