1use duck_diagnostic::*;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4enum SqlError {
5 SyntaxError,
6 UnknownTable,
7 UnknownColumn,
8 AmbiguousColumn,
9 TypeMismatch,
10 DivisionByZero,
11 FullTableScan,
12 DeprecatedSyntax,
13}
14
15impl DiagnosticCode for SqlError {
16 fn code(&self) -> &str {
17 match self {
18 Self::SyntaxError => "SQL0001",
19 Self::UnknownTable => "SQL0002",
20 Self::UnknownColumn => "SQL0003",
21 Self::AmbiguousColumn => "SQL0004",
22 Self::TypeMismatch => "SQL0005",
23 Self::DivisionByZero => "SQL0006",
24 Self::FullTableScan => "SQL-W001",
25 Self::DeprecatedSyntax => "SQL-W002",
26 }
27 }
28
29 fn severity(&self) -> Severity {
30 match self {
31 Self::FullTableScan | Self::DeprecatedSyntax => Severity::Warning,
32 _ => Severity::Error,
33 }
34 }
35}
36
37fn main() {
38 let query = r#"SELECT u.name, o.total
39FROM users u
40JOIN orders o ON u.id = o.user_id
41WHERE u.age / 0 > 10
42 AND o.status = active"#;
43
44 let mut engine = DiagnosticEngine::<SqlError>::new();
45
46 engine.emit(
47 Diagnostic::new(SqlError::DivisionByZero, "division by zero in expression")
48 .with_label(Label::primary(
49 Span::new("query.sql", 4, 6, 11),
50 Some("this will always fail at runtime".into()),
51 ))
52 .with_note("division by a literal zero is never valid"),
53 );
54
55 engine.emit(
56 Diagnostic::new(SqlError::UnknownColumn, "unknown column `active`")
57 .with_label(Label::primary(
58 Span::new("query.sql", 5, 18, 6),
59 Some("not a known column".into()),
60 ))
61 .with_help("did you mean the string `'active'`?"),
62 );
63
64 engine.emit(
65 Diagnostic::new(SqlError::FullTableScan, "query requires a full table scan on `users`")
66 .with_label(Label::primary(
67 Span::new("query.sql", 2, 5, 7),
68 Some("no index on `users.age`".into()),
69 ))
70 .with_help("consider adding an index: CREATE INDEX idx_users_age ON users(age)"),
71 );
72
73 engine.print_all(query);
74}