use crate::{
db::{
cursor::{
ContinuationSignature, CursorPlanError, GroupedPlannedCursor, PlannedCursor,
prepare_cursor, prepare_grouped_cursor,
},
executor::ExecutableAccessPath,
query::plan::{ExecutionOrderContract, ExecutionOrdering},
},
model::entity::EntityModel,
traits::FieldValue,
types::EntityTag,
};
#[derive(Clone, Debug, Eq, PartialEq)]
pub(in crate::db) enum CursorValidationOutcome {
Scalar(Box<PlannedCursor>),
Grouped(GroupedPlannedCursor),
}
#[expect(clippy::too_many_arguments)]
pub(in crate::db) fn validate_cursor_compatibility<K: FieldValue>(
contract: &ExecutionOrderContract,
access: Option<ExecutableAccessPath<'_, K>>,
entity_path: &'static str,
entity_tag: EntityTag,
entity_model: &EntityModel,
continuation_signature: ContinuationSignature,
initial_offset: u32,
cursor: Option<&[u8]>,
) -> Result<CursorValidationOutcome, CursorPlanError> {
match contract.ordering() {
ExecutionOrdering::PrimaryKey => {
if cursor.is_some() || contract.supports_cursor() {
return Err(CursorPlanError::cursor_requires_explicit_or_grouped_ordering());
}
Ok(CursorValidationOutcome::Scalar(Box::new(
PlannedCursor::none(),
)))
}
ExecutionOrdering::Explicit(order) => {
let scalar = prepare_cursor(
access,
entity_path,
entity_tag,
entity_model,
Some(order),
contract.direction(),
continuation_signature,
initial_offset,
cursor,
)?;
Ok(CursorValidationOutcome::Scalar(Box::new(scalar)))
}
ExecutionOrdering::Grouped(order) => {
let grouped = prepare_grouped_cursor(
entity_path,
order.as_ref(),
continuation_signature,
initial_offset,
cursor,
)?;
Ok(CursorValidationOutcome::Grouped(grouped))
}
}
}