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}
368
369#[derive(Debug, Clone, PartialEq)]
370pub enum NetworkErrorKind {
371 Connection {
372 message: String,
373 },
374 Engine {
375 message: String,
376 },
377 Transport {
378 message: String,
379 },
380 Status {
381 message: String,
382 },
383}
384
385#[derive(Debug, Clone, PartialEq)]
386pub enum AuthErrorKind {
387 AuthenticationFailed {
388 reason: String,
389 },
390 AuthorizationDenied {
391 resource: String,
392 },
393 TokenExpired,
394 InvalidToken,
395}
396
397#[derive(Debug, Clone, PartialEq)]
398pub enum FunctionErrorKind {
399 UnknownFunction,
400 ArityMismatch {
401 expected: usize,
402 actual: usize,
403 },
404 TooManyArguments {
405 max_args: usize,
406 actual: usize,
407 },
408 InvalidArgumentType {
409 index: usize,
410 expected: Vec<ValueType>,
411 actual: ValueType,
412 },
413 UndefinedArgument {
414 index: usize,
415 },
416 MissingInput,
417 ExecutionFailed {
418 reason: String,
419 },
420 InternalError {
421 details: String,
422 },
423 GeneratorNotFound,
424}
425
426#[derive(Debug, thiserror::Error)]
427pub enum TypeError {
428 #[error("Cannot apply {operator} operator to {operand_category}")]
429 LogicalOperatorNotApplicable {
430 operator: LogicalOp,
431 operand_category: OperandCategory,
432 fragment: Fragment,
433 },
434
435 #[error("Cannot apply '{operator}' operator to {left} and {right}")]
436 BinaryOperatorNotApplicable {
437 operator: BinaryOp,
438 left: ValueType,
439 right: ValueType,
440 fragment: Fragment,
441 },
442
443 #[error("unsupported cast from {from} to {to}")]
444 UnsupportedCast {
445 from: ValueType,
446 to: ValueType,
447 fragment: Fragment,
448 },
449
450 #[error("failed to cast to {target}")]
451 CastToNumberFailed {
452 target: ValueType,
453 fragment: Fragment,
454 cause: Box<TypeError>,
455 },
456
457 #[error("failed to cast to {target}")]
458 CastToTemporalFailed {
459 target: ValueType,
460 fragment: Fragment,
461 cause: Box<TypeError>,
462 },
463
464 #[error("failed to cast to bool")]
465 CastToBooleanFailed {
466 fragment: Fragment,
467 cause: Box<TypeError>,
468 },
469
470 #[error("failed to cast to {target}")]
471 CastToUuidFailed {
472 target: ValueType,
473 fragment: Fragment,
474 cause: Box<TypeError>,
475 },
476
477 #[error("failed to cast BLOB to UTF8")]
478 CastBlobToUtf8Failed {
479 fragment: Fragment,
480 cause: Box<TypeError>,
481 },
482
483 #[error("{message}")]
484 ConstraintViolation {
485 kind: ConstraintKind,
486 message: String,
487 fragment: Fragment,
488 },
489
490 #[error("invalid number format")]
491 InvalidNumberFormat {
492 target: ValueType,
493 fragment: Fragment,
494 },
495
496 #[error("number out of range")]
497 NumberOutOfRange {
498 target: ValueType,
499 fragment: Fragment,
500 descriptor: Option<NumberOutOfRangeDescriptor>,
501 },
502
503 #[error("division by zero")]
504 DivisionByZero {
505 target: ValueType,
506 fragment: Fragment,
507 },
508
509 #[error("NaN not allowed")]
510 NanNotAllowed,
511
512 #[error("too large for precise float conversion")]
513 IntegerPrecisionLoss {
514 object_type: ValueType,
515 target: ValueType,
516 fragment: Fragment,
517 },
518
519 #[error("decimal scale exceeds precision")]
520 DecimalScaleExceedsPrecision {
521 scale: u8,
522 precision: u8,
523 fragment: Fragment,
524 },
525
526 #[error("invalid decimal precision")]
527 DecimalPrecisionInvalid {
528 precision: u8,
529 },
530
531 #[error("invalid boolean format")]
532 InvalidBooleanFormat {
533 fragment: Fragment,
534 },
535
536 #[error("empty boolean value")]
537 EmptyBooleanValue {
538 fragment: Fragment,
539 },
540
541 #[error("invalid boolean")]
542 InvalidNumberBoolean {
543 fragment: Fragment,
544 },
545
546 #[error("{message}")]
547 Temporal {
548 kind: TemporalKind,
549 message: String,
550 fragment: Fragment,
551 },
552
553 #[error("invalid UUID v4 format")]
554 InvalidUuid4Format {
555 fragment: Fragment,
556 },
557
558 #[error("invalid UUID v7 format")]
559 InvalidUuid7Format {
560 fragment: Fragment,
561 },
562
563 #[error("{message}")]
564 BlobEncoding {
565 kind: BlobEncodingKind,
566 message: String,
567 fragment: Fragment,
568 },
569
570 #[error("Serde deserialization error: {message}")]
571 SerdeDeserialize {
572 message: String,
573 },
574
575 #[error("Serde serialization error: {message}")]
576 SerdeSerialize {
577 message: String,
578 },
579
580 #[error("Keycode serialization error: {message}")]
581 SerdeKeycode {
582 message: String,
583 },
584
585 #[error("Array conversion error: {message}")]
586 ArrayConversion {
587 message: String,
588 },
589
590 #[error("UTF-8 conversion error: {message}")]
591 Utf8Conversion {
592 message: String,
593 },
594
595 #[error("Integer conversion error: {message}")]
596 IntegerConversion {
597 message: String,
598 },
599
600 #[error("{message}")]
601 Network {
602 kind: NetworkErrorKind,
603 message: String,
604 },
605
606 #[error("{message}")]
607 Auth {
608 kind: AuthErrorKind,
609 message: String,
610 },
611
612 #[error("dictionary entry ID {value} exceeds maximum {max_value} for type {id_type}")]
613 DictionaryCapacityExceeded {
614 id_type: ValueType,
615 value: u128,
616 max_value: u128,
617 },
618
619 #[error("{message}")]
620 AssertionFailed {
621 fragment: Fragment,
622 message: String,
623 expression: Option<String>,
624 },
625
626 #[error("{message}")]
627 Function {
628 kind: FunctionErrorKind,
629 message: String,
630 fragment: Fragment,
631 },
632
633 #[error("{message}")]
634 Ast {
635 kind: AstErrorKind,
636 message: String,
637 fragment: Fragment,
638 },
639
640 #[error("{message}")]
641 Runtime {
642 kind: RuntimeErrorKind,
643 message: String,
644 },
645
646 #[error("{message}")]
647 Procedure {
648 kind: ProcedureErrorKind,
649 message: String,
650 fragment: Fragment,
651 },
652}
653
654#[derive(Debug, Clone, PartialEq)]
655pub struct NumberOutOfRangeDescriptor {
656 pub namespace: Option<String>,
657 pub table: Option<String>,
658 pub column: Option<String>,
659 pub column_type: Option<ValueType>,
660}
661
662impl NumberOutOfRangeDescriptor {
663 pub fn location_string(&self) -> String {
664 match (self.namespace.as_deref(), self.table.as_deref(), self.column.as_deref()) {
665 (Some(s), Some(t), Some(c)) => format!("{}::{}.{}", s, t, c),
666 (Some(s), Some(t), None) => format!("{}::{}", s, t),
667 (None, Some(t), Some(c)) => format!("{}.{}", t, c),
668 (Some(s), None, Some(c)) => format!("{}::{}", s, c),
669 (Some(s), None, None) => s.to_string(),
670 (None, Some(t), None) => t.to_string(),
671 (None, None, Some(c)) => c.to_string(),
672 (None, None, None) => "unknown location".to_string(),
673 }
674 }
675}
676
677#[derive(Debug, PartialEq)]
678pub struct Error(pub Box<Diagnostic>);
679
680impl Deref for Error {
681 type Target = Diagnostic;
682
683 fn deref(&self) -> &Self::Target {
684 &self.0
685 }
686}
687
688impl DerefMut for Error {
689 fn deref_mut(&mut self) -> &mut Self::Target {
690 &mut self.0
691 }
692}
693
694impl Display for Error {
695 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
696 let out = DefaultRenderer::render_string(&self.0);
697 f.write_str(out.as_str())
698 }
699}
700
701impl Error {
702 pub fn diagnostic(self) -> Diagnostic {
703 *self.0
704 }
705}
706
707impl error::Error for Error {}
708
709impl de::Error for Error {
710 fn custom<T: Display>(msg: T) -> Self {
711 TypeError::SerdeDeserialize {
712 message: msg.to_string(),
713 }
714 .into()
715 }
716}
717
718impl ser::Error for Error {
719 fn custom<T: Display>(msg: T) -> Self {
720 TypeError::SerdeSerialize {
721 message: msg.to_string(),
722 }
723 .into()
724 }
725}
726
727impl From<num::TryFromIntError> for Error {
728 fn from(err: num::TryFromIntError) -> Self {
729 TypeError::IntegerConversion {
730 message: err.to_string(),
731 }
732 .into()
733 }
734}
735
736impl From<TryFromSliceError> for Error {
737 fn from(err: TryFromSliceError) -> Self {
738 TypeError::ArrayConversion {
739 message: err.to_string(),
740 }
741 .into()
742 }
743}
744
745impl From<string::FromUtf8Error> for Error {
746 fn from(err: string::FromUtf8Error) -> Self {
747 TypeError::Utf8Conversion {
748 message: err.to_string(),
749 }
750 .into()
751 }
752}
753
754impl From<TypeError> for Error {
755 fn from(err: TypeError) -> Self {
756 Error(Box::new(err.into_diagnostic()))
757 }
758}
759
760impl From<SystemColumnsError> for Error {
761 fn from(err: SystemColumnsError) -> Self {
762 Error(Box::new(err.into_diagnostic()))
763 }
764}
765
766impl From<Box<TypeError>> for Error {
767 fn from(err: Box<TypeError>) -> Self {
768 Error(Box::new(err.into_diagnostic()))
769 }
770}
771
772impl From<num::TryFromIntError> for TypeError {
773 fn from(err: num::TryFromIntError) -> Self {
774 TypeError::IntegerConversion {
775 message: err.to_string(),
776 }
777 }
778}
779
780impl From<TryFromSliceError> for TypeError {
781 fn from(err: TryFromSliceError) -> Self {
782 TypeError::ArrayConversion {
783 message: err.to_string(),
784 }
785 }
786}
787
788impl From<string::FromUtf8Error> for TypeError {
789 fn from(err: string::FromUtf8Error) -> Self {
790 TypeError::Utf8Conversion {
791 message: err.to_string(),
792 }
793 }
794}
795
796impl de::Error for TypeError {
797 fn custom<T: Display>(msg: T) -> Self {
798 TypeError::SerdeDeserialize {
799 message: msg.to_string(),
800 }
801 }
802}
803
804impl ser::Error for TypeError {
805 fn custom<T: Display>(msg: T) -> Self {
806 TypeError::SerdeSerialize {
807 message: msg.to_string(),
808 }
809 }
810}