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("Database unreachable: {0}")]
48 #[diagnostic(code(prax::database_unreachable))]
49 Unreachable(String),
50
51 #[error("{0}")]
57 #[diagnostic(code(prax::feature_unavailable))]
58 FeatureUnavailable(String),
59
60 #[error("Command error: {0}")]
62 #[diagnostic(code(prax::command))]
63 Command(String),
64
65 #[error("Format error: {0}")]
67 #[diagnostic(code(prax::format))]
68 Format(String),
69
70 #[error("Codegen error: {0}")]
72 #[diagnostic(code(prax::codegen))]
73 Codegen(String),
74}
75
76impl From<toml::de::Error> for CliError {
77 fn from(err: toml::de::Error) -> Self {
78 CliError::Config(format!("Failed to parse TOML: {}", err))
79 }
80}
81
82impl From<toml::ser::Error> for CliError {
83 fn from(err: toml::ser::Error) -> Self {
84 CliError::Config(format!("Failed to serialize TOML: {}", err))
85 }
86}
87
88impl From<prax_schema::LoadError> for CliError {
89 fn from(e: prax_schema::LoadError) -> Self {
90 use prax_schema::SchemaError;
91 let resolved = render_schema_error(&e.error, &e.sources);
93 match &e.error {
94 SchemaError::ValidationFailed { .. } => CliError::Validation(resolved),
95 _ => CliError::Schema(resolved),
96 }
97 }
98}
99
100impl From<prax_schema::SchemaError> for CliError {
101 fn from(e: prax_schema::SchemaError) -> Self {
102 use prax_schema::SchemaError;
103 match &e {
104 SchemaError::ValidationFailed { .. } => CliError::Validation(e.to_string()),
105 _ => CliError::Schema(e.to_string()),
106 }
107 }
108}
109
110fn render_schema_error(err: &prax_schema::SchemaError, sources: &prax_schema::SourceMap) -> String {
112 use prax_schema::SchemaError;
113 use std::fmt::Write;
114
115 let mut out = err.to_string();
116 match err {
117 SchemaError::ParseInFile { source, inner } => {
118 if let Some(p) = sources.path_of(*source) {
119 let _ = write!(out, "\n in: {}\n detail: {}", p.display(), inner);
120 }
121 }
122 SchemaError::DuplicateAcrossFiles { first, second, .. }
123 | SchemaError::MultipleDatasource { first, second } => {
124 if let (Some(a), Some(b)) = (
125 sources.path_of(first.source),
126 sources.path_of(second.source),
127 ) {
128 let _ = write!(
129 out,
130 "\n first: {} (bytes {}..{})\n second: {} (bytes {}..{})",
131 a.display(),
132 first.span.start,
133 first.span.end,
134 b.display(),
135 second.span.start,
136 second.span.end,
137 );
138 }
139 }
140 SchemaError::ValidationFailed { errors, .. } => {
141 for (i, e) in errors.iter().enumerate() {
142 let _ = write!(out, "\n {}. {}", i + 1, render_schema_error(e, sources));
143 }
144 }
145 _ => {}
146 }
147 out
148}