use super::ViewUpdate;
use crate::storage::warp_table::observed::*;
use crate::storage::warp_table::{Capacity, IndexKey};
pub struct ContinuousView<Id: IndexKey, Value: Clone + Eq> {
capacity: Capacity,
replica: Option<ViewReplica<Id, Value>>,
}
#[derive(Debug)]
pub enum ContinuousViewError {
Creation(ViewCreationError),
Apply(ViewApplyError),
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ContinuousViewStatus {
AwaitingBaseline,
Current,
BaselineRequired,
}
impl<Id: IndexKey, Value: Clone + Eq> ContinuousView<Id, Value> {
pub const fn new(capacity: Capacity) -> Self {
Self {
capacity,
replica: None,
}
}
pub fn copy(&self) -> Option<&ViewReplica<Id, Value>> {
self.replica.as_ref()
}
pub fn get(&self, id: Id) -> Option<&Value> {
self.replica.as_ref()?.get(id).map(|row| row.value)
}
pub fn rows(&self) -> impl Iterator<Item = (Id, &Value)> {
self.replica
.iter()
.flat_map(|replica| replica.rows())
.map(|row| (row.id, row.value))
}
pub fn status(&self) -> ContinuousViewStatus {
match self.replica.as_ref().map(ViewReplica::status) {
None | Some(ViewReplicaStatus::AwaitingBaseline) => {
ContinuousViewStatus::AwaitingBaseline
}
Some(ViewReplicaStatus::Current { .. }) => ContinuousViewStatus::Current,
Some(ViewReplicaStatus::BaselineRequired { .. }) => {
ContinuousViewStatus::BaselineRequired
}
}
}
pub fn connection(&self) -> ViewConnection {
self.replica
.as_ref()
.map_or(ViewConnection::Disconnected, ViewReplica::connection)
}
pub fn set_connection(&mut self, connection: ViewConnection) {
if let Some(replica) = &mut self.replica {
replica.set_connection(connection);
}
}
pub fn receive(
&mut self,
update: &ViewUpdate<Id, Value>,
) -> Result<ViewApplyOutcome, ContinuousViewError> {
match update {
ViewUpdate::Baseline { through, rows } => {
if self.replica.is_none() {
let mut replica =
ViewReplica::try_new(through.source, through.view, self.capacity)
.map_err(ContinuousViewError::Creation)?;
replica
.begin_baseline(*through, rows.len())
.map_err(ContinuousViewError::Apply)?;
replica
.baseline_chunk(*through, rows)
.map_err(ContinuousViewError::Apply)?;
let outcome = replica
.finish_baseline(*through)
.map_err(ContinuousViewError::Apply)?;
replica.set_connection(ViewConnection::Connected);
self.replica = Some(replica);
return Ok(outcome);
}
let replica = self.replica.as_mut().ok_or(ContinuousViewError::Apply(
ViewApplyError::BaselineNotStarted,
))?;
if replica
.begin_baseline(*through, rows.len())
.map_err(ContinuousViewError::Apply)?
== ViewApplyOutcome::Stale
{
return Ok(ViewApplyOutcome::Stale);
}
replica
.baseline_chunk(*through, rows)
.map_err(ContinuousViewError::Apply)?;
replica
.finish_baseline(*through)
.map_err(ContinuousViewError::Apply)
}
ViewUpdate::Changes {
base,
through,
changes,
} => match &mut self.replica {
Some(replica) => replica
.apply_changes(*base, *through, changes)
.map_err(ContinuousViewError::Apply),
None => Ok(ViewApplyOutcome::BaselineRequired),
},
}
}
pub fn reconnect(
&mut self,
update: &ViewUpdate<Id, Value>,
) -> Result<ViewApplyOutcome, ContinuousViewError> {
if !matches!(update, ViewUpdate::Baseline { .. }) {
return Ok(ViewApplyOutcome::BaselineRequired);
}
let mut replacement = Self::new(self.capacity);
let result = replacement.receive(update)?;
self.replica = replacement.replica;
Ok(result)
}
}