use crate::ast::Span;
use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum PlannerError {
#[error("invalid PRAGMA '{name}': {reason}")]
InvalidPragma { name: String, reason: String },
#[error("error[ALOPEX-C001]: table '{name}' not found at line {line}, column {column}")]
TableNotFound {
name: String,
line: u64,
column: u64,
},
#[error("error[ALOPEX-C002]: table '{name}' already exists")]
TableAlreadyExists { name: String },
#[error(
"error[ALOPEX-C003]: column '{column}' not found in table '{table}' at line {line}, column {col}"
)]
ColumnNotFound {
column: String,
table: String,
line: u64,
col: u64,
},
#[error(
"error[ALOPEX-C004]: ambiguous column '{column}' found in tables: {tables:?} at line {line}, column {col}"
)]
AmbiguousColumn {
column: String,
tables: Vec<String>,
line: u64,
col: u64,
},
#[error("error[ALOPEX-C005]: index '{name}' already exists")]
IndexAlreadyExists { name: String },
#[error("error[ALOPEX-C006]: index '{name}' not found")]
IndexNotFound { name: String },
#[error(
"error[ALOPEX-C007]: table function '{name}' does not exist at line {line}, column {column}"
)]
UnknownTableFunction {
name: String,
line: u64,
column: u64,
},
#[error(
"error[ALOPEX-T001]: type mismatch at line {line}, column {column}: expected {expected}, found {found}"
)]
TypeMismatch {
expected: String,
found: String,
line: u64,
column: u64,
},
#[error(
"error[ALOPEX-T002]: invalid operator '{op}' for type '{type_name}' at line {line}, column {column}"
)]
InvalidOperator {
op: String,
type_name: String,
line: u64,
column: u64,
},
#[error(
"error[ALOPEX-T003]: null constraint violation for column '{column}' at line {line}, column {col}"
)]
NullConstraintViolation { column: String, line: u64, col: u64 },
#[error(
"error[ALOPEX-T004]: vector dimension mismatch at line {line}, column {column}: expected {expected}, found {found}"
)]
VectorDimensionMismatch {
expected: u32,
found: u32,
line: u64,
column: u64,
},
#[error(
"error[ALOPEX-T005]: invalid metric '{value}' at line {line}, column {column}. Valid options: cosine, l2, inner"
)]
InvalidMetric {
value: String,
line: u64,
column: u64,
},
#[error(
"error[ALOPEX-T006]: column count ({columns}) does not match value count ({values}) at line {line}, column {column}"
)]
ColumnValueCountMismatch {
columns: usize,
values: usize,
line: u64,
column: u64,
},
#[error("error[ALOPEX-T007]: invalid expression: {message}")]
InvalidExpression { message: String },
#[error(
"error[ALOPEX-T008]: set operation column count mismatch: left {left}, right {right} at line {line}, column {column}"
)]
SetOperationColumnCountMismatch {
left: usize,
right: usize,
line: u64,
column: u64,
},
#[error(
"error[ALOPEX-T009]: common table expression '{cte}' declares {declared} column names but its query returns {actual} columns at line {line}, column {column}"
)]
CteColumnCountMismatch {
cte: String,
declared: usize,
actual: usize,
line: u64,
column: u64,
},
#[error(
"error[ALOPEX-T010]: common table expression '{cte}' declares column '{name}' more than once at line {line}, column {column}"
)]
DuplicateCteColumn {
cte: String,
name: String,
line: u64,
column: u64,
},
#[error(
"error[ALOPEX-T011]: VALUES row {row} has {actual} columns but row 1 has {expected} at line {line}, column {column}"
)]
ValuesColumnCountMismatch {
row: usize,
expected: usize,
actual: usize,
line: u64,
column: u64,
},
#[error(
"error[ALOPEX-T012]: relation alias '{alias}' declares {declared} column names but the relation has {actual} columns at line {line}, column {column}"
)]
TableAliasColumnCountMismatch {
alias: String,
declared: usize,
actual: usize,
line: u64,
column: u64,
},
#[error(
"error[ALOPEX-T013]: row value has {actual} fields but its comparison operand has {expected} at line {line}, column {column}"
)]
RowArityMismatch {
expected: usize,
actual: usize,
line: u64,
column: u64,
},
#[error(
"error[ALOPEX-T014]: SELECT DISTINCT ON expressions must match initial ORDER BY expressions at line {line}, column {column}"
)]
DistinctOnOrderByMismatch { line: u64, column: u64 },
#[error(
"error[ALOPEX-T015]: {join_type} JOIN cannot have a LATERAL right side at line {line}, column {column}"
)]
LateralJoinTypeUnsupported {
join_type: String,
line: u64,
column: u64,
},
#[error(
"error[ALOPEX-F001]: feature '{feature}' is not supported in this version. Expected in {version}"
)]
UnsupportedFeature {
feature: String,
version: String,
line: u64,
column: u64,
},
}
impl PlannerError {
pub fn table_not_found(name: impl Into<String>, span: Span) -> Self {
Self::TableNotFound {
name: name.into(),
line: span.start.line,
column: span.start.column,
}
}
pub fn table_already_exists(name: impl Into<String>) -> Self {
Self::TableAlreadyExists { name: name.into() }
}
pub fn unknown_table_function(name: impl Into<String>, span: Span) -> Self {
Self::UnknownTableFunction {
name: name.into(),
line: span.start.line,
column: span.start.column,
}
}
pub fn lateral_join_type_unsupported(join_type: impl Into<String>, span: Span) -> Self {
Self::LateralJoinTypeUnsupported {
join_type: join_type.into(),
line: span.start.line,
column: span.start.column,
}
}
pub fn column_not_found(
column: impl Into<String>,
table: impl Into<String>,
span: Span,
) -> Self {
Self::ColumnNotFound {
column: column.into(),
table: table.into(),
line: span.start.line,
col: span.start.column,
}
}
pub fn ambiguous_column(column: impl Into<String>, tables: Vec<String>, span: Span) -> Self {
Self::AmbiguousColumn {
column: column.into(),
tables,
line: span.start.line,
col: span.start.column,
}
}
pub fn index_already_exists(name: impl Into<String>) -> Self {
Self::IndexAlreadyExists { name: name.into() }
}
pub fn index_not_found(name: impl Into<String>) -> Self {
Self::IndexNotFound { name: name.into() }
}
pub fn type_mismatch(
expected: impl Into<String>,
found: impl Into<String>,
span: Span,
) -> Self {
Self::TypeMismatch {
expected: expected.into(),
found: found.into(),
line: span.start.line,
column: span.start.column,
}
}
pub fn invalid_expression(message: impl Into<String>) -> Self {
Self::InvalidExpression {
message: message.into(),
}
}
pub fn set_operation_column_count_mismatch(left: usize, right: usize, span: Span) -> Self {
Self::SetOperationColumnCountMismatch {
left,
right,
line: span.start.line,
column: span.start.column,
}
}
pub fn cte_column_count_mismatch(
cte: impl Into<String>,
declared: usize,
actual: usize,
span: Span,
) -> Self {
Self::CteColumnCountMismatch {
cte: cte.into(),
declared,
actual,
line: span.start.line,
column: span.start.column,
}
}
pub fn duplicate_cte_column(
cte: impl Into<String>,
column_name: impl Into<String>,
span: Span,
) -> Self {
Self::DuplicateCteColumn {
cte: cte.into(),
name: column_name.into(),
line: span.start.line,
column: span.start.column,
}
}
pub fn values_column_count_mismatch(
row: usize,
expected: usize,
actual: usize,
span: Span,
) -> Self {
Self::ValuesColumnCountMismatch {
row,
expected,
actual,
line: span.start.line,
column: span.start.column,
}
}
pub fn table_alias_column_count_mismatch(
alias: impl Into<String>,
declared: usize,
actual: usize,
span: Span,
) -> Self {
Self::TableAliasColumnCountMismatch {
alias: alias.into(),
declared,
actual,
line: span.start.line,
column: span.start.column,
}
}
pub fn invalid_operator(
op: impl Into<String>,
type_name: impl Into<String>,
span: Span,
) -> Self {
Self::InvalidOperator {
op: op.into(),
type_name: type_name.into(),
line: span.start.line,
column: span.start.column,
}
}
pub fn null_constraint_violation(column: impl Into<String>, span: Span) -> Self {
Self::NullConstraintViolation {
column: column.into(),
line: span.start.line,
col: span.start.column,
}
}
pub fn vector_dimension_mismatch(expected: u32, found: u32, span: Span) -> Self {
Self::VectorDimensionMismatch {
expected,
found,
line: span.start.line,
column: span.start.column,
}
}
pub fn invalid_metric(value: impl Into<String>, span: Span) -> Self {
Self::InvalidMetric {
value: value.into(),
line: span.start.line,
column: span.start.column,
}
}
pub fn column_value_count_mismatch(columns: usize, values: usize, span: Span) -> Self {
Self::ColumnValueCountMismatch {
columns,
values,
line: span.start.line,
column: span.start.column,
}
}
pub fn distinct_on_order_by_mismatch(span: Span) -> Self {
Self::DistinctOnOrderByMismatch {
line: span.start.line,
column: span.start.column,
}
}
pub fn unsupported_feature(
feature: impl Into<String>,
version: impl Into<String>,
span: Span,
) -> Self {
Self::UnsupportedFeature {
feature: feature.into(),
version: version.into(),
line: span.start.line,
column: span.start.column,
}
}
}