use std::{io::IsTerminal, path::PathBuf};
use miette::{Diagnostic, GraphicalReportHandler, GraphicalTheme};
use thiserror::Error as ThisError;
#[derive(Debug, ThisError, Diagnostic)]
pub(crate) enum Warning {
#[error("no queries were found")]
#[diagnostic(
severity(Warning),
help(
"Cornucopia only generates code from annotated SQL queries. Make sure your queries directory path is correct and contains annotated queries. See https://cornucopia-rs.github.io/cornucopia/writing_queries/writing_queries.html for more."
)
)]
NoQueries,
#[error("`manifest.package.edition` is ignored")]
#[diagnostic(
severity(Warning),
help(
"Cornucopia controls the edition of the generated crate because the emitted code's syntax is tied to it. Remove this key from your config."
)
)]
IgnoredManifestEdition,
#[error("`manifest.package.rust-version` is ignored")]
#[diagnostic(
severity(Warning),
help(
"Cornucopia controls the MSRV of the generated crate because it is tied to the edition cornucopia emits for. Remove this key from your config."
)
)]
IgnoredManifestRustVersion,
#[error("`types.type-traits-mapping` is deprecated")]
#[diagnostic(
severity(Warning),
help(
"Use `types.custom` instead. See https://cornucopia-rs.github.io/cornucopia/configuration.html#custom-type-mappings for more."
)
)]
DeprecatedTypeTraitsMapping,
#[error("`types.type-attributes-mapping` is deprecated")]
#[diagnostic(
severity(Warning),
help(
"Use `types.custom` instead. See https://cornucopia-rs.github.io/cornucopia/configuration.html#custom-type-mappings for more."
)
)]
DeprecatedTypeAttributesMapping,
}
impl Warning {
fn render(&self, theme: GraphicalTheme) -> String {
let mut buff = String::new();
if GraphicalReportHandler::new()
.with_theme(theme)
.render_report(&mut buff, self)
.is_err()
{
format!("Warning: {self}")
} else {
buff
}
}
pub(crate) fn emit(&self) {
let theme = if std::io::stderr().is_terminal() && std::env::var_os("NO_COLOR").is_none() {
GraphicalTheme::unicode()
} else {
GraphicalTheme::unicode_nocolor()
};
eprintln!("{}", self.render(theme));
}
}
#[derive(Debug, ThisError, Diagnostic)]
#[error(transparent)]
#[diagnostic(transparent)]
pub enum Error {
Connection(#[from] crate::conn::error::Error),
ReadQueries(#[from] crate::read_queries::error::Error),
ParseQueries(#[from] Box<crate::parser::error::Error>),
ValidateQueries(#[from] Box<crate::validation::error::Error>),
Container(#[from] crate::container::error::Error),
PrepareQueries(#[from] Box<crate::prepare_queries::error::Error>),
LoadSchema(#[from] Box<crate::load_schema::error::Error>),
PersistCrate(#[from] PersistError),
Config(#[from] crate::config::ConfigError),
}
impl Error {
#[must_use]
pub fn report(self) -> String {
let mut buff = String::new();
if GraphicalReportHandler::new()
.with_theme(GraphicalTheme::unicode_nocolor())
.render_report(&mut buff, &self)
.is_err()
{
format!("Error: {self}")
} else {
buff
}
}
}
#[derive(Debug, ThisError, Diagnostic)]
#[error("Could not perform IO on file `{file_path}`: ({err})")]
pub struct PersistError {
pub(crate) file_path: PathBuf,
pub(crate) err: std::io::Error,
}
impl PersistError {
pub fn wrap(path: impl Into<PathBuf>) -> impl FnOnce(std::io::Error) -> PersistError {
|err| PersistError {
file_path: path.into(),
err,
}
}
}
#[cfg(test)]
mod tests {
use miette::GraphicalTheme;
use super::Warning;
#[test]
fn no_queries_warning_renders() {
let rendered = Warning::NoQueries.render(GraphicalTheme::unicode_nocolor());
assert!(rendered.contains("no queries were found"));
assert!(rendered.contains("annotated SQL queries"));
}
}