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