#[cfg(feature = "clap")]
pub mod cli;
pub mod create;
pub mod gc;
use std::collections::BTreeSet;
use crate::identifier::{QualifiedTable, Table};
pub(crate) mod sql_str_serde {
use serde::{Deserialize, Deserializer};
use sqlx::SqlSafeStr as _;
pub fn deserialize<'de, D>(deserializer: D) -> Result<sqlx::SqlStr, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Ok(sqlx::AssertSqlSafe(s).into_sql_str())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ConcurrentlyConfig {
None,
All,
Except(BTreeSet<Table>),
}
impl ConcurrentlyConfig {
#[must_use]
pub fn is_concurrent_for(&self, table: &Table) -> bool {
match self {
Self::None => false,
Self::All => true,
Self::Except(tables) => !tables.contains(table),
}
}
}
#[derive(Debug, thiserror::Error)]
#[error("SQL fragment must not be empty")]
pub struct EmptySqlFragment;
#[derive(Debug, thiserror::Error)]
pub enum FillFactorParseError {
#[error("fillfactor must be an integer between 1 and 100")]
InvalidFormat,
#[error("fillfactor must be between 1 and 100, got {0}")]
OutOfRange(u8),
}
#[derive(Debug, Clone)]
pub struct SqlFragment(String);
impl SqlFragment {
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl core::str::FromStr for SqlFragment {
type Err = EmptySqlFragment;
fn from_str(value: &str) -> core::result::Result<Self, Self::Err> {
if value.is_empty() {
return Err(EmptySqlFragment);
}
Ok(Self(value.to_owned()))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FillFactor(u8);
impl FillFactor {
pub const MIN: u8 = 1;
pub const MAX: u8 = 100;
pub fn new(value: u8) -> Result<Self, FillFactorParseError> {
if !(Self::MIN..=Self::MAX).contains(&value) {
return Err(FillFactorParseError::OutOfRange(value));
}
Ok(Self(value))
}
#[must_use]
pub const fn as_u8(self) -> u8 {
self.0
}
}
impl core::str::FromStr for FillFactor {
type Err = FillFactorParseError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
let parsed: u8 = value
.parse()
.map_err(|_| FillFactorParseError::InvalidFormat)?;
Self::new(parsed)
}
}
impl core::fmt::Display for FillFactor {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.0)
}
}
use crate::identifier::{Index, Schema};
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error(transparent)]
Connection(#[from] crate::sqlx::ConnectionError),
#[error("worker task panicked: {0}")]
WorkerPanic(tokio::task::JoinError),
#[error("SQL error: {0}")]
Sql(#[from] sqlx::Error),
#[error("no partitions found for {qualified_table}")]
NoPartitions {
qualified_table: QualifiedTable,
},
#[error("invalid identifier: {0}")]
Identifier(#[from] crate::identifier::ParseError),
#[error("unknown partition tables in concurrently selection: {tables:?}")]
UnknownPartitionTables {
tables: BTreeSet<Table>,
},
#[error("index {schema}.{index} is already valid")]
IndexAlreadyValid {
schema: Schema,
index: Index,
},
#[error("index {schema}.{index} not found")]
IndexNotFound {
schema: Schema,
index: Index,
},
}