use crate::db::{
session::sql::write_policy::{
DEFAULT_PUBLIC_BOUNDED_WRITE_LIMIT, DEFAULT_PUBLIC_WRITE_RETURNING_RESPONSE_BYTES,
SqlWriteBoundedPlanProof, SqlWriteBoundedPolicyRejection, SqlWriteExecutionBounds,
SqlWriteExposureClass, SqlWritePlanCore, SqlWritePolicyBounds, SqlWritePrimaryKeyPlanProof,
SqlWriteReturningBounds, SqlWriteShapePolicyRejection, SqlWriteStatementShape,
},
sql::parser::SqlDeleteStatement,
};
#[doc(hidden)]
pub(in crate::db) const DEFAULT_PUBLIC_BOUNDED_DELETE_LIMIT: u32 =
DEFAULT_PUBLIC_BOUNDED_WRITE_LIMIT;
#[doc(hidden)]
pub(in crate::db) const DEFAULT_PUBLIC_DELETE_RETURNING_RESPONSE_BYTES: u32 =
DEFAULT_PUBLIC_WRITE_RETURNING_RESPONSE_BYTES;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub enum SqlDeleteExposurePolicy {
SessionWriteCurrent,
GeneratedQuery,
GeneratedDdl,
PublicPrimaryKeyOnly,
PublicBoundedDeterministic,
AdminBulk,
}
impl SqlDeleteExposurePolicy {
pub(super) const fn exposure_class(self) -> SqlWriteExposureClass {
match self {
Self::SessionWriteCurrent => SqlWriteExposureClass::SessionWriteCurrent,
Self::GeneratedQuery => SqlWriteExposureClass::GeneratedQuery,
Self::GeneratedDdl => SqlWriteExposureClass::GeneratedDdl,
Self::PublicPrimaryKeyOnly => SqlWriteExposureClass::PublicPrimaryKeyOnly,
Self::PublicBoundedDeterministic => SqlWriteExposureClass::PublicBoundedDeterministic,
Self::AdminBulk => SqlWriteExposureClass::AdminBulk,
}
}
}
#[derive(Clone, Copy, Debug)]
#[doc(hidden)]
pub struct SqlDeletePolicyContext<'a> {
pub primary_key_fields: &'a [&'a str],
pub max_public_bounded_limit: u32,
pub max_returning_rows: Option<u32>,
pub max_returning_response_bytes: Option<u32>,
}
impl<'a> SqlDeletePolicyContext<'a> {
#[must_use]
pub const fn new(primary_key_fields: &'a [&'a str]) -> Self {
Self {
primary_key_fields,
max_public_bounded_limit: DEFAULT_PUBLIC_BOUNDED_DELETE_LIMIT,
max_returning_rows: None,
max_returning_response_bytes: None,
}
}
pub(super) const fn write_bounds(self) -> SqlWritePolicyBounds {
SqlWritePolicyBounds::new(
self.max_public_bounded_limit,
self.max_returning_rows,
self.max_returning_response_bytes,
)
}
#[must_use]
pub const fn public_generated(primary_key_fields: &'a [&'a str]) -> Self {
Self {
primary_key_fields,
max_public_bounded_limit: DEFAULT_PUBLIC_BOUNDED_DELETE_LIMIT,
max_returning_rows: None,
max_returning_response_bytes: Some(DEFAULT_PUBLIC_DELETE_RETURNING_RESPONSE_BYTES),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub struct SqlDeleteStatementClassification {
pub target_entity: String,
pub write_shape: SqlWriteStatementShape,
}
pub(super) type SqlDeletePlanCore =
SqlWritePlanCore<SqlDeleteStatement, SqlDeleteStatementClassification>;
#[derive(Clone, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub enum SqlValidatedDeletePlan {
SessionCurrent(SqlSessionCurrentDeletePlan),
PublicPrimaryKeyOnly(SqlPublicPrimaryKeyDeletePlan),
PublicBoundedDeterministic(SqlPublicBoundedDeletePlan),
AdminBulk(SqlAdminBulkDeletePlan),
}
impl SqlValidatedDeletePlan {
#[must_use]
pub const fn classification(&self) -> &SqlDeleteStatementClassification {
match self {
Self::SessionCurrent(plan) => plan.core.classification(),
Self::PublicPrimaryKeyOnly(plan) => plan.core.classification(),
Self::PublicBoundedDeterministic(plan) => plan.core.classification(),
Self::AdminBulk(plan) => plan.core.classification(),
}
}
#[must_use]
pub const fn execution_bounds(&self) -> SqlWriteExecutionBounds {
match self {
Self::SessionCurrent(plan) => plan.core.execution_bounds(),
Self::PublicPrimaryKeyOnly(plan) => plan.core.execution_bounds(),
Self::PublicBoundedDeterministic(plan) => plan.core.execution_bounds(),
Self::AdminBulk(plan) => plan.core.execution_bounds(),
}
}
#[must_use]
pub const fn returning_bounds(&self) -> SqlWriteReturningBounds {
self.execution_bounds().returning
}
#[must_use]
pub const fn statement_entity(&self) -> &str {
match self {
Self::SessionCurrent(plan) => plan.core.statement().entity.as_str(),
Self::PublicPrimaryKeyOnly(plan) => plan.core.statement().entity.as_str(),
Self::PublicBoundedDeterministic(plan) => plan.core.statement().entity.as_str(),
Self::AdminBulk(plan) => plan.core.statement().entity.as_str(),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub struct SqlSessionCurrentDeletePlan {
pub(super) core: SqlDeletePlanCore,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub struct SqlPublicPrimaryKeyDeletePlan {
pub(super) core: SqlDeletePlanCore,
pub(super) primary_key_proof: SqlWritePrimaryKeyPlanProof,
}
impl SqlPublicPrimaryKeyDeletePlan {
pub(in crate::db::session::sql) const fn statement(&self) -> &SqlDeleteStatement {
self.core.statement()
}
#[must_use]
pub const fn execution_bounds(&self) -> SqlWriteExecutionBounds {
self.core.execution_bounds()
}
#[must_use]
pub const fn primary_key_fields(&self) -> &[String] {
self.primary_key_proof.primary_key_fields()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub struct SqlPublicBoundedDeletePlan {
pub(super) core: SqlDeletePlanCore,
pub(super) bounded_proof: SqlWriteBoundedPlanProof,
}
impl SqlPublicBoundedDeletePlan {
pub(in crate::db::session::sql) const fn statement(&self) -> &SqlDeleteStatement {
self.core.statement()
}
#[must_use]
pub const fn execution_bounds(&self) -> SqlWriteExecutionBounds {
self.core.execution_bounds()
}
#[cfg(test)]
pub(in crate::db) const fn set_execution_bounds_for_tests(
&mut self,
execution_bounds: SqlWriteExecutionBounds,
) {
self.core.set_execution_bounds_for_tests(execution_bounds);
}
#[must_use]
pub const fn limit(&self) -> u32 {
self.bounded_proof.limit()
}
#[must_use]
pub const fn ordered_primary_key_fields(&self) -> &[String] {
self.bounded_proof.ordered_primary_key_fields()
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub struct SqlAdminBulkDeletePlan {
pub(super) core: SqlDeletePlanCore,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub enum SqlDeletePolicyRejection {
NotDelete,
GeneratedQueryRejectsDelete,
GeneratedDdlRejectsDelete,
MissingWhere,
PrimaryKeyProofFailed,
MissingCanonicalPrimaryKeyOrder,
DescendingOrder,
MissingLimit,
OffsetUnsupported,
LimitTooHigh,
}
impl SqlDeletePolicyRejection {
const fn from_bounded_write_rejection(rejection: SqlWriteBoundedPolicyRejection) -> Self {
match rejection {
SqlWriteBoundedPolicyRejection::MissingCanonicalPrimaryKeyOrder => {
Self::MissingCanonicalPrimaryKeyOrder
}
SqlWriteBoundedPolicyRejection::DescendingOrder => Self::DescendingOrder,
SqlWriteBoundedPolicyRejection::MissingLimit => Self::MissingLimit,
SqlWriteBoundedPolicyRejection::OffsetUnsupported => Self::OffsetUnsupported,
SqlWriteBoundedPolicyRejection::LimitTooHigh => Self::LimitTooHigh,
}
}
pub(super) const fn from_write_shape_rejection(
rejection: SqlWriteShapePolicyRejection,
) -> Self {
match rejection {
SqlWriteShapePolicyRejection::MissingWhere => Self::MissingWhere,
SqlWriteShapePolicyRejection::PrimaryKeyProofFailed => Self::PrimaryKeyProofFailed,
SqlWriteShapePolicyRejection::Bounded(rejection) => {
Self::from_bounded_write_rejection(rejection)
}
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[doc(hidden)]
pub struct SqlDeletePolicyReport {
pub classification: Option<SqlDeleteStatementClassification>,
pub plan: Option<SqlValidatedDeletePlan>,
pub rejection: Option<SqlDeletePolicyRejection>,
}
impl SqlDeletePolicyReport {
#[must_use]
pub const fn is_admitted(&self) -> bool {
self.rejection.is_none()
}
pub(super) const fn rejected(rejection: SqlDeletePolicyRejection) -> Self {
Self {
classification: None,
plan: None,
rejection: Some(rejection),
}
}
}