1use std::path::PathBuf;
2use thiserror::Error;
3
4#[derive(Error, Debug)]
5#[allow(dead_code)]
6pub enum DbtLineageError {
7 #[error("dbt project not found: no dbt_project.yml in {0}")]
8 ProjectNotFound(PathBuf),
9
10 #[error("failed to read file {path}: {source}")]
11 FileReadError {
12 path: PathBuf,
13 source: std::io::Error,
14 },
15
16 #[error("failed to parse YAML in {path}: {source}")]
17 YamlParseError {
18 path: PathBuf,
19 source: serde_saphyr::Error,
20 },
21
22 #[error("model not found: {0}")]
23 ModelNotFound(String),
24
25 #[error("cycle detected in lineage graph")]
26 CycleDetected,
27
28 #[error("duplicate model name '{name}' found in {path1} and {path2}")]
29 DuplicateModel {
30 name: String,
31 path1: PathBuf,
32 path2: PathBuf,
33 },
34
35 #[error("failed to parse artifact {path}: {source}")]
36 ArtifactParseError {
37 path: PathBuf,
38 source: serde_json::Error,
39 },
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45 use std::io;
46
47 #[test]
48 fn test_error_display() {
49 let err = DbtLineageError::ProjectNotFound(PathBuf::from("/foo"));
50 assert_eq!(
51 err.to_string(),
52 "dbt project not found: no dbt_project.yml in /foo"
53 );
54
55 let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
56 let err = DbtLineageError::FileReadError {
57 path: PathBuf::from("/bar.sql"),
58 source: io_err,
59 };
60 assert!(err.to_string().contains("/bar.sql"));
61
62 let err = DbtLineageError::ModelNotFound("orders".into());
63 assert_eq!(err.to_string(), "model not found: orders");
64
65 let err = DbtLineageError::CycleDetected;
66 assert_eq!(err.to_string(), "cycle detected in lineage graph");
67
68 let err = DbtLineageError::DuplicateModel {
69 name: "orders".into(),
70 path1: PathBuf::from("a.sql"),
71 path2: PathBuf::from("b.sql"),
72 };
73 assert!(err.to_string().contains("duplicate model name"));
74 assert!(err.to_string().contains("orders"));
75 }
76}