use crate::base::{
database::{ColumnOperationError, ColumnType},
math::decimal::DecimalError,
};
use proof_of_sql_parser::{
intermediate_decimal::IntermediateDecimalError, posql_time::PoSQLTimestampError, Identifier,
ResourceId,
};
use thiserror::Error;
#[derive(Error, Debug, PartialEq, Eq)]
pub enum ConversionError {
#[error("Column '{0}' was not found in table '{1}'")]
MissingColumn(Box<Identifier>, Box<ResourceId>),
#[error("Column '{0}' was not found")]
MissingColumnWithoutTable(Box<Identifier>),
#[error("Expected '{expected}' but found '{actual}'")]
InvalidDataType {
expected: ColumnType,
actual: ColumnType,
},
#[error("Left side has '{1}' type but right side has '{0}' type")]
DataTypeMismatch(String, String),
#[error("Columns have different lengths: {0} != {1}")]
DifferentColumnLength(usize, usize),
#[error("Multiple result columns with the same alias '{0}' have been found.")]
DuplicateResultAlias(String),
#[error("A WHERE clause must has boolean type. It is currently of type '{0}'.")]
NonbooleanWhereClause(ColumnType),
#[error("Invalid order by: alias '{0}' does not appear in the result expressions.")]
InvalidOrderBy(String),
#[error("Invalid group by: column '{0}' must appear in the group by expression.")]
InvalidGroupByColumnRef(String),
#[error("Invalid expression: {0}")]
InvalidExpression(String),
#[error("Encountered parsing error: {0}")]
ParseError(String),
#[error(transparent)]
DecimalConversionError(#[from] DecimalError),
#[error("Timestamp conversion error: {0}")]
TimestampConversionError(#[from] PoSQLTimestampError),
#[error(transparent)]
ColumnOperationError(#[from] ColumnOperationError),
#[error("Query not provable because: {0}")]
Unprovable(String),
}
impl From<String> for ConversionError {
fn from(value: String) -> Self {
ConversionError::ParseError(value)
}
}
impl From<ConversionError> for String {
fn from(error: ConversionError) -> Self {
error.to_string()
}
}
impl From<IntermediateDecimalError> for ConversionError {
fn from(err: IntermediateDecimalError) -> ConversionError {
ConversionError::DecimalConversionError(DecimalError::IntermediateDecimalConversionError(
err,
))
}
}
impl ConversionError {
pub fn non_numeric_expr_in_agg<S: Into<String>>(dtype: S, func: S) -> Self {
ConversionError::InvalidExpression(format!(
"cannot use expression of type '{}' with numeric aggregation function '{}'",
dtype.into().to_lowercase(),
func.into().to_lowercase()
))
}
}
pub type ConversionResult<T> = std::result::Result<T, ConversionError>;