use crate::{
db::{
cursor::IndexScanContinuationInput,
data::{DataKey, RawDataKey},
direction::Direction,
executor::{LoweredIndexPrefixSpec, LoweredIndexRangeSpec, LoweredKey},
index::{IndexDataKeyScanChunk, predicate::IndexPredicateExecution},
registry::StoreHandle,
},
error::InternalError,
model::index::IndexModel,
types::EntityTag,
};
use std::ops::Bound;
pub(in crate::db::executor) struct PrimaryScan;
impl PrimaryScan {
pub(in crate::db::executor) fn decode_data_key(
raw: &RawDataKey,
) -> Result<DataKey, InternalError> {
DataKey::try_from_raw(raw).map_err(|err| {
InternalError::identity_corruption(format!("failed to decode data key: {err}"))
})
}
}
pub(in crate::db::executor) struct IndexScan;
impl IndexScan {
pub(in crate::db::executor) fn prefix_structural(
store: StoreHandle,
entity_tag: EntityTag,
spec: &LoweredIndexPrefixSpec,
direction: Direction,
limit: usize,
predicate_execution: Option<IndexPredicateExecution<'_>>,
) -> Result<Vec<DataKey>, InternalError> {
Self::resolve_limited(
store,
entity_tag,
spec.index(),
spec.lower(),
spec.upper(),
IndexScanContinuationInput::new(None, direction),
limit,
predicate_execution,
)
}
pub(in crate::db::executor) fn range_structural(
store: StoreHandle,
entity_tag: EntityTag,
spec: &LoweredIndexRangeSpec,
continuation: IndexScanContinuationInput<'_>,
limit: usize,
predicate_execution: Option<IndexPredicateExecution<'_>>,
) -> Result<Vec<DataKey>, InternalError> {
Self::resolve_limited(
store,
entity_tag,
spec.index(),
spec.lower(),
spec.upper(),
continuation,
limit,
predicate_execution,
)
}
#[expect(clippy::too_many_arguments)]
pub(in crate::db::executor) fn chunk_structural(
store: StoreHandle,
entity_tag: EntityTag,
index: &IndexModel,
lower: &Bound<LoweredKey>,
upper: &Bound<LoweredKey>,
continuation: IndexScanContinuationInput<'_>,
max_entries: usize,
output_limit: Option<usize>,
) -> Result<IndexDataKeyScanChunk, InternalError> {
Self::resolve_chunk(
store,
entity_tag,
index,
lower,
upper,
continuation,
max_entries,
output_limit,
)
}
#[expect(clippy::too_many_arguments)]
fn resolve_limited(
store: StoreHandle,
entity_tag: EntityTag,
index: &IndexModel,
lower: &Bound<LoweredKey>,
upper: &Bound<LoweredKey>,
continuation: IndexScanContinuationInput<'_>,
limit: usize,
predicate_execution: Option<IndexPredicateExecution<'_>>,
) -> Result<Vec<DataKey>, InternalError> {
let keys = store.with_index(|index_store| {
index_store.resolve_data_values_in_raw_range_limited(
entity_tag,
index,
(lower, upper),
continuation,
limit,
predicate_execution,
)
})?;
Ok(keys)
}
#[expect(clippy::too_many_arguments)]
fn resolve_chunk(
store: StoreHandle,
entity_tag: EntityTag,
index: &IndexModel,
lower: &Bound<LoweredKey>,
upper: &Bound<LoweredKey>,
continuation: IndexScanContinuationInput<'_>,
max_entries: usize,
output_limit: Option<usize>,
) -> Result<IndexDataKeyScanChunk, InternalError> {
let chunk = store.with_index(|index_store| {
index_store.resolve_data_values_in_raw_range_chunk(
entity_tag,
index,
(lower, upper),
continuation,
max_entries,
output_limit,
)
})?;
Ok(chunk)
}
}