alopex_sql/planner/
error.rs

1//! Planner error types for the Alopex SQL dialect.
2//!
3//! This module defines error types for the planning phase, including:
4//! - Catalog errors (ALOPEX-C*): Table/column/index lookup failures
5//! - Type errors (ALOPEX-T*): Type mismatches, constraint violations
6//! - Feature errors (ALOPEX-F*): Unsupported features
7
8use crate::ast::Span;
9use thiserror::Error;
10
11/// Planner errors for the Alopex SQL dialect.
12#[derive(Debug, Clone, PartialEq, Eq, Error)]
13pub enum PlannerError {
14    // === Catalog Errors (ALOPEX-C*) ===
15    /// ALOPEX-C001: Table not found.
16    #[error("error[ALOPEX-C001]: table '{name}' not found at line {line}, column {column}")]
17    TableNotFound {
18        name: String,
19        line: u64,
20        column: u64,
21    },
22
23    /// ALOPEX-C002: Table already exists.
24    #[error("error[ALOPEX-C002]: table '{name}' already exists")]
25    TableAlreadyExists { name: String },
26
27    /// ALOPEX-C003: Column not found.
28    #[error(
29        "error[ALOPEX-C003]: column '{column}' not found in table '{table}' at line {line}, column {col}"
30    )]
31    ColumnNotFound {
32        column: String,
33        table: String,
34        line: u64,
35        col: u64,
36    },
37
38    /// ALOPEX-C004: Ambiguous column reference.
39    #[error(
40        "error[ALOPEX-C004]: ambiguous column '{column}' found in tables: {tables:?} at line {line}, column {col}"
41    )]
42    AmbiguousColumn {
43        column: String,
44        tables: Vec<String>,
45        line: u64,
46        col: u64,
47    },
48
49    /// ALOPEX-C005: Index already exists.
50    #[error("error[ALOPEX-C005]: index '{name}' already exists")]
51    IndexAlreadyExists { name: String },
52
53    /// ALOPEX-C006: Index not found.
54    #[error("error[ALOPEX-C006]: index '{name}' not found")]
55    IndexNotFound { name: String },
56
57    // === Type Errors (ALOPEX-T*) ===
58    /// ALOPEX-T001: Type mismatch.
59    #[error(
60        "error[ALOPEX-T001]: type mismatch at line {line}, column {column}: expected {expected}, found {found}"
61    )]
62    TypeMismatch {
63        expected: String,
64        found: String,
65        line: u64,
66        column: u64,
67    },
68
69    /// ALOPEX-T002: Invalid operator for type.
70    #[error(
71        "error[ALOPEX-T002]: invalid operator '{op}' for type '{type_name}' at line {line}, column {column}"
72    )]
73    InvalidOperator {
74        op: String,
75        type_name: String,
76        line: u64,
77        column: u64,
78    },
79
80    /// ALOPEX-T003: NULL constraint violation.
81    #[error(
82        "error[ALOPEX-T003]: null constraint violation for column '{column}' at line {line}, column {col}"
83    )]
84    NullConstraintViolation { column: String, line: u64, col: u64 },
85
86    /// ALOPEX-T004: Vector dimension mismatch.
87    #[error(
88        "error[ALOPEX-T004]: vector dimension mismatch at line {line}, column {column}: expected {expected}, found {found}"
89    )]
90    VectorDimensionMismatch {
91        expected: u32,
92        found: u32,
93        line: u64,
94        column: u64,
95    },
96
97    /// ALOPEX-T005: Invalid metric.
98    #[error(
99        "error[ALOPEX-T005]: invalid metric '{value}' at line {line}, column {column}. Valid options: cosine, l2, inner"
100    )]
101    InvalidMetric {
102        value: String,
103        line: u64,
104        column: u64,
105    },
106
107    /// ALOPEX-T006: Column count does not match value count.
108    #[error(
109        "error[ALOPEX-T006]: column count ({columns}) does not match value count ({values}) at line {line}, column {column}"
110    )]
111    ColumnValueCountMismatch {
112        columns: usize,
113        values: usize,
114        line: u64,
115        column: u64,
116    },
117
118    // === Feature Errors (ALOPEX-F*) ===
119    /// ALOPEX-F001: Unsupported feature.
120    #[error(
121        "error[ALOPEX-F001]: feature '{feature}' is not supported in this version. Expected in {version}"
122    )]
123    UnsupportedFeature {
124        feature: String,
125        version: String,
126        line: u64,
127        column: u64,
128    },
129}
130
131impl PlannerError {
132    /// Create a TableNotFound error from a span.
133    pub fn table_not_found(name: impl Into<String>, span: Span) -> Self {
134        Self::TableNotFound {
135            name: name.into(),
136            line: span.start.line,
137            column: span.start.column,
138        }
139    }
140
141    /// Create a TableAlreadyExists error.
142    pub fn table_already_exists(name: impl Into<String>) -> Self {
143        Self::TableAlreadyExists { name: name.into() }
144    }
145
146    /// Create a ColumnNotFound error from a span.
147    pub fn column_not_found(
148        column: impl Into<String>,
149        table: impl Into<String>,
150        span: Span,
151    ) -> Self {
152        Self::ColumnNotFound {
153            column: column.into(),
154            table: table.into(),
155            line: span.start.line,
156            col: span.start.column,
157        }
158    }
159
160    /// Create an AmbiguousColumn error from a span.
161    pub fn ambiguous_column(column: impl Into<String>, tables: Vec<String>, span: Span) -> Self {
162        Self::AmbiguousColumn {
163            column: column.into(),
164            tables,
165            line: span.start.line,
166            col: span.start.column,
167        }
168    }
169
170    /// Create an IndexAlreadyExists error.
171    pub fn index_already_exists(name: impl Into<String>) -> Self {
172        Self::IndexAlreadyExists { name: name.into() }
173    }
174
175    /// Create an IndexNotFound error.
176    pub fn index_not_found(name: impl Into<String>) -> Self {
177        Self::IndexNotFound { name: name.into() }
178    }
179
180    /// Create a TypeMismatch error from a span.
181    pub fn type_mismatch(
182        expected: impl Into<String>,
183        found: impl Into<String>,
184        span: Span,
185    ) -> Self {
186        Self::TypeMismatch {
187            expected: expected.into(),
188            found: found.into(),
189            line: span.start.line,
190            column: span.start.column,
191        }
192    }
193
194    /// Create an InvalidOperator error from a span.
195    pub fn invalid_operator(
196        op: impl Into<String>,
197        type_name: impl Into<String>,
198        span: Span,
199    ) -> Self {
200        Self::InvalidOperator {
201            op: op.into(),
202            type_name: type_name.into(),
203            line: span.start.line,
204            column: span.start.column,
205        }
206    }
207
208    /// Create a NullConstraintViolation error from a span.
209    pub fn null_constraint_violation(column: impl Into<String>, span: Span) -> Self {
210        Self::NullConstraintViolation {
211            column: column.into(),
212            line: span.start.line,
213            col: span.start.column,
214        }
215    }
216
217    /// Create a VectorDimensionMismatch error from a span.
218    pub fn vector_dimension_mismatch(expected: u32, found: u32, span: Span) -> Self {
219        Self::VectorDimensionMismatch {
220            expected,
221            found,
222            line: span.start.line,
223            column: span.start.column,
224        }
225    }
226
227    /// Create an InvalidMetric error from a span.
228    pub fn invalid_metric(value: impl Into<String>, span: Span) -> Self {
229        Self::InvalidMetric {
230            value: value.into(),
231            line: span.start.line,
232            column: span.start.column,
233        }
234    }
235
236    /// Create a ColumnValueCountMismatch error from a span.
237    pub fn column_value_count_mismatch(columns: usize, values: usize, span: Span) -> Self {
238        Self::ColumnValueCountMismatch {
239            columns,
240            values,
241            line: span.start.line,
242            column: span.start.column,
243        }
244    }
245
246    /// Create an UnsupportedFeature error from a span.
247    pub fn unsupported_feature(
248        feature: impl Into<String>,
249        version: impl Into<String>,
250        span: Span,
251    ) -> Self {
252        Self::UnsupportedFeature {
253            feature: feature.into(),
254            version: version.into(),
255            line: span.start.line,
256            column: span.start.column,
257        }
258    }
259}