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(
128 "error[ALOPEX-F001]: feature '{feature}' is not supported in this version. Expected in {version}"
129 )]
130 UnsupportedFeature {
131 feature: String,
132 version: String,
133 line: u64,
134 column: u64,
135 },
136}
137
138impl PlannerError {
139 pub fn table_not_found(name: impl Into<String>, span: Span) -> Self {
141 Self::TableNotFound {
142 name: name.into(),
143 line: span.start.line,
144 column: span.start.column,
145 }
146 }
147
148 pub fn table_already_exists(name: impl Into<String>) -> Self {
150 Self::TableAlreadyExists { name: name.into() }
151 }
152
153 pub fn column_not_found(
155 column: impl Into<String>,
156 table: impl Into<String>,
157 span: Span,
158 ) -> Self {
159 Self::ColumnNotFound {
160 column: column.into(),
161 table: table.into(),
162 line: span.start.line,
163 col: span.start.column,
164 }
165 }
166
167 pub fn ambiguous_column(column: impl Into<String>, tables: Vec<String>, span: Span) -> Self {
169 Self::AmbiguousColumn {
170 column: column.into(),
171 tables,
172 line: span.start.line,
173 col: span.start.column,
174 }
175 }
176
177 pub fn index_already_exists(name: impl Into<String>) -> Self {
179 Self::IndexAlreadyExists { name: name.into() }
180 }
181
182 pub fn index_not_found(name: impl Into<String>) -> Self {
184 Self::IndexNotFound { name: name.into() }
185 }
186
187 pub fn type_mismatch(
189 expected: impl Into<String>,
190 found: impl Into<String>,
191 span: Span,
192 ) -> Self {
193 Self::TypeMismatch {
194 expected: expected.into(),
195 found: found.into(),
196 line: span.start.line,
197 column: span.start.column,
198 }
199 }
200
201 pub fn invalid_expression(message: impl Into<String>) -> Self {
203 Self::InvalidExpression {
204 message: message.into(),
205 }
206 }
207
208 pub fn invalid_operator(
210 op: impl Into<String>,
211 type_name: impl Into<String>,
212 span: Span,
213 ) -> Self {
214 Self::InvalidOperator {
215 op: op.into(),
216 type_name: type_name.into(),
217 line: span.start.line,
218 column: span.start.column,
219 }
220 }
221
222 pub fn null_constraint_violation(column: impl Into<String>, span: Span) -> Self {
224 Self::NullConstraintViolation {
225 column: column.into(),
226 line: span.start.line,
227 col: span.start.column,
228 }
229 }
230
231 pub fn vector_dimension_mismatch(expected: u32, found: u32, span: Span) -> Self {
233 Self::VectorDimensionMismatch {
234 expected,
235 found,
236 line: span.start.line,
237 column: span.start.column,
238 }
239 }
240
241 pub fn invalid_metric(value: impl Into<String>, span: Span) -> Self {
243 Self::InvalidMetric {
244 value: value.into(),
245 line: span.start.line,
246 column: span.start.column,
247 }
248 }
249
250 pub fn column_value_count_mismatch(columns: usize, values: usize, span: Span) -> Self {
252 Self::ColumnValueCountMismatch {
253 columns,
254 values,
255 line: span.start.line,
256 column: span.start.column,
257 }
258 }
259
260 pub fn unsupported_feature(
262 feature: impl Into<String>,
263 version: impl Into<String>,
264 span: Span,
265 ) -> Self {
266 Self::UnsupportedFeature {
267 feature: feature.into(),
268 version: version.into(),
269 line: span.start.line,
270 column: span.start.column,
271 }
272 }
273}