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::{fragment::Fragment, value::value_type::ValueType};
22
23#[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 rql: 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
42 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: ValueType,
49}
50
51impl Default for Diagnostic {
52 fn default() -> Self {
53 Self {
54 code: String::new(),
55 rql: 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_rql(&mut self, rql: String) {
76 self.rql = Some(rql.clone());
77
78 if let Some(ref mut cause) = self.cause {
79 let mut updated_cause = mem::take(cause.as_mut());
80 updated_cause.with_rql(rql);
81 **cause = updated_cause;
82 }
83 }
84
85 pub fn with_fragment(&mut self, new_fragment: Fragment) {
86 self.fragment = new_fragment;
87
88 if let Some(ref mut cause) = self.cause {
89 cause.with_fragment(self.fragment.clone());
90 }
91 }
92
93 pub fn fragment(&self) -> Option<Fragment> {
94 match &self.fragment {
95 Fragment::Statement {
96 ..
97 } => Some(self.fragment.clone()),
98 _ => None,
99 }
100 }
101}
102
103pub trait IntoDiagnostic {
104 fn into_diagnostic(self) -> Diagnostic;
105}
106
107#[derive(Debug, Clone, PartialEq)]
108pub enum UnaryOp {
109 Not,
110}
111
112impl Display for UnaryOp {
113 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
114 match self {
115 UnaryOp::Not => f.write_str("NOT"),
116 }
117 }
118}
119
120#[derive(Debug, Clone, PartialEq)]
121pub enum BinaryOp {
122 Add,
123 Sub,
124 Mul,
125 Div,
126 Rem,
127 Equal,
128 NotEqual,
129 LessThan,
130 LessThanEqual,
131 GreaterThan,
132 GreaterThanEqual,
133 Between,
134}
135
136impl BinaryOp {
137 pub fn symbol(&self) -> &'static str {
138 match self {
139 BinaryOp::Add => "+",
140 BinaryOp::Sub => "-",
141 BinaryOp::Mul => "*",
142 BinaryOp::Div => "/",
143 BinaryOp::Rem => "%",
144 BinaryOp::Equal => "==",
145 BinaryOp::NotEqual => "!=",
146 BinaryOp::LessThan => "<",
147 BinaryOp::LessThanEqual => "<=",
148 BinaryOp::GreaterThan => ">",
149 BinaryOp::GreaterThanEqual => ">=",
150 BinaryOp::Between => "BETWEEN",
151 }
152 }
153}
154
155impl Display for BinaryOp {
156 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
157 f.write_str(self.symbol())
158 }
159}
160
161#[derive(Debug, Clone, PartialEq)]
162pub enum LogicalOp {
163 Not,
164 And,
165 Or,
166 Xor,
167}
168
169impl Display for LogicalOp {
170 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
171 match self {
172 LogicalOp::Not => f.write_str("NOT"),
173 LogicalOp::And => f.write_str("AND"),
174 LogicalOp::Or => f.write_str("OR"),
175 LogicalOp::Xor => f.write_str("XOR"),
176 }
177 }
178}
179
180#[derive(Debug, Clone, PartialEq)]
181pub enum OperandCategory {
182 Number,
183 Text,
184 Temporal,
185 Uuid,
186}
187
188impl Display for OperandCategory {
189 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
190 match self {
191 OperandCategory::Number => f.write_str("number"),
192 OperandCategory::Text => f.write_str("text"),
193 OperandCategory::Temporal => f.write_str("temporal value"),
194 OperandCategory::Uuid => f.write_str("UUID"),
195 }
196 }
197}
198
199#[derive(Debug, Clone, Copy, PartialEq)]
200pub enum ColumnReadReason {
201 WrongType,
202 DoesNotFit,
203}
204
205impl Display for ColumnReadReason {
206 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
207 match self {
208 ColumnReadReason::WrongType => f.write_str("wrong type"),
209 ColumnReadReason::DoesNotFit => f.write_str("does not fit"),
210 }
211 }
212}
213
214#[derive(Debug, Clone, PartialEq)]
215pub enum ConstraintKind {
216 Utf8MaxBytes {
217 actual: usize,
218 max: usize,
219 },
220 BlobMaxBytes {
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 InvalidColumnProperty,
309 InvalidPolicy,
310 UnexpectedToken {
311 expected: String,
312 },
313}
314
315#[derive(Debug, Clone, PartialEq)]
316pub enum ProcedureErrorKind {
317 UndefinedProcedure {
318 name: String,
319 },
320
321 NoRegisteredImplementation {
322 name: String,
323 },
324}
325
326#[derive(Debug, Clone, PartialEq)]
327pub enum RuntimeErrorKind {
328 VariableNotFound {
329 fragment: Fragment,
330 },
331 VariableIsDataframe {
332 name: String,
333 },
334 VariableIsClosure {
335 fragment: Fragment,
336 },
337 VariableIsImmutable {
338 name: String,
339 },
340 MaxIterationsExceeded {
341 limit: usize,
342 },
343 FieldNotFound {
344 variable: String,
345 field: String,
346 available: Vec<String>,
347 },
348 AppendTargetNotFrame {
349 name: String,
350 },
351 AppendColumnMismatch {
352 name: String,
353 existing: Vec<String>,
354 incoming: Vec<String>,
355 fragment: Fragment,
356 },
357 ExpectedSingleColumn {
358 actual: usize,
359 },
360 ConditionalBranchMismatch {
361 expected: Vec<String>,
362 actual: Vec<String>,
363 fragment: Fragment,
364 },
365 ColumnLengthMismatch {
366 left: usize,
367 right: usize,
368 fragment: Fragment,
369 },
370}
371
372#[derive(Debug, Clone, PartialEq)]
373pub enum FunctionErrorKind {
374 ArityMismatch {
375 expected: usize,
376 actual: usize,
377 },
378 TooManyArguments {
379 max_args: usize,
380 actual: usize,
381 },
382}
383
384#[derive(Debug, thiserror::Error)]
385pub enum TypeError {
386 #[error("Cannot apply {operator} operator to {operand_category}")]
387 LogicalOperatorNotApplicable {
388 operator: LogicalOp,
389 operand_category: OperandCategory,
390 fragment: Fragment,
391 },
392
393 #[error("Cannot apply '{operator}' operator to {left} and {right}")]
394 BinaryOperatorNotApplicable {
395 operator: BinaryOp,
396 left: ValueType,
397 right: ValueType,
398 fragment: Fragment,
399 },
400
401 #[error("unsupported cast from {from} to {to}")]
402 UnsupportedCast {
403 from: ValueType,
404 to: ValueType,
405 fragment: Fragment,
406 },
407
408 #[error("{message}")]
409 ConstraintViolation {
410 kind: ConstraintKind,
411 message: String,
412 fragment: Fragment,
413 },
414
415 #[error("invalid number format")]
416 InvalidNumberFormat {
417 target: ValueType,
418 fragment: Fragment,
419 },
420
421 #[error("number out of range")]
422 NumberOutOfRange {
423 target: ValueType,
424 fragment: Fragment,
425 descriptor: Option<NumberOutOfRangeDescriptor>,
426 },
427
428 #[error("division by zero")]
429 DivisionByZero {
430 target: ValueType,
431 fragment: Fragment,
432 },
433
434 #[error("NaN not allowed")]
435 NanNotAllowed,
436
437 #[error("too large for precise float conversion")]
438 IntegerPrecisionLoss {
439 object_type: ValueType,
440 target: ValueType,
441 fragment: Fragment,
442 },
443
444 #[error("decimal scale exceeds precision")]
445 DecimalScaleExceedsPrecision {
446 scale: u8,
447 precision: u8,
448 fragment: Fragment,
449 },
450
451 #[error("invalid decimal precision")]
452 DecimalPrecisionInvalid {
453 precision: u8,
454 },
455
456 #[error("invalid boolean format")]
457 InvalidBooleanFormat {
458 fragment: Fragment,
459 },
460
461 #[error("empty boolean value")]
462 EmptyBooleanValue {
463 fragment: Fragment,
464 },
465
466 #[error("invalid boolean")]
467 InvalidNumberBoolean {
468 fragment: Fragment,
469 },
470
471 #[error("{message}")]
472 Temporal {
473 kind: TemporalKind,
474 message: String,
475 fragment: Fragment,
476 },
477
478 #[error("invalid UUID v4 format")]
479 InvalidUuid4Format {
480 fragment: Fragment,
481 },
482
483 #[error("invalid UUID v7 format")]
484 InvalidUuid7Format {
485 fragment: Fragment,
486 },
487
488 #[error("{message}")]
489 BlobEncoding {
490 kind: BlobEncodingKind,
491 message: String,
492 fragment: Fragment,
493 },
494
495 #[error("Serde deserialization error: {message}")]
496 SerdeDeserialize {
497 message: String,
498 },
499
500 #[error("Serde serialization error: {message}")]
501 SerdeSerialize {
502 message: String,
503 },
504
505 #[error("Keycode serialization error: {message}")]
506 SerdeKeycode {
507 message: String,
508 },
509
510 #[error("Array conversion error: {message}")]
511 ArrayConversion {
512 message: String,
513 },
514
515 #[error("UTF-8 conversion error: {message}")]
516 Utf8Conversion {
517 message: String,
518 },
519
520 #[error("Integer conversion error: {message}")]
521 IntegerConversion {
522 message: String,
523 },
524
525 #[error("cannot read {column_type} as {target}: {reason}")]
526 ColumnRead {
527 column_type: ValueType,
528 target: &'static str,
529 reason: ColumnReadReason,
530 },
531
532 #[error("dictionary entry ID {value} exceeds maximum {max_value} for type {id_type}")]
533 DictionaryCapacityExceeded {
534 id_type: ValueType,
535 value: u128,
536 max_value: u128,
537 },
538
539 #[error("{message}")]
540 Function {
541 kind: FunctionErrorKind,
542 message: String,
543 fragment: Fragment,
544 },
545
546 #[error("{message}")]
547 Ast {
548 kind: AstErrorKind,
549 message: String,
550 fragment: Fragment,
551 },
552
553 #[error("{message}")]
554 Runtime {
555 kind: RuntimeErrorKind,
556 message: String,
557 },
558
559 #[error("{message}")]
560 Procedure {
561 kind: ProcedureErrorKind,
562 message: String,
563 fragment: Fragment,
564 },
565}
566
567#[derive(Debug, Clone, PartialEq)]
568pub struct NumberOutOfRangeDescriptor {
569 pub namespace: Option<String>,
570 pub table: Option<String>,
571 pub column: Option<String>,
572 pub column_type: Option<ValueType>,
573}
574
575impl NumberOutOfRangeDescriptor {
576 pub fn location_string(&self) -> String {
577 match (self.namespace.as_deref(), self.table.as_deref(), self.column.as_deref()) {
578 (Some(s), Some(t), Some(c)) => format!("{}::{}.{}", s, t, c),
579 (Some(s), Some(t), None) => format!("{}::{}", s, t),
580 (None, Some(t), Some(c)) => format!("{}.{}", t, c),
581 (Some(s), None, Some(c)) => format!("{}::{}", s, c),
582 (Some(s), None, None) => s.to_string(),
583 (None, Some(t), None) => t.to_string(),
584 (None, None, Some(c)) => c.to_string(),
585 (None, None, None) => "unknown location".to_string(),
586 }
587 }
588}
589
590#[derive(Debug, PartialEq)]
591pub struct Error(pub Box<Diagnostic>);
592
593impl Deref for Error {
594 type Target = Diagnostic;
595
596 fn deref(&self) -> &Self::Target {
597 &self.0
598 }
599}
600
601impl DerefMut for Error {
602 fn deref_mut(&mut self) -> &mut Self::Target {
603 &mut self.0
604 }
605}
606
607impl Display for Error {
608 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
609 let out = DefaultRenderer::render_string(&self.0);
610 f.write_str(out.as_str())
611 }
612}
613
614impl Error {
615 pub fn diagnostic(self) -> Diagnostic {
616 *self.0
617 }
618}
619
620impl error::Error for Error {}
621
622impl de::Error for Error {
623 fn custom<T: Display>(msg: T) -> Self {
624 TypeError::SerdeDeserialize {
625 message: msg.to_string(),
626 }
627 .into()
628 }
629}
630
631impl ser::Error for Error {
632 fn custom<T: Display>(msg: T) -> Self {
633 TypeError::SerdeSerialize {
634 message: msg.to_string(),
635 }
636 .into()
637 }
638}
639
640impl From<num::TryFromIntError> for Error {
641 fn from(err: num::TryFromIntError) -> Self {
642 TypeError::IntegerConversion {
643 message: err.to_string(),
644 }
645 .into()
646 }
647}
648
649impl From<TryFromSliceError> for Error {
650 fn from(err: TryFromSliceError) -> Self {
651 TypeError::ArrayConversion {
652 message: err.to_string(),
653 }
654 .into()
655 }
656}
657
658impl From<string::FromUtf8Error> for Error {
659 fn from(err: string::FromUtf8Error) -> Self {
660 TypeError::Utf8Conversion {
661 message: err.to_string(),
662 }
663 .into()
664 }
665}
666
667impl From<TypeError> for Error {
668 fn from(err: TypeError) -> Self {
669 Error(Box::new(err.into_diagnostic()))
670 }
671}
672
673impl From<Box<TypeError>> for Error {
674 fn from(err: Box<TypeError>) -> Self {
675 Error(Box::new(err.into_diagnostic()))
676 }
677}
678
679impl From<num::TryFromIntError> for TypeError {
680 fn from(err: num::TryFromIntError) -> Self {
681 TypeError::IntegerConversion {
682 message: err.to_string(),
683 }
684 }
685}
686
687impl From<TryFromSliceError> for TypeError {
688 fn from(err: TryFromSliceError) -> Self {
689 TypeError::ArrayConversion {
690 message: err.to_string(),
691 }
692 }
693}
694
695impl From<string::FromUtf8Error> for TypeError {
696 fn from(err: string::FromUtf8Error) -> Self {
697 TypeError::Utf8Conversion {
698 message: err.to_string(),
699 }
700 }
701}
702
703impl de::Error for TypeError {
704 fn custom<T: Display>(msg: T) -> Self {
705 TypeError::SerdeDeserialize {
706 message: msg.to_string(),
707 }
708 }
709}
710
711impl ser::Error for TypeError {
712 fn custom<T: Display>(msg: T) -> Self {
713 TypeError::SerdeSerialize {
714 message: msg.to_string(),
715 }
716 }
717}