Skip to main content

bhtune_db/
error.rs

1//! `bhtune-db`'s error type.
2
3/// Everything that can go wrong opening the database, running migrations, or executing a
4/// query.
5#[derive(Debug, thiserror::Error)]
6pub enum DbError {
7    #[error("failed to open or connect to the database: {0}")]
8    Connect(#[source] sqlx::Error),
9
10    #[error("failed to run database migrations: {0}")]
11    Migrate(#[source] sqlx::migrate::MigrateError),
12
13    #[error("database query failed: {0}")]
14    Query(#[source] sqlx::Error),
15
16    /// A value read back from a TEXT enum column didn't match any known
17    /// variant. This can only happen if the row was written by something
18    /// other than this crate (or a future version wrote a variant this
19    /// version doesn't know about) — the `CHECK` constraints on every
20    /// enum-shaped column prevent the database itself from ever storing an
21    /// invalid value.
22    #[error("column {column:?} held an unrecognized value: {value:?}")]
23    InvalidEnumValue { column: &'static str, value: String },
24
25    /// An MV-actuation finalization API was given [`crate::models::MvActuationStatus::Pending`].
26    /// Pending is the initial state inserted by
27    /// [`crate::models::TuneMvActuationRow::insert_pending`], not a terminal result.
28    #[error("pending is not a terminal MV actuation status")]
29    InvalidMvActuationFinalStatus,
30
31    /// A JSON column (`tune_runs.template_snapshot_json`/`tags_json`/
32    /// `timing_metrics_json`, `dcs_templates.versions_json`) held syntactically valid JSON
33    /// -- the schema's `CHECK (json_valid(...))` already guarantees that much -- but it
34    /// didn't deserialize into the Rust shape the column is supposed to hold. This can
35    /// happen honestly, not just from external tampering: an older snapshot can predate a
36    /// field a later release added to its typed representation.
37    #[error("column {column:?} held JSON that didn't match the expected shape: {source}")]
38    InvalidJsonShape {
39        column: &'static str,
40        #[source]
41        source: serde_json::Error,
42    },
43
44    /// [`crate::models::DcsTemplateRow::delete`] targeted a template that at least one
45    /// `loops` row still references. The schema's `ON DELETE RESTRICT` foreign key is what
46    /// actually enforces this; this variant exists so `bhtune-cli`'s `template delete` can
47    /// turn the resulting SQLite foreign-key-violation error into a message naming the
48    /// template rather than a raw SQL error, without needing its own `sqlx` dependency just
49    /// to inspect the error kind.
50    #[error("template {id} is still referenced by one or more saved loops and cannot be deleted")]
51    TemplateInUse { id: i64 },
52
53    /// [`crate::backup::backup_to`]'s destination already exists. Refused rather than
54    /// silently overwritten — clobbering a previous backup because of a reused filename
55    /// would itself be a data-loss bug.
56    #[error("backup destination already exists: {}", .0.display())]
57    BackupDestinationExists(std::path::PathBuf),
58
59    /// [`crate::backup::restore_from`] (or [`crate::backup::backup_to`]'s own post-write
60    /// check) determined a file is not a usable bhtune backup: it failed
61    /// `PRAGMA integrity_check`, or it doesn't contain a `tune_runs` table.
62    #[error("not a valid bhtune backup file: {0}")]
63    InvalidBackup(String),
64
65    /// A filesystem operation during [`crate::backup::backup_to`]/
66    /// [`crate::backup::restore_from`] (copying, renaming, or removing a file) failed.
67    #[error("backup/restore file operation failed: {0}")]
68    Io(#[source] std::io::Error),
69
70    /// [`crate::backup::restore_from`] found another connection (in this process or
71    /// another) still attached to the live database. Restoring while that's true risks
72    /// desynchronizing whatever holds it: its view of the file would silently stop matching
73    /// what's on disk the moment the restore replaces it.
74    #[error(
75        "database at {} appears to be in use by another connection or process -- close it before restoring",
76        .0.display()
77    )]
78    DatabaseInUse(std::path::PathBuf),
79}
80
81pub type DbResult<T> = Result<T, DbError>;