1use crate::ast::Span;
9use thiserror::Error;
10
11#[derive(Debug, Clone, PartialEq, Eq, Error)]
13pub enum PlannerError {
14 #[error("invalid PRAGMA '{name}': {reason}")]
16 InvalidPragma { name: String, reason: String },
17 #[error("error[ALOPEX-C001]: table '{name}' not found at line {line}, column {column}")]
20 TableNotFound {
21 name: String,
22 line: u64,
23 column: u64,
24 },
25
26 #[error("error[ALOPEX-C002]: table '{name}' already exists")]
28 TableAlreadyExists { name: String },
29
30 #[error(
32 "error[ALOPEX-C003]: column '{column}' not found in table '{table}' at line {line}, column {col}"
33 )]
34 ColumnNotFound {
35 column: String,
36 table: String,
37 line: u64,
38 col: u64,
39 },
40
41 #[error(
43 "error[ALOPEX-C004]: ambiguous column '{column}' found in tables: {tables:?} at line {line}, column {col}"
44 )]
45 AmbiguousColumn {
46 column: String,
47 tables: Vec<String>,
48 line: u64,
49 col: u64,
50 },
51
52 #[error("error[ALOPEX-C005]: index '{name}' already exists")]
54 IndexAlreadyExists { name: String },
55
56 #[error("error[ALOPEX-C006]: index '{name}' not found")]
58 IndexNotFound { name: String },
59
60 #[error(
63 "error[ALOPEX-T001]: type mismatch at line {line}, column {column}: expected {expected}, found {found}"
64 )]
65 TypeMismatch {
66 expected: String,
67 found: String,
68 line: u64,
69 column: u64,
70 },
71
72 #[error(
74 "error[ALOPEX-T002]: invalid operator '{op}' for type '{type_name}' at line {line}, column {column}"
75 )]
76 InvalidOperator {
77 op: String,
78 type_name: String,
79 line: u64,
80 column: u64,
81 },
82
83 #[error(
85 "error[ALOPEX-T003]: null constraint violation for column '{column}' at line {line}, column {col}"
86 )]
87 NullConstraintViolation { column: String, line: u64, col: u64 },
88
89 #[error(
91 "error[ALOPEX-T004]: vector dimension mismatch at line {line}, column {column}: expected {expected}, found {found}"
92 )]
93 VectorDimensionMismatch {
94 expected: u32,
95 found: u32,
96 line: u64,
97 column: u64,
98 },
99
100 #[error(
102 "error[ALOPEX-T005]: invalid metric '{value}' at line {line}, column {column}. Valid options: cosine, l2, inner"
103 )]
104 InvalidMetric {
105 value: String,
106 line: u64,
107 column: u64,
108 },
109
110 #[error(
112 "error[ALOPEX-T006]: column count ({columns}) does not match value count ({values}) at line {line}, column {column}"
113 )]
114 ColumnValueCountMismatch {
115 columns: usize,
116 values: usize,
117 line: u64,
118 column: u64,
119 },
120
121 #[error("error[ALOPEX-T007]: invalid expression: {message}")]
123 InvalidExpression { message: String },
124
125 #[error(
127 "error[ALOPEX-T008]: set operation column count mismatch: left {left}, right {right} at line {line}, column {column}"
128 )]
129 SetOperationColumnCountMismatch {
130 left: usize,
131 right: usize,
132 line: u64,
133 column: u64,
134 },
135
136 #[error(
139 "error[ALOPEX-F001]: feature '{feature}' is not supported in this version. Expected in {version}"
140 )]
141 UnsupportedFeature {
142 feature: String,
143 version: String,
144 line: u64,
145 column: u64,
146 },
147}
148
149impl PlannerError {
150 pub fn table_not_found(name: impl Into<String>, span: Span) -> Self {
152 Self::TableNotFound {
153 name: name.into(),
154 line: span.start.line,
155 column: span.start.column,
156 }
157 }
158
159 pub fn table_already_exists(name: impl Into<String>) -> Self {
161 Self::TableAlreadyExists { name: name.into() }
162 }
163
164 pub fn column_not_found(
166 column: impl Into<String>,
167 table: impl Into<String>,
168 span: Span,
169 ) -> Self {
170 Self::ColumnNotFound {
171 column: column.into(),
172 table: table.into(),
173 line: span.start.line,
174 col: span.start.column,
175 }
176 }
177
178 pub fn ambiguous_column(column: impl Into<String>, tables: Vec<String>, span: Span) -> Self {
180 Self::AmbiguousColumn {
181 column: column.into(),
182 tables,
183 line: span.start.line,
184 col: span.start.column,
185 }
186 }
187
188 pub fn index_already_exists(name: impl Into<String>) -> Self {
190 Self::IndexAlreadyExists { name: name.into() }
191 }
192
193 pub fn index_not_found(name: impl Into<String>) -> Self {
195 Self::IndexNotFound { name: name.into() }
196 }
197
198 pub fn type_mismatch(
200 expected: impl Into<String>,
201 found: impl Into<String>,
202 span: Span,
203 ) -> Self {
204 Self::TypeMismatch {
205 expected: expected.into(),
206 found: found.into(),
207 line: span.start.line,
208 column: span.start.column,
209 }
210 }
211
212 pub fn invalid_expression(message: impl Into<String>) -> Self {
214 Self::InvalidExpression {
215 message: message.into(),
216 }
217 }
218
219 pub fn set_operation_column_count_mismatch(left: usize, right: usize, span: Span) -> Self {
221 Self::SetOperationColumnCountMismatch {
222 left,
223 right,
224 line: span.start.line,
225 column: span.start.column,
226 }
227 }
228
229 pub fn invalid_operator(
231 op: impl Into<String>,
232 type_name: impl Into<String>,
233 span: Span,
234 ) -> Self {
235 Self::InvalidOperator {
236 op: op.into(),
237 type_name: type_name.into(),
238 line: span.start.line,
239 column: span.start.column,
240 }
241 }
242
243 pub fn null_constraint_violation(column: impl Into<String>, span: Span) -> Self {
245 Self::NullConstraintViolation {
246 column: column.into(),
247 line: span.start.line,
248 col: span.start.column,
249 }
250 }
251
252 pub fn vector_dimension_mismatch(expected: u32, found: u32, span: Span) -> Self {
254 Self::VectorDimensionMismatch {
255 expected,
256 found,
257 line: span.start.line,
258 column: span.start.column,
259 }
260 }
261
262 pub fn invalid_metric(value: impl Into<String>, span: Span) -> Self {
264 Self::InvalidMetric {
265 value: value.into(),
266 line: span.start.line,
267 column: span.start.column,
268 }
269 }
270
271 pub fn column_value_count_mismatch(columns: usize, values: usize, span: Span) -> Self {
273 Self::ColumnValueCountMismatch {
274 columns,
275 values,
276 line: span.start.line,
277 column: span.start.column,
278 }
279 }
280
281 pub fn unsupported_feature(
283 feature: impl Into<String>,
284 version: impl Into<String>,
285 span: Span,
286 ) -> Self {
287 Self::UnsupportedFeature {
288 feature: feature.into(),
289 version: version.into(),
290 line: span.start.line,
291 column: span.start.column,
292 }
293 }
294}