use crate::cow::CowSegment;
use crate::{
canonical::{CanonicalNodeIterator, CanonicalRelationshipIterator, CanonicalSegmentError},
NodeId, NodeRecord, RelId, RelRecord,
};
use hawdb_core::{HawDBError, Result};
use std::collections::BTreeSet;
use std::iter::Peekable;
mod checkpoint;
mod cursor;
pub(crate) use cursor::Cursor as CheckpointOverlayCursor;
#[cfg(test)]
mod tests;
pub(crate) use checkpoint::{CheckpointOverlayIterator, CheckpointRecordRef};
pub struct GraphNodeIterator {
inner: OverlayIterator<NodeRecord, CanonicalNodeIterator>,
}
impl GraphNodeIterator {
#[doc(hidden)]
pub fn checkpoint_steps(mut self) -> impl Iterator<Item = Result<Option<NodeRecord>>> {
std::iter::from_fn(move || self.inner.next_step())
}
}
impl Iterator for GraphNodeIterator {
type Item = Result<NodeRecord>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
pub struct GraphRelationshipIterator {
inner: OverlayIterator<RelRecord, CanonicalRelationshipIterator>,
}
impl GraphRelationshipIterator {
#[doc(hidden)]
pub fn checkpoint_steps(mut self) -> impl Iterator<Item = Result<Option<RelRecord>>> {
std::iter::from_fn(move || self.inner.next_step())
}
}
impl Iterator for GraphRelationshipIterator {
type Item = Result<RelRecord>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
pub fn node_records(
base: Option<CanonicalNodeIterator>,
delta: Vec<NodeRecord>,
tombstones: CowSegment<BTreeSet<NodeId>>,
) -> GraphNodeIterator {
GraphNodeIterator {
inner: OverlayIterator::new(base, delta, tombstones),
}
}
pub fn relationship_records(
base: Option<CanonicalRelationshipIterator>,
delta: Vec<RelRecord>,
tombstones: CowSegment<BTreeSet<RelId>>,
) -> GraphRelationshipIterator {
GraphRelationshipIterator {
inner: OverlayIterator::new(base, delta, tombstones),
}
}
pub(crate) trait OverlayRecord {
type Id: Copy + Ord;
fn id(&self) -> Self::Id;
}
impl OverlayRecord for NodeRecord {
type Id = NodeId;
fn id(&self) -> NodeId {
self.id
}
}
impl OverlayRecord for RelRecord {
type Id = RelId;
fn id(&self) -> RelId {
self.id
}
}
struct OverlayIterator<R: OverlayRecord, B: Iterator> {
base: Option<Peekable<B>>,
delta: Peekable<std::vec::IntoIter<R>>,
tombstones: CowSegment<BTreeSet<R::Id>>,
}
impl<R: OverlayRecord, B: Iterator> OverlayIterator<R, B> {
fn new(base: Option<B>, delta: Vec<R>, tombstones: CowSegment<BTreeSet<R::Id>>) -> Self {
Self {
base: base.map(Iterator::peekable),
delta: delta.into_iter().peekable(),
tombstones,
}
}
}
impl<R: OverlayRecord, B: Iterator<Item = std::result::Result<R, CanonicalSegmentError>>>
OverlayIterator<R, B>
{
fn next_base(&mut self) -> Result<R> {
self.base
.as_mut()
.and_then(Iterator::next)
.expect("peeked base record exists")
.map_err(|error| HawDBError::StorageIntegrity(error.to_string()))
}
}
impl<R: OverlayRecord, B: Iterator<Item = std::result::Result<R, CanonicalSegmentError>>>
OverlayIterator<R, B>
{
fn next_step(&mut self) -> Option<Result<Option<R>>> {
let base_id = match self.base.as_mut().and_then(|base| base.peek()) {
Some(Ok(record)) => Some(record.id()),
Some(Err(_)) => return Some(self.next_base().map(Some)),
None => None,
};
let delta_id = self.delta.peek().map(OverlayRecord::id);
let record = match (base_id, delta_id) {
(None, None) => return None,
(Some(base_id), Some(delta_id)) if base_id == delta_id => {
if let Err(error) = self.next_base() {
return Some(Err(error));
}
Ok(self.delta.next().expect("matching delta record exists"))
}
(None, Some(_)) => Ok(self.delta.next().expect("peeked delta record exists")),
(Some(base_id), Some(delta_id)) if base_id > delta_id => {
Ok(self.delta.next().expect("peeked delta record exists"))
}
(Some(_), _) => self.next_base(),
};
Some(record.map(|record| {
if self.tombstones.contains(&record.id()) {
None
} else {
Some(record)
}
}))
}
}
impl<R: OverlayRecord, B: Iterator<Item = std::result::Result<R, CanonicalSegmentError>>> Iterator
for OverlayIterator<R, B>
{
type Item = Result<R>;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.next_step()? {
Ok(None) => continue,
Ok(Some(record)) => return Some(Ok(record)),
Err(error) => return Some(Err(error)),
}
}
}
}