use crate::{
db::access::{
AccessPath, AccessPlan, ExecutableAccessPath, ExecutionPathPayload, 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()),
}
}
#[derive(Clone, Copy, Debug)]
pub(in crate::db) enum ExecutableAccessPathDispatch<'a, K> {
ByKey(&'a K),
ByKeys(&'a [K]),
KeyRange { start: &'a K, end: &'a K },
IndexPrefix,
IndexMultiLookup { value_count: usize },
IndexRange,
FullScan,
}
#[must_use]
pub(in crate::db) const fn dispatch_executable_access_path<'a, K>(
path: &'a ExecutableAccessPath<'a, K>,
) -> ExecutableAccessPathDispatch<'a, K> {
match path.payload() {
ExecutionPathPayload::ByKey(key) => ExecutableAccessPathDispatch::ByKey(*key),
ExecutionPathPayload::ByKeys(keys) => ExecutableAccessPathDispatch::ByKeys(keys),
ExecutionPathPayload::KeyRange { start, end } => {
ExecutableAccessPathDispatch::KeyRange { start, end }
}
ExecutionPathPayload::IndexPrefix => ExecutableAccessPathDispatch::IndexPrefix,
ExecutionPathPayload::IndexMultiLookup { value_count } => {
ExecutableAccessPathDispatch::IndexMultiLookup {
value_count: *value_count,
}
}
ExecutionPathPayload::IndexRange { .. } => ExecutableAccessPathDispatch::IndexRange,
ExecutionPathPayload::FullScan => ExecutableAccessPathDispatch::FullScan,
}
}