use crate::{
db::access::{
AccessPathKind,
execution_contract::{ExecutionBounds, ExecutionPathPayload},
},
model::index::IndexModel,
value::Value,
};
use std::ops::Bound;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db) struct ExecutableAccessPath<'a, K> {
bounds: ExecutionBounds,
payload: ExecutionPathPayload<'a, K>,
}
impl<'a, K> ExecutableAccessPath<'a, K> {
#[must_use]
pub(in crate::db) const fn new(
bounds: ExecutionBounds,
payload: ExecutionPathPayload<'a, K>,
) -> Self {
Self { bounds, payload }
}
#[must_use]
pub(in crate::db) const fn payload(&self) -> &ExecutionPathPayload<'a, K> {
&self.payload
}
#[must_use]
pub(in crate::db) const fn kind(&self) -> AccessPathKind {
match self.payload {
ExecutionPathPayload::ByKey(_) => AccessPathKind::ByKey,
ExecutionPathPayload::ByKeys(_) => AccessPathKind::ByKeys,
ExecutionPathPayload::KeyRange { .. } => AccessPathKind::KeyRange,
ExecutionPathPayload::IndexPrefix => AccessPathKind::IndexPrefix,
ExecutionPathPayload::IndexMultiLookup { .. } => AccessPathKind::IndexMultiLookup,
ExecutionPathPayload::IndexRange { .. } => AccessPathKind::IndexRange,
ExecutionPathPayload::FullScan => AccessPathKind::FullScan,
}
}
#[must_use]
pub(in crate::db) const fn index_range_semantic_bounds(
&self,
) -> Option<(&'a [Value], &'a Bound<Value>, &'a Bound<Value>)> {
match self.payload {
ExecutionPathPayload::IndexRange {
prefix_values,
lower,
upper,
} => Some((prefix_values, lower, upper)),
ExecutionPathPayload::ByKey(_)
| ExecutionPathPayload::ByKeys(_)
| ExecutionPathPayload::KeyRange { .. }
| ExecutionPathPayload::IndexPrefix
| ExecutionPathPayload::IndexMultiLookup { .. }
| ExecutionPathPayload::FullScan => None,
}
}
#[must_use]
pub(in crate::db) const fn index_prefix_details(&self) -> Option<(IndexModel, usize)> {
match self.bounds {
ExecutionBounds::IndexPrefix { index, prefix_len } => Some((index, prefix_len)),
ExecutionBounds::Unbounded
| ExecutionBounds::PrimaryKeyRange
| ExecutionBounds::IndexRange { .. } => None,
}
}
#[must_use]
pub(in crate::db) const fn index_range_details(&self) -> Option<(IndexModel, usize)> {
match self.bounds {
ExecutionBounds::IndexRange { index, prefix_len } => Some((index, prefix_len)),
ExecutionBounds::Unbounded
| ExecutionBounds::PrimaryKeyRange
| ExecutionBounds::IndexPrefix { .. } => None,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) enum ExecutableAccessNode<'a, K> {
Path(ExecutableAccessPath<'a, K>),
Union(Vec<ExecutableAccessPlan<'a, K>>),
Intersection(Vec<ExecutableAccessPlan<'a, K>>),
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) struct ExecutableAccessPlan<'a, K> {
node: ExecutableAccessNode<'a, K>,
}
impl<'a, K> ExecutableAccessPlan<'a, K> {
#[must_use]
pub(in crate::db) const fn for_path(path: ExecutableAccessPath<'a, K>) -> Self {
Self {
node: ExecutableAccessNode::Path(path),
}
}
#[must_use]
pub(in crate::db) const fn union(children: Vec<Self>) -> Self {
Self {
node: ExecutableAccessNode::Union(children),
}
}
#[must_use]
pub(in crate::db) const fn intersection(children: Vec<Self>) -> Self {
Self {
node: ExecutableAccessNode::Intersection(children),
}
}
#[must_use]
pub(in crate::db) const fn node(&self) -> &ExecutableAccessNode<'a, K> {
&self.node
}
#[must_use]
pub(in crate::db) const fn as_path(&self) -> Option<&ExecutableAccessPath<'a, K>> {
match &self.node {
ExecutableAccessNode::Path(path) => Some(path),
ExecutableAccessNode::Union(_) | ExecutableAccessNode::Intersection(_) => None,
}
}
}