1use miette::Diagnostic;
4use thiserror::Error;
5
6pub type CliResult<T> = Result<T, CliError>;
8
9#[derive(Error, Debug, Diagnostic)]
11pub enum CliError {
12 #[error("IO error: {0}")]
14 #[diagnostic(code(prax::io))]
15 Io(#[from] std::io::Error),
16
17 #[error("Configuration error: {0}")]
19 #[diagnostic(code(prax::config))]
20 Config(String),
21
22 #[error("Schema error: {0}")]
24 #[diagnostic(code(prax::schema))]
25 Schema(String),
26
27 #[error("Validation error: {0}")]
29 #[diagnostic(code(prax::validation))]
30 Validation(String),
31
32 #[error("Migration error: {0}")]
34 #[diagnostic(code(prax::migration))]
35 Migration(String),
36
37 #[error("Database error: {0}")]
39 #[diagnostic(code(prax::database))]
40 Database(String),
41
42 #[error("Command error: {0}")]
44 #[diagnostic(code(prax::command))]
45 Command(String),
46
47 #[error("Format error: {0}")]
49 #[diagnostic(code(prax::format))]
50 Format(String),
51
52 #[error("Codegen error: {0}")]
54 #[diagnostic(code(prax::codegen))]
55 Codegen(String),
56}
57
58impl From<toml::de::Error> for CliError {
59 fn from(err: toml::de::Error) -> Self {
60 CliError::Config(format!("Failed to parse TOML: {}", err))
61 }
62}
63
64impl From<toml::ser::Error> for CliError {
65 fn from(err: toml::ser::Error) -> Self {
66 CliError::Config(format!("Failed to serialize TOML: {}", err))
67 }
68}
69
70impl From<prax_schema::LoadError> for CliError {
71 fn from(e: prax_schema::LoadError) -> Self {
72 use prax_schema::SchemaError;
73 let resolved = render_schema_error(&e.error, &e.sources);
75 match &e.error {
76 SchemaError::ValidationFailed { .. } => CliError::Validation(resolved),
77 _ => CliError::Schema(resolved),
78 }
79 }
80}
81
82impl From<prax_schema::SchemaError> for CliError {
83 fn from(e: prax_schema::SchemaError) -> Self {
84 use prax_schema::SchemaError;
85 match &e {
86 SchemaError::ValidationFailed { .. } => CliError::Validation(e.to_string()),
87 _ => CliError::Schema(e.to_string()),
88 }
89 }
90}
91
92fn render_schema_error(err: &prax_schema::SchemaError, sources: &prax_schema::SourceMap) -> String {
94 use prax_schema::SchemaError;
95 use std::fmt::Write;
96
97 let mut out = err.to_string();
98 match err {
99 SchemaError::ParseInFile { source, inner } => {
100 if let Some(p) = sources.path_of(*source) {
101 let _ = write!(out, "\n in: {}\n detail: {}", p.display(), inner);
102 }
103 }
104 SchemaError::DuplicateAcrossFiles { first, second, .. }
105 | SchemaError::MultipleDatasource { first, second } => {
106 if let (Some(a), Some(b)) = (
107 sources.path_of(first.source),
108 sources.path_of(second.source),
109 ) {
110 let _ = write!(
111 out,
112 "\n first: {} (bytes {}..{})\n second: {} (bytes {}..{})",
113 a.display(),
114 first.span.start,
115 first.span.end,
116 b.display(),
117 second.span.start,
118 second.span.end,
119 );
120 }
121 }
122 SchemaError::ValidationFailed { errors, .. } => {
123 for (i, e) in errors.iter().enumerate() {
124 let _ = write!(out, "\n {}. {}", i + 1, render_schema_error(e, sources));
125 }
126 }
127 _ => {}
128 }
129 out
130}