use crate::{DatabaseError, Ent, Id, ReadEnt};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct IncomingEdgeValue {
pub source: Id,
pub sort_key: Vec<u8>,
}
impl IncomingEdgeValue {
pub fn new(source: Id, sort_key: Vec<u8>) -> Self {
Self { source, sort_key }
}
pub fn with_dest(self, dest: Id) -> EdgeValue {
EdgeValue::new(self.source, self.sort_key, dest)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EdgeValue {
pub source: Id,
pub sort_key: Vec<u8>,
pub dest: Id,
}
impl EdgeValue {
pub fn new(source: Id, sort_key: Vec<u8>, dest: Id) -> Self {
Self {
source,
sort_key,
dest,
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum DraftError {
#[error("Source entity not found: {0}")]
SourceNotFound(Id),
#[error("Destination entity not found: {0}")]
DestNotFound(Id),
#[error("Invalid edge type: {0}")]
InvalidEdgeType(String),
#[error("Database error: {0}")]
Database(#[from] DatabaseError),
#[error("Validation failed: {0}")]
ValidationFailed(String),
}
pub trait EdgeDraft: PartialEq {
fn check<T: ReadEnt>(
self,
txn: &T,
) -> Result<Vec<IncomingEdgeValue>, DraftError>;
}
pub trait IncomingEdgeProvider<E: Ent + ?Sized> {
type Draft: EdgeDraft;
fn draft(ent: &E) -> Self::Draft;
}
pub fn check_incoming_edges<E, T>(
ent: &E,
txn: &T,
) -> Result<Vec<EdgeValue>, DraftError>
where
E: Ent,
T: ReadEnt,
{
let dest = ent.id();
Ok(E::EdgeProvider::draft(ent)
.check(txn)?
.into_iter()
.map(|edge| edge.with_dest(dest))
.collect())
}
impl<E: Ent, T1, T2> IncomingEdgeProvider<E> for (T1, T2)
where
T1: IncomingEdgeProvider<E>,
T2: IncomingEdgeProvider<E>,
{
type Draft = (T1::Draft, T2::Draft);
fn draft(ent: &E) -> Self::Draft {
(T1::draft(ent), T2::draft(ent))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NullEdgeDraft;
impl EdgeDraft for NullEdgeDraft {
fn check<T: ReadEnt>(
self,
_txn: &T,
) -> Result<Vec<IncomingEdgeValue>, DraftError> {
Ok(Vec::new())
}
}
pub struct NullEdgeProvider;
impl<E: Ent> IncomingEdgeProvider<E> for NullEdgeProvider {
type Draft = NullEdgeDraft;
fn draft(_ent: &E) -> Self::Draft {
NullEdgeDraft
}
}
impl<T1, T2> EdgeDraft for (T1, T2)
where
T1: EdgeDraft,
T2: EdgeDraft,
{
fn check<Trans: ReadEnt>(
self,
txn: &Trans,
) -> Result<Vec<IncomingEdgeValue>, DraftError> {
let (t1, t2) = self;
let mut edges = t1.check(txn)?;
edges.extend(t2.check(txn)?);
Ok(edges)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_edge_value_creation() {
let edge = EdgeValue::new(1, b"connects_to".to_vec(), 2);
assert_eq!(edge.source, 1);
assert_eq!(edge.sort_key, b"connects_to");
assert_eq!(edge.dest, 2);
}
#[test]
fn test_incoming_edge_value_creation() {
let edge = IncomingEdgeValue::new(1, b"connects_to".to_vec());
assert_eq!(edge.source, 1);
assert_eq!(edge.sort_key, b"connects_to");
}
}