Skip to main content

dynoxide/import/
notice.rs

1//! What an import has to say, and how much it matters.
2//!
3//! Every message the importer raises carries a [`Concern`], decided at the
4//! point it is raised. That decision is the only thing standing between "the
5//! run printed a warning" and "the run refused to say it succeeded", and for a
6//! while it was made afresh at each of thirty call sites. Now a message is
7//! either something the run saw happen or it is not, and one function turns
8//! that into an exit code.
9
10/// How much a message matters.
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum Concern {
13    /// An original value was seen reaching the output. The run does not
14    /// report success while any of these stand: `dynoxide import` exits 3,
15    /// `--serve` and `--mcp` refuse to start, and `ImportSummary::exposures`
16    /// lists them.
17    ///
18    /// Only for what the run observed, never for what it could not rule out.
19    /// A caution raised on every ordinary import would make the non-zero
20    /// exit the normal outcome, and the flag that suppresses it the default.
21    Exposure,
22    /// Something that could have gone wrong, or that the run could not
23    /// check. Reported, and the exit code is unchanged.
24    Caution,
25}
26
27/// One message from an import.
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct Notice {
30    pub concern: Concern,
31    pub message: String,
32}
33
34impl Notice {
35    /// A value the run saw reach the output.
36    pub fn exposure(message: impl Into<String>) -> Self {
37        Self {
38            concern: Concern::Exposure,
39            message: message.into(),
40        }
41    }
42
43    /// Something worth saying that does not change the exit code.
44    pub fn caution(message: impl Into<String>) -> Self {
45        Self {
46            concern: Concern::Caution,
47            message: message.into(),
48        }
49    }
50
51    /// The same notice, named for the table it came from.
52    pub fn for_table(mut self, table: &str) -> Self {
53        self.message = format!("table '{table}': {}", self.message);
54        self
55    }
56}
57
58/// A notice prints as its message. It does not deref to one: the concern is
59/// the point of the type, and a notice that passed for a string anywhere a
60/// string is expected would lose it without a compile error.
61impl std::fmt::Display for Notice {
62    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63        f.write_str(&self.message)
64    }
65}