use crate::db::query::plan::{
OrderSpec, QueryMode,
validate::plan_shape::{has_explicit_order, validate_order_shape},
validate::{IntentKeyAccessKind, IntentKeyAccessPolicyViolation, PolicyPlanError},
};
pub(crate) fn validate_intent_plan_shape(
mode: QueryMode,
order: Option<&OrderSpec>,
grouped: bool,
) -> Result<(), PolicyPlanError> {
validate_order_shape(order)?;
let is_delete_mode = mode.is_delete();
if is_delete_mode && grouped {
return Err(PolicyPlanError::delete_plan_with_grouping());
}
if is_delete_mode
&& matches!(&mode, QueryMode::Delete(spec) if spec.limit.is_some() || spec.offset() > 0)
&& !has_explicit_order(order)
{
return Err(PolicyPlanError::delete_window_requires_order());
}
Ok(())
}
pub(crate) const fn validate_intent_key_access_policy(
key_access_conflict: bool,
key_access_kind: Option<IntentKeyAccessKind>,
has_predicate: bool,
) -> Result<(), IntentKeyAccessPolicyViolation> {
if key_access_conflict {
return Err(IntentKeyAccessPolicyViolation::key_access_conflict());
}
if has_predicate {
if matches!(key_access_kind, Some(IntentKeyAccessKind::Many)) {
return Err(IntentKeyAccessPolicyViolation::by_ids_with_predicate());
}
if matches!(key_access_kind, Some(IntentKeyAccessKind::Only)) {
return Err(IntentKeyAccessPolicyViolation::only_with_predicate());
}
}
Ok(())
}