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