1use std::{
5 fmt::{Display, Formatter},
6 ops::{Deref, DerefMut},
7};
8
9use serde::{Deserialize, Serialize, de, ser};
10
11mod diagnostic;
12pub mod r#macro;
13pub mod render;
14pub mod util;
15
16use std::{array::TryFromSliceError, error, fmt, mem, num, string};
17
18use render::DefaultRenderer;
19
20use crate::{fragment::Fragment, value::r#type::Type};
21
22#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
24pub struct OperatorChainEntry {
25 pub node_id: u64,
26 pub operator_name: String,
27 pub operator_version: String,
28}
29
30#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
31pub struct Diagnostic {
32 pub code: String,
33 pub statement: Option<String>,
34 pub message: String,
35 pub column: Option<DiagnosticColumn>,
36 pub fragment: Fragment,
37 pub label: Option<String>,
38 pub help: Option<String>,
39 pub notes: Vec<String>,
40 pub cause: Option<Box<Diagnostic>>,
41 pub operator_chain: Option<Vec<OperatorChainEntry>>,
43}
44
45#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
46pub struct DiagnosticColumn {
47 pub name: String,
48 pub r#type: Type,
49}
50
51impl Default for Diagnostic {
52 fn default() -> Self {
53 Self {
54 code: String::new(),
55 statement: None,
56 message: String::new(),
57 column: None,
58 fragment: Fragment::None,
59 label: None,
60 help: None,
61 notes: Vec::new(),
62 cause: None,
63 operator_chain: None,
64 }
65 }
66}
67
68impl Display for Diagnostic {
69 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
70 f.write_fmt(format_args!("{}", self.code))
71 }
72}
73
74impl Diagnostic {
75 pub fn with_statement(&mut self, statement: String) {
78 self.statement = Some(statement.clone());
79
80 if let Some(ref mut cause) = self.cause {
82 let mut updated_cause = mem::replace(cause.as_mut(), Diagnostic::default());
83 updated_cause.with_statement(statement);
84 *cause = Box::new(updated_cause);
85 }
86 }
87
88 pub fn with_fragment(&mut self, new_fragment: Fragment) {
91 self.fragment = new_fragment;
95
96 if let Some(ref mut cause) = self.cause {
97 cause.with_fragment(self.fragment.clone());
98 }
99 }
100
101 pub fn fragment(&self) -> Option<Fragment> {
104 match &self.fragment {
105 Fragment::Statement {
106 ..
107 } => Some(self.fragment.clone()),
108 _ => None,
109 }
110 }
111}
112
113pub trait IntoDiagnostic {
119 fn into_diagnostic(self) -> Diagnostic;
121}
122
123#[derive(Debug, Clone, PartialEq)]
124pub enum UnaryOp {
125 Not,
126}
127
128impl Display for UnaryOp {
129 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
130 match self {
131 UnaryOp::Not => f.write_str("NOT"),
132 }
133 }
134}
135
136#[derive(Debug, Clone, PartialEq)]
137pub enum BinaryOp {
138 Add,
139 Sub,
140 Mul,
141 Div,
142 Rem,
143 Equal,
144 NotEqual,
145 LessThan,
146 LessThanEqual,
147 GreaterThan,
148 GreaterThanEqual,
149 Between,
150}
151
152impl BinaryOp {
153 pub fn symbol(&self) -> &'static str {
154 match self {
155 BinaryOp::Add => "+",
156 BinaryOp::Sub => "-",
157 BinaryOp::Mul => "*",
158 BinaryOp::Div => "/",
159 BinaryOp::Rem => "%",
160 BinaryOp::Equal => "==",
161 BinaryOp::NotEqual => "!=",
162 BinaryOp::LessThan => "<",
163 BinaryOp::LessThanEqual => "<=",
164 BinaryOp::GreaterThan => ">",
165 BinaryOp::GreaterThanEqual => ">=",
166 BinaryOp::Between => "BETWEEN",
167 }
168 }
169}
170
171impl Display for BinaryOp {
172 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
173 f.write_str(self.symbol())
174 }
175}
176
177#[derive(Debug, Clone, PartialEq)]
178pub enum LogicalOp {
179 Not,
180 And,
181 Or,
182 Xor,
183}
184
185impl Display for LogicalOp {
186 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
187 match self {
188 LogicalOp::Not => f.write_str("NOT"),
189 LogicalOp::And => f.write_str("AND"),
190 LogicalOp::Or => f.write_str("OR"),
191 LogicalOp::Xor => f.write_str("XOR"),
192 }
193 }
194}
195
196#[derive(Debug, Clone, PartialEq)]
197pub enum OperandCategory {
198 Number,
199 Text,
200 Temporal,
201 Uuid,
202}
203
204impl Display for OperandCategory {
205 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
206 match self {
207 OperandCategory::Number => f.write_str("number"),
208 OperandCategory::Text => f.write_str("text"),
209 OperandCategory::Temporal => f.write_str("temporal value"),
210 OperandCategory::Uuid => f.write_str("UUID"),
211 }
212 }
213}
214
215#[derive(Debug, Clone, PartialEq)]
216pub enum ConstraintKind {
217 Utf8MaxBytes {
218 actual: usize,
219 max: usize,
220 },
221 BlobMaxBytes {
222 actual: usize,
223 max: usize,
224 },
225 IntMaxBytes {
226 actual: usize,
227 max: usize,
228 },
229 UintMaxBytes {
230 actual: usize,
231 max: usize,
232 },
233 DecimalPrecision {
234 actual: u8,
235 max: u8,
236 },
237 DecimalScale {
238 actual: u8,
239 max: u8,
240 },
241 NoneNotAllowed {
242 column_type: Type,
243 },
244}
245
246#[derive(Debug, Clone, PartialEq)]
247pub enum TemporalKind {
248 InvalidDateFormat,
249 InvalidDateTimeFormat,
250 InvalidTimeFormat,
251 InvalidDurationFormat,
252 InvalidYear,
253 InvalidTimeComponentFormat {
254 component: String,
255 },
256 InvalidMonth,
257 InvalidDay,
258 InvalidHour,
259 InvalidMinute,
260 InvalidSecond,
261 InvalidFractionalSeconds,
262 InvalidDateValues,
263 InvalidTimeValues,
264 InvalidDurationCharacter,
265 IncompleteDurationSpecification,
266 InvalidUnitInContext {
267 unit: char,
268 in_time_part: bool,
269 },
270 InvalidDurationComponentValue {
271 unit: char,
272 },
273 UnrecognizedTemporalPattern,
274 EmptyDateComponent,
275 EmptyTimeComponent,
276 DuplicateDurationComponent {
277 component: char,
278 },
279 OutOfOrderDurationComponent {
280 component: char,
281 },
282}
283
284#[derive(Debug, Clone, PartialEq)]
285pub enum BlobEncodingKind {
286 InvalidHex,
287 InvalidBase64,
288 InvalidBase64Url,
289 InvalidBase58,
290 InvalidUtf8Sequence {
291 error: String,
292 },
293}
294
295#[derive(Debug, Clone, PartialEq)]
296pub enum AstErrorKind {
297 TokenizeError {
298 message: String,
299 },
300 UnexpectedEof,
301 ExpectedIdentifier,
302 InvalidColumnProperty,
303 InvalidPolicy,
304 UnexpectedToken {
305 expected: String,
306 },
307 UnsupportedToken,
308 MultipleExpressionsWithoutBraces,
309 UnrecognizedType,
310 UnsupportedAstNode {
311 node_type: String,
312 },
313 EmptyPipeline,
314}
315
316#[derive(Debug, Clone, PartialEq)]
317pub enum ProcedureErrorKind {
318 UndefinedProcedure {
319 name: String,
320 },
321}
322
323#[derive(Debug, Clone, PartialEq)]
324pub enum RuntimeErrorKind {
325 VariableNotFound {
326 name: String,
327 },
328 VariableIsDataframe {
329 name: String,
330 },
331 VariableIsImmutable {
332 name: String,
333 },
334 BreakOutsideLoop,
335 ContinueOutsideLoop,
336 MaxIterationsExceeded {
337 limit: usize,
338 },
339 UndefinedFunction {
340 name: String,
341 },
342 FieldNotFound {
343 variable: String,
344 field: String,
345 available: Vec<String>,
346 },
347 AppendTargetNotFrame {
348 name: String,
349 },
350}
351
352#[derive(Debug, Clone, PartialEq)]
353pub enum NetworkErrorKind {
354 Connection {
355 message: String,
356 },
357 Engine {
358 message: String,
359 },
360 Transport {
361 message: String,
362 },
363 Status {
364 message: String,
365 },
366}
367
368#[derive(Debug, Clone, PartialEq)]
369pub enum AuthErrorKind {
370 AuthenticationFailed {
371 reason: String,
372 },
373 AuthorizationDenied {
374 resource: String,
375 },
376 TokenExpired,
377 InvalidToken,
378}
379
380#[derive(Debug, Clone, PartialEq)]
381pub enum FunctionErrorKind {
382 UnknownFunction,
383 ArityMismatch {
384 expected: usize,
385 actual: usize,
386 },
387 TooManyArguments {
388 max_args: usize,
389 actual: usize,
390 },
391 InvalidArgumentType {
392 index: usize,
393 expected: Vec<Type>,
394 actual: Type,
395 },
396 UndefinedArgument {
397 index: usize,
398 },
399 MissingInput,
400 ExecutionFailed {
401 reason: String,
402 },
403 InternalError {
404 details: String,
405 },
406 GeneratorNotFound,
407}
408
409#[derive(Debug, thiserror::Error)]
410pub enum TypeError {
411 #[error("Cannot apply {operator} operator to {operand_category}")]
412 LogicalOperatorNotApplicable {
413 operator: LogicalOp,
414 operand_category: OperandCategory,
415 fragment: Fragment,
416 },
417
418 #[error("Cannot apply '{operator}' operator to {left} and {right}")]
419 BinaryOperatorNotApplicable {
420 operator: BinaryOp,
421 left: Type,
422 right: Type,
423 fragment: Fragment,
424 },
425
426 #[error("unsupported cast from {from} to {to}")]
427 UnsupportedCast {
428 from: Type,
429 to: Type,
430 fragment: Fragment,
431 },
432
433 #[error("failed to cast to {target}")]
434 CastToNumberFailed {
435 target: Type,
436 fragment: Fragment,
437 cause: Box<TypeError>,
438 },
439
440 #[error("failed to cast to {target}")]
441 CastToTemporalFailed {
442 target: Type,
443 fragment: Fragment,
444 cause: Box<TypeError>,
445 },
446
447 #[error("failed to cast to bool")]
448 CastToBooleanFailed {
449 fragment: Fragment,
450 cause: Box<TypeError>,
451 },
452
453 #[error("failed to cast to {target}")]
454 CastToUuidFailed {
455 target: Type,
456 fragment: Fragment,
457 cause: Box<TypeError>,
458 },
459
460 #[error("failed to cast BLOB to UTF8")]
461 CastBlobToUtf8Failed {
462 fragment: Fragment,
463 cause: Box<TypeError>,
464 },
465
466 #[error("{message}")]
467 ConstraintViolation {
468 kind: ConstraintKind,
469 message: String,
470 fragment: Fragment,
471 },
472
473 #[error("invalid number format")]
474 InvalidNumberFormat {
475 target: Type,
476 fragment: Fragment,
477 },
478
479 #[error("number out of range")]
480 NumberOutOfRange {
481 target: Type,
482 fragment: Fragment,
483 descriptor: Option<NumberOutOfRangeDescriptor>,
484 },
485
486 #[error("NaN not allowed")]
487 NanNotAllowed,
488
489 #[error("too large for precise float conversion")]
490 IntegerPrecisionLoss {
491 source_type: Type,
492 target: Type,
493 fragment: Fragment,
494 },
495
496 #[error("decimal scale exceeds precision")]
497 DecimalScaleExceedsPrecision {
498 scale: u8,
499 precision: u8,
500 fragment: Fragment,
501 },
502
503 #[error("invalid decimal precision")]
504 DecimalPrecisionInvalid {
505 precision: u8,
506 },
507
508 #[error("invalid boolean format")]
509 InvalidBooleanFormat {
510 fragment: Fragment,
511 },
512
513 #[error("empty boolean value")]
514 EmptyBooleanValue {
515 fragment: Fragment,
516 },
517
518 #[error("invalid boolean")]
519 InvalidNumberBoolean {
520 fragment: Fragment,
521 },
522
523 #[error("{message}")]
524 Temporal {
525 kind: TemporalKind,
526 message: String,
527 fragment: Fragment,
528 },
529
530 #[error("invalid UUID v4 format")]
531 InvalidUuid4Format {
532 fragment: Fragment,
533 },
534
535 #[error("invalid UUID v7 format")]
536 InvalidUuid7Format {
537 fragment: Fragment,
538 },
539
540 #[error("{message}")]
541 BlobEncoding {
542 kind: BlobEncodingKind,
543 message: String,
544 fragment: Fragment,
545 },
546
547 #[error("Serde deserialization error: {message}")]
548 SerdeDeserialize {
549 message: String,
550 },
551
552 #[error("Serde serialization error: {message}")]
553 SerdeSerialize {
554 message: String,
555 },
556
557 #[error("Keycode serialization error: {message}")]
558 SerdeKeycode {
559 message: String,
560 },
561
562 #[error("Array conversion error: {message}")]
563 ArrayConversion {
564 message: String,
565 },
566
567 #[error("UTF-8 conversion error: {message}")]
568 Utf8Conversion {
569 message: String,
570 },
571
572 #[error("Integer conversion error: {message}")]
573 IntegerConversion {
574 message: String,
575 },
576
577 #[error("{message}")]
578 Network {
579 kind: NetworkErrorKind,
580 message: String,
581 },
582
583 #[error("{message}")]
584 Auth {
585 kind: AuthErrorKind,
586 message: String,
587 },
588
589 #[error("dictionary entry ID {value} exceeds maximum {max_value} for type {id_type}")]
590 DictionaryCapacityExceeded {
591 id_type: Type,
592 value: u128,
593 max_value: u128,
594 },
595
596 #[error("{message}")]
597 AssertionFailed {
598 fragment: Fragment,
599 message: String,
600 expression: Option<String>,
601 },
602
603 #[error("{message}")]
604 Function {
605 kind: FunctionErrorKind,
606 message: String,
607 fragment: Fragment,
608 },
609
610 #[error("{message}")]
611 Ast {
612 kind: AstErrorKind,
613 message: String,
614 fragment: Fragment,
615 },
616
617 #[error("{message}")]
618 Runtime {
619 kind: RuntimeErrorKind,
620 message: String,
621 },
622
623 #[error("{message}")]
624 Procedure {
625 kind: ProcedureErrorKind,
626 message: String,
627 fragment: Fragment,
628 },
629}
630
631#[derive(Debug, Clone, PartialEq)]
632pub struct NumberOutOfRangeDescriptor {
633 pub namespace: Option<String>,
634 pub table: Option<String>,
635 pub column: Option<String>,
636 pub column_type: Option<Type>,
637}
638
639impl NumberOutOfRangeDescriptor {
640 pub fn location_string(&self) -> String {
641 match (self.namespace.as_deref(), self.table.as_deref(), self.column.as_deref()) {
642 (Some(s), Some(t), Some(c)) => format!("{}::{}.{}", s, t, c),
643 (Some(s), Some(t), None) => format!("{}::{}", s, t),
644 (None, Some(t), Some(c)) => format!("{}.{}", t, c),
645 (Some(s), None, Some(c)) => format!("{}::{}", s, c),
646 (Some(s), None, None) => s.to_string(),
647 (None, Some(t), None) => t.to_string(),
648 (None, None, Some(c)) => c.to_string(),
649 (None, None, None) => "unknown location".to_string(),
650 }
651 }
652}
653
654#[derive(Debug, PartialEq)]
655pub struct Error(pub Diagnostic);
656
657impl Deref for Error {
658 type Target = Diagnostic;
659
660 fn deref(&self) -> &Self::Target {
661 &self.0
662 }
663}
664
665impl DerefMut for Error {
666 fn deref_mut(&mut self) -> &mut Self::Target {
667 &mut self.0
668 }
669}
670
671impl Display for Error {
672 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
673 let out = DefaultRenderer::render_string(&self.0);
674 f.write_str(out.as_str())
675 }
676}
677
678impl Error {
679 pub fn diagnostic(self) -> Diagnostic {
680 self.0
681 }
682}
683
684impl error::Error for Error {}
685
686impl de::Error for Error {
687 fn custom<T: Display>(msg: T) -> Self {
688 TypeError::SerdeDeserialize {
689 message: msg.to_string(),
690 }
691 .into()
692 }
693}
694
695impl ser::Error for Error {
696 fn custom<T: Display>(msg: T) -> Self {
697 TypeError::SerdeSerialize {
698 message: msg.to_string(),
699 }
700 .into()
701 }
702}
703
704impl From<num::TryFromIntError> for Error {
705 fn from(err: num::TryFromIntError) -> Self {
706 TypeError::IntegerConversion {
707 message: err.to_string(),
708 }
709 .into()
710 }
711}
712
713impl From<TryFromSliceError> for Error {
714 fn from(err: TryFromSliceError) -> Self {
715 TypeError::ArrayConversion {
716 message: err.to_string(),
717 }
718 .into()
719 }
720}
721
722impl From<string::FromUtf8Error> for Error {
723 fn from(err: string::FromUtf8Error) -> Self {
724 TypeError::Utf8Conversion {
725 message: err.to_string(),
726 }
727 .into()
728 }
729}
730
731impl From<TypeError> for Error {
732 fn from(err: TypeError) -> Self {
733 Error(err.into_diagnostic())
734 }
735}
736
737impl From<num::TryFromIntError> for TypeError {
738 fn from(err: num::TryFromIntError) -> Self {
739 TypeError::IntegerConversion {
740 message: err.to_string(),
741 }
742 }
743}
744
745impl From<TryFromSliceError> for TypeError {
746 fn from(err: TryFromSliceError) -> Self {
747 TypeError::ArrayConversion {
748 message: err.to_string(),
749 }
750 }
751}
752
753impl From<string::FromUtf8Error> for TypeError {
754 fn from(err: string::FromUtf8Error) -> Self {
755 TypeError::Utf8Conversion {
756 message: err.to_string(),
757 }
758 }
759}
760
761impl de::Error for TypeError {
762 fn custom<T: Display>(msg: T) -> Self {
763 TypeError::SerdeDeserialize {
764 message: msg.to_string(),
765 }
766 }
767}
768
769impl ser::Error for TypeError {
770 fn custom<T: Display>(msg: T) -> Self {
771 TypeError::SerdeSerialize {
772 message: msg.to_string(),
773 }
774 }
775}