#[cfg(test)]
mod tests;
mod boundary;
mod continuation;
mod error;
mod runtime;
mod signature;
mod spine;
mod string;
mod validated;
mod token;
use crate::db::{
direction::Direction,
query::plan::{
OrderSpec, validate::CursorOrderPlanShapeError, validate_cursor_order_plan_shape,
},
};
pub(in crate::db) use boundary::apply_order_direction;
pub(in crate::db::cursor) use boundary::validate_cursor_window_offset;
pub(in crate::db) use boundary::{CursorBoundary, CursorBoundarySlot};
pub(in crate::db) use continuation::{
IndexScanContinuationInput, effective_keep_count_for_limit, effective_page_offset_for_window,
};
pub(crate) use error::CursorPlanError;
#[cfg(test)]
pub(crate) use error::CursorSignaturePrefix;
pub(in crate::db) use runtime::{ContinuationKeyRef, ContinuationRuntime};
#[expect(unreachable_pub)]
pub use signature::ContinuationSignature;
pub(crate) use string::CursorDecodeError;
use string::decode_cursor;
#[cfg(any(test, feature = "sql"))]
pub(in crate::db) use string::encode_cursor;
#[cfg(test)]
pub(in crate::db) use string::encode_grouped_cursor_token;
pub(in crate::db) use token::{GroupedContinuationToken, TokenWireError};
pub(in crate::db) use validated::ValidatedGroupedCursor;
pub(in crate::db) fn decode_optional_cursor_token(
cursor_token: Option<&str>,
) -> Result<Option<Vec<u8>>, CursorPlanError> {
cursor_token
.map(|token| decode_cursor(token).map_err(CursorPlanError::invalid_continuation_cursor))
.transpose()
}
pub(in crate::db) fn decode_optional_grouped_cursor_token(
cursor_token: Option<&str>,
) -> Result<Option<GroupedContinuationToken>, CursorPlanError> {
decode_optional_cursor_token(cursor_token)?
.map(|bytes| {
GroupedContinuationToken::decode(bytes.as_slice())
.map_err(CursorPlanError::from_token_wire_error)
})
.transpose()
}
#[cfg(test)]
pub(in crate::db) fn prepare_grouped_cursor(
entity_path: &'static str,
order: Option<&OrderSpec>,
direction: Direction,
continuation_signature: ContinuationSignature,
initial_offset: u32,
cursor: Option<&[u8]>,
) -> Result<ValidatedGroupedCursor, CursorPlanError> {
validate_grouped_cursor_order_plan(order)?;
spine::validate_grouped_cursor(
cursor,
entity_path,
continuation_signature,
direction,
initial_offset,
)
}
pub(in crate::db) fn prepare_grouped_cursor_token(
entity_path: &'static str,
order: Option<&OrderSpec>,
direction: Direction,
continuation_signature: ContinuationSignature,
initial_offset: u32,
cursor: Option<GroupedContinuationToken>,
) -> Result<ValidatedGroupedCursor, CursorPlanError> {
validate_grouped_cursor_order_plan(order)?;
spine::validate_grouped_cursor_token(
cursor,
entity_path,
continuation_signature,
direction,
initial_offset,
)
}
pub(in crate::db) fn validate_grouped_cursor_order_plan(
order: Option<&OrderSpec>,
) -> Result<(), CursorPlanError> {
validated_cursor_order_internal(order, false).map(|_| ())
}
fn validated_cursor_order_internal(
order: Option<&OrderSpec>,
require_explicit_order: bool,
) -> Result<Option<&OrderSpec>, CursorPlanError> {
validate_cursor_order_plan_shape(order, require_explicit_order)
.map_err(CursorOrderPlanShapeError::to_cursor_plan_error)
}