use crate::{
db::{
DbSession, QueryError,
integrity::{
IntegrityCheckRequest, IntegrityCheckResult, IntegrityDeepError,
IntegrityEntityIdentity, IntegrityJobError, IntegrityJobId, IntegrityJobOwner,
IntegritySubmissionKey,
},
sql::{SqlIntegrityStatement, parse_integrity_sql},
},
traits::CanisterKind,
};
use icydb_diagnostic_code::SqlLoweringCode;
#[derive(Debug)]
pub enum SqlIntegrityError {
Integrity(IntegrityDeepError),
Sql(QueryError),
}
impl From<IntegrityDeepError> for SqlIntegrityError {
fn from(error: IntegrityDeepError) -> Self {
Self::Integrity(error)
}
}
impl From<IntegrityJobError> for SqlIntegrityError {
fn from(error: IntegrityJobError) -> Self {
Self::Integrity(IntegrityDeepError::Job(error))
}
}
impl From<QueryError> for SqlIntegrityError {
fn from(error: QueryError) -> Self {
Self::Sql(error)
}
}
impl<C: CanisterKind> DbSession<C> {
pub fn execute_admin_integrity_sql(
&self,
sql: &str,
owner: IntegrityJobOwner,
) -> Result<IntegrityCheckResult, SqlIntegrityError> {
let statement = parse_integrity_sql(sql).map_err(QueryError::from_sql_parse_error)?;
let request = self.lower_integrity_sql_request(statement)?;
self.execute_admin_integrity(request, owner)
.map_err(SqlIntegrityError::from)
}
fn lower_integrity_sql_request(
&self,
statement: SqlIntegrityStatement,
) -> Result<IntegrityCheckRequest, SqlIntegrityError> {
match statement {
SqlIntegrityStatement::Quick { entity } => Ok(IntegrityCheckRequest::Quick {
entity: self.integrity_sql_entity_selector(entity.as_str())?,
}),
SqlIntegrityStatement::DeepStart {
entity,
submission_key,
} => Ok(IntegrityCheckRequest::DeepStart {
entity: self.integrity_sql_entity_selector(entity.as_str())?,
submission_key: IntegritySubmissionKey::new(submission_key)?,
}),
SqlIntegrityStatement::DeepContinue {
job_id,
acknowledged_sequence,
} => Ok(IntegrityCheckRequest::deep_continue(
IntegrityJobId::try_from_hex(job_id.as_str())?,
acknowledged_sequence,
)),
SqlIntegrityStatement::DeepAbort { job_id } => Ok(IntegrityCheckRequest::deep_abort(
IntegrityJobId::try_from_hex(job_id.as_str())?,
)),
}
}
fn integrity_sql_entity_selector(
&self,
sql_entity: &str,
) -> Result<IntegrityEntityIdentity, SqlIntegrityError> {
let catalog = self
.find_accepted_schema_catalog_context_for_entity_name(sql_entity)
.map_err(IntegrityDeepError::from)?
.ok_or_else(|| QueryError::sql_lowering(SqlLoweringCode::EntityMismatch))?;
Ok(IntegrityEntityIdentity::from_accepted_identity(
catalog.identity(),
))
}
}