summaryrefslogtreecommitdiff
path: root/src/cli/recanonicalize.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/cli/recanonicalize.rs')
-rw-r--r--src/cli/recanonicalize.rs86
1 files changed, 86 insertions, 0 deletions
diff --git a/src/cli/recanonicalize.rs b/src/cli/recanonicalize.rs
new file mode 100644
index 0000000..9db5b77
--- /dev/null
+++ b/src/cli/recanonicalize.rs
@@ -0,0 +1,86 @@
+use sqlx::sqlite::SqlitePool;
+
+use crate::{app::App, db};
+
+/// Command-line entry point for repairing canonical names in the `hi` database.
+/// This command may be necessary after an upgrade, if the canonical forms of
+/// names has changed. It will re-calculate the canonical form of each name in
+/// the database, based on its display form, and store the results back to the
+/// database.
+///
+/// This is intended to be used as a Clap [Parser], to capture command-line
+/// arguments for the `hi-recanonicalize` command:
+///
+/// ```no_run
+/// # use hi::cli::recanonicalize::Error;
+/// #
+/// # #[tokio::main]
+/// # async fn main() -> Result<(), Error> {
+/// use clap::Parser;
+/// use hi::cli::recanonicalize::Args;
+///
+/// let args = Args::parse();
+/// args.run().await?;
+/// # Ok(())
+/// # }
+/// ```
+#[derive(clap::Parser)]
+#[command(
+ version,
+ about = "Recanonicalize names in the `hi` database.",
+ long_about = r#"Recanonicalize names in the `hi` database.
+
+The `hi` server must not be running while this command is run.
+
+The database at `--database-url` will also be created, or upgraded, automatically."#
+)]
+pub struct Args {
+ /// Sqlite URL or path for the `hi` database
+ #[arg(short, long, env, default_value = "sqlite://.hi")]
+ database_url: String,
+
+ /// Sqlite URL or path for a backup of the `hi` database during upgrades
+ #[arg(short = 'D', long, env, default_value = "sqlite://.hi.backup")]
+ backup_database_url: String,
+}
+
+impl Args {
+ /// Recanonicalizes the `hi` database, using the parsed configuation in
+ /// `self`.
+ ///
+ /// This will perform the following tasks:
+ ///
+ /// * Migrate the `hi` database (at `--database-url`).
+ /// * Recanonicalize names in the `login` and `channel` tables.
+ ///
+ /// # Errors
+ ///
+ /// Will return `Err` if the canonicalization or database upgrade processes
+ /// fail. The specific [`Error`] variant will expose the cause
+ /// of the failure.
+ pub async fn run(self) -> Result<(), Error> {
+ let pool = self.pool().await?;
+
+ let app = App::from(pool);
+ app.logins().recanonicalize().await?;
+ app.channels().recanonicalize().await?;
+
+ Ok(())
+ }
+
+ async fn pool(&self) -> Result<SqlitePool, db::Error> {
+ db::prepare(&self.database_url, &self.backup_database_url).await
+ }
+}
+
+/// Errors that can be raised by [`Args::run`].
+#[derive(Debug, thiserror::Error)]
+#[error(transparent)]
+pub enum Error {
+ // /// Failure due to `io::Error`. See [`io::Error`].
+ // Io(#[from] io::Error),
+ /// Failure due to a database initialization error. See [`db::Error`].
+ Database(#[from] db::Error),
+ /// Failure due to a data manipulation error. See [`sqlx::Error`].
+ Sqlx(#[from] sqlx::Error),
+}