graphrecords-query 0.5.0

High-performance graph-based data records
Documentation
use super::{DynArityStream, DynIndex, DynIndexOwned, DynStream, DynValue};
use crate::{
    EvaluateOperand, IndexDomain, Operand, OperandContext, QueryResult,
    execution::{CacheableOperand, EvaluationCache},
    operands::{GroupOperand, Partition, PartitionOwned},
    optimizer::{Estimate, Estimated, PlanNode, Stats},
};
use graphrecords_core::GraphRecord;
use std::sync::Arc;

pub struct DynPayload {
    context: Arc<dyn OperandContext<Self>>,
}

pub enum DynYield<'a> {
    Lane(DynStream<'a>),
    Group(Partition<'a, DynIndex, DynIndex, DynPayload>),
}

pub enum DynTerminalArity<T> {
    MultipleOrdered(Vec<T>),
    MultipleUnordered(Vec<T>),
    Single(Option<T>),
    Definite(T),
}

pub enum DynTerminalLane {
    IndexedValue(DynTerminalArity<(DynIndexOwned, QueryResult<DynValue>)>),
    IndexedMask(DynTerminalArity<(DynIndexOwned, QueryResult<bool>)>),
    IndexedUnit(DynTerminalArity<(DynIndexOwned, QueryResult<()>)>),
    BareValue(DynTerminalArity<QueryResult<DynValue>>),
    BareMask(DynTerminalArity<QueryResult<bool>>),
}

pub enum DynTerminal {
    Lane(DynTerminalLane),
    Group(PartitionOwned<DynIndex, DynIndex, Self>),
}

impl<T> DynTerminalArity<T> {
    fn from_stream<'a, U: 'a>(stream: DynArityStream<'a, U>, function: impl Fn(U) -> T) -> Self {
        match stream {
            DynArityStream::MultipleOrdered(stream) => {
                Self::MultipleOrdered(stream.map(function).collect())
            }
            DynArityStream::MultipleUnordered(stream) => {
                Self::MultipleUnordered(stream.map(function).collect())
            }
            DynArityStream::Single(element) => Self::Single(element.map(function)),
            DynArityStream::Definite(element) => Self::Definite(function(element)),
        }
    }

    fn to_stream<'a, U: 'a>(&'a self, function: impl Fn(&'a T) -> U + 'a) -> DynArityStream<'a, U> {
        match self {
            Self::MultipleOrdered(elements) => {
                DynArityStream::MultipleOrdered(Box::new(elements.iter().map(function)))
            }
            Self::MultipleUnordered(elements) => {
                DynArityStream::MultipleUnordered(Box::new(elements.iter().map(function)))
            }
            Self::Single(element) => DynArityStream::Single(element.as_ref().map(function)),
            Self::Definite(element) => DynArityStream::Definite(function(element)),
        }
    }
}

impl DynTerminalLane {
    pub(crate) fn from_stream(stream: DynStream<'_>) -> Self {
        match stream {
            DynStream::IndexedValue(stream) => {
                Self::IndexedValue(DynTerminalArity::from_stream(stream, |(index, outcome)| {
                    (<DynIndex as IndexDomain>::to_owned(&index), outcome)
                }))
            }
            DynStream::IndexedMask(stream) => {
                Self::IndexedMask(DynTerminalArity::from_stream(stream, |(index, outcome)| {
                    (<DynIndex as IndexDomain>::to_owned(&index), outcome)
                }))
            }
            DynStream::IndexedUnit(stream) => {
                Self::IndexedUnit(DynTerminalArity::from_stream(stream, |(index, outcome)| {
                    (<DynIndex as IndexDomain>::to_owned(&index), outcome)
                }))
            }
            DynStream::BareValue(stream) => {
                Self::BareValue(DynTerminalArity::from_stream(stream, |outcome| outcome))
            }
            DynStream::BareMask(stream) => {
                Self::BareMask(DynTerminalArity::from_stream(stream, |outcome| outcome))
            }
        }
    }

    fn to_stream(&self) -> DynStream<'_> {
        match self {
            Self::IndexedValue(stream) => DynStream::IndexedValue(
                stream.to_stream(|(index, outcome)| (DynIndex::from_owned(index), outcome.clone())),
            ),
            Self::IndexedMask(stream) => DynStream::IndexedMask(
                stream.to_stream(|(index, outcome)| (DynIndex::from_owned(index), outcome.clone())),
            ),
            Self::IndexedUnit(stream) => DynStream::IndexedUnit(
                stream.to_stream(|(index, outcome)| (DynIndex::from_owned(index), outcome.clone())),
            ),
            Self::BareValue(stream) => DynStream::BareValue(stream.to_stream(QueryResult::clone)),
            Self::BareMask(stream) => DynStream::BareMask(stream.to_stream(QueryResult::clone)),
        }
    }
}

impl DynTerminal {
    pub(crate) fn from_yield(yielded: DynYield<'_>) -> Self {
        match yielded {
            DynYield::Lane(stream) => Self::Lane(DynTerminalLane::from_stream(stream)),
            DynYield::Group(partition) => Self::Group(
                <GroupOperand<DynIndex, DynIndex, DynPayload> as CacheableOperand>::into_cached(
                    partition,
                ),
            ),
        }
    }

    fn to_yield(&self) -> DynYield<'_> {
        match self {
            Self::Lane(stream) => DynYield::Lane(stream.to_stream()),
            Self::Group(partition) => DynYield::Group(
                <GroupOperand<DynIndex, DynIndex, DynPayload> as CacheableOperand>::from_cached(
                    partition,
                ),
            ),
        }
    }
}

impl Clone for DynPayload {
    fn clone(&self) -> Self {
        Self {
            context: Arc::clone(&self.context),
        }
    }
}

impl EvaluateOperand for DynPayload {
    type ReturnValue<'a>
        = DynYield<'a>
    where
        Self: 'a;

    fn evaluate<'a>(
        &'a self,
        graphrecord: &'a GraphRecord,
        cache: &'a EvaluationCache<'a>,
    ) -> QueryResult<Self::ReturnValue<'a>> {
        self.context.evaluate(graphrecord, cache)
    }
}

impl Estimated for DynPayload {
    fn estimate(&self, stats: &Stats) -> Estimate {
        self.context.estimate(stats)
    }
}

impl Operand for DynPayload {
    fn context(&self) -> &dyn OperandContext<Self> {
        self.context.as_ref()
    }

    fn as_plan_node(&self) -> &dyn PlanNode {
        self.context.as_ref()
    }

    fn from_context(context: Arc<dyn OperandContext<Self>>) -> Self {
        Self { context }
    }
}

impl CacheableOperand for DynPayload {
    type Cached = DynTerminal;

    fn into_cached(values: Self::ReturnValue<'_>) -> Self::Cached {
        DynTerminal::from_yield(values)
    }

    fn from_cached(cached: &Self::Cached) -> Self::ReturnValue<'_> {
        cached.to_yield()
    }
}