use super::Error;
use crate::serializer::Serializer;
use crate::{identifier::Identifier, AsConnection};
use rusqlite::{params, OptionalExtension};
use std::{borrow::Borrow, marker::PhantomData};
#[derive(Debug)]
pub struct Iter<'db, 'tbl, S, C>
where
S: Serializer,
C: AsConnection,
{
connection: C,
database: Identifier<'db>,
table: Identifier<'tbl>,
front: Option<S::Buffer>,
back: Option<S::Buffer>,
size: usize,
serializer: PhantomData<S>,
}
impl<'db, 'tbl, S, C> Iter<'db, 'tbl, S, C>
where
S: Serializer,
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,
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().map(Borrow::borrow),
self.back.as_ref().map(Borrow::borrow),
) {
(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, S, C> Iterator for Iter<'db, 'tbl, S, C>
where
S: Serializer,
C: AsConnection,
{
type Item = Result<S::Target, Error<S>>;
fn next(&mut self) -> Option<Self::Item> {
let next: rusqlite::Result<Option<S::Buffer>> = self
.select("key", "ORDER BY key ASC", |row| row.get(0))
.optional();
match next {
Ok(Some(serialized)) => {
let ret = match S::deserialize(serialized.borrow()) {
Ok(value) => Some(Ok(value)),
Err(e) => Some(Err(Error::Deserialize(e))),
};
self.front = Some(serialized);
if let Err(e) = self.update_size() {
return Some(Err(e.into()));
}
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, S, C> DoubleEndedIterator for Iter<'db, 'tbl, S, C>
where
S: Serializer,
C: AsConnection,
{
fn next_back(&mut self) -> Option<Self::Item> {
let next: rusqlite::Result<Option<S::Buffer>> = self
.select("key", "ORDER BY key DESC", |row| row.get(0))
.optional();
match next {
Ok(Some(serialized)) => {
let ret = match S::deserialize(serialized.borrow()) {
Ok(value) => Some(Ok(value)),
Err(e) => Some(Err(Error::Deserialize(e))),
};
self.back = Some(serialized);
if let Err(e) = self.update_size() {
return Some(Err(e.into()));
}
ret
}
Ok(None) => {
self.size = 0;
None
}
Err(e) => Some(Err(e.into())),
}
}
}