use crate::{
db::access::{AccessPath, AccessPlan, SemanticIndexRangeSpec},
model::index::IndexModel,
value::Value,
};
#[derive(Clone, Copy, Debug)]
pub(in crate::db) enum AccessPathDispatch<'a, K> {
ByKey(&'a K),
ByKeys(&'a [K]),
KeyRange {
start: &'a K,
end: &'a K,
},
IndexPrefix {
index: IndexModel,
values: &'a [Value],
},
IndexMultiLookup {
index: IndexModel,
values: &'a [Value],
},
IndexRange {
spec: &'a SemanticIndexRangeSpec,
},
FullScan,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::db) enum AccessPathKind {
ByKey,
ByKeys,
KeyRange,
IndexPrefix,
IndexMultiLookup,
IndexRange,
FullScan,
}
impl<K> AccessPathDispatch<'_, K> {
#[must_use]
pub(in crate::db) const fn kind(self) -> AccessPathKind {
match self {
Self::ByKey(_) => AccessPathKind::ByKey,
Self::ByKeys(_) => AccessPathKind::ByKeys,
Self::KeyRange { .. } => AccessPathKind::KeyRange,
Self::IndexPrefix { .. } => AccessPathKind::IndexPrefix,
Self::IndexMultiLookup { .. } => AccessPathKind::IndexMultiLookup,
Self::IndexRange { .. } => AccessPathKind::IndexRange,
Self::FullScan => AccessPathKind::FullScan,
}
}
}
impl AccessPathKind {
#[must_use]
pub(in crate::db) const fn supports_pk_stream_access(self) -> bool {
matches!(self, Self::KeyRange | Self::FullScan)
}
#[must_use]
pub(in crate::db) const fn supports_reverse_traversal(self) -> bool {
!matches!(self, Self::ByKeys)
}
#[must_use]
pub(in crate::db) const fn supports_count_pushdown_shape(self) -> bool {
matches!(self, Self::KeyRange | Self::FullScan)
}
#[must_use]
pub(in crate::db) const fn supports_primary_scan_fetch_hint(self) -> bool {
matches!(self, Self::ByKey | Self::KeyRange | Self::FullScan)
}
#[must_use]
pub(in crate::db) const fn is_key_direct_access(self) -> bool {
matches!(self, Self::ByKey | Self::ByKeys)
}
#[must_use]
pub(in crate::db) const fn supports_bytes_terminal_primary_key_window(self) -> bool {
matches!(self, Self::FullScan | Self::KeyRange)
}
#[must_use]
pub(in crate::db) const fn supports_bytes_terminal_ordered_key_stream_window(self) -> bool {
matches!(
self,
Self::ByKey
| Self::ByKeys
| Self::IndexPrefix
| Self::IndexMultiLookup
| Self::IndexRange
)
}
#[must_use]
pub(in crate::db) const fn supports_count_terminal_primary_key_existing_rows(self) -> bool {
matches!(self, Self::ByKey | Self::ByKeys)
}
#[must_use]
pub(in crate::db) const fn requires_top_n_seek_lookahead(self) -> bool {
matches!(self, Self::ByKeys | Self::IndexMultiLookup)
}
}
#[must_use]
pub(in crate::db) const fn dispatch_access_path<K>(
path: &AccessPath<K>,
) -> AccessPathDispatch<'_, K> {
match path {
AccessPath::ByKey(key) => AccessPathDispatch::ByKey(key),
AccessPath::ByKeys(keys) => AccessPathDispatch::ByKeys(keys.as_slice()),
AccessPath::KeyRange { start, end } => AccessPathDispatch::KeyRange { start, end },
AccessPath::IndexPrefix { index, values } => AccessPathDispatch::IndexPrefix {
index: *index,
values: values.as_slice(),
},
AccessPath::IndexMultiLookup { index, values } => AccessPathDispatch::IndexMultiLookup {
index: *index,
values: values.as_slice(),
},
AccessPath::IndexRange { spec } => AccessPathDispatch::IndexRange { spec },
AccessPath::FullScan => AccessPathDispatch::FullScan,
}
}
#[derive(Clone, Copy, Debug)]
pub(in crate::db) enum AccessPlanDispatch<'a, K> {
Path(AccessPathDispatch<'a, K>),
Union(&'a [AccessPlan<K>]),
Intersection(&'a [AccessPlan<K>]),
}
#[must_use]
pub(in crate::db) fn dispatch_access_plan<K>(plan: &AccessPlan<K>) -> AccessPlanDispatch<'_, K> {
match plan {
AccessPlan::Path(path) => AccessPlanDispatch::Path(dispatch_access_path(path.as_ref())),
AccessPlan::Union(children) => AccessPlanDispatch::Union(children.as_slice()),
AccessPlan::Intersection(children) => AccessPlanDispatch::Intersection(children.as_slice()),
}
}