Skip to main content

toasty_cli/
lib.rs

1#![warn(missing_docs)]
2//! A library for building Toasty command-line tools.
3//!
4//! `toasty-cli` provides [`ToastyCli`], a ready-made CLI runner that wraps a
5//! [`toasty::Db`] handle and exposes database migration subcommands (generate,
6//! apply, drop, reset, snapshot). It uses [clap] for argument parsing and
7//! [dialoguer] for interactive prompts.
8//!
9//! The crate also exposes the underlying configuration used by the command
10//! runner. Reusable migration history, snapshot, and generation types live in
11//! [`toasty::migration`].
12//!
13//! # Main types
14//!
15//! - [`ToastyCli`] — parses CLI arguments and dispatches to the appropriate
16//!   migration subcommand.
17//! - [`Config`] / [`MigrationConfig`] — configure migration paths, prefix
18//!   styles, and checksum behavior. Loaded from a `Toasty.toml` file or built
19//!   programmatically.
20//! - [`toasty::migration::History`] / [`toasty::migration::HistoryEntry`] —
21//!   read and write the TOML history that tracks which migrations exist.
22//! - [`toasty::migration::Snapshot`] — read and write schema snapshot TOML
23//!   files.
24//!
25//! # Examples
26//!
27//! ```ignore
28//! use toasty_cli::ToastyCli;
29//!
30//! let db = toasty::Db::builder("sqlite::memory:").build().await?;
31//! let cli = ToastyCli::new(db);
32//! cli.parse_and_run().await?;
33//! ```
34
35mod config;
36mod migration;
37mod theme;
38mod utility;
39
40pub use config::Config;
41pub use migration::{
42    ApplyCommand, DropCommand, GenerateCommand, MigrationCommand, MigrationConfig,
43    MigrationPrefixStyle, ResetCommand, SnapshotCommand,
44};
45
46use anyhow::Result;
47use clap::Parser;
48use toasty::Db;
49
50/// A CLI runner that dispatches migration subcommands against a [`Db`].
51///
52/// `ToastyCli` holds a database connection and a [`Config`]. Call
53/// [`parse_and_run`](Self::parse_and_run) to parse `std::env::args` and
54/// execute the matching subcommand, or [`parse_from`](Self::parse_from) to
55/// parse from an arbitrary iterator (useful for testing).
56///
57/// # Examples
58///
59/// ```ignore
60/// use toasty_cli::{ToastyCli, Config, MigrationConfig};
61///
62/// let config = Config::new()
63///     .migration(MigrationConfig::new().path("db"));
64/// let db = toasty::Db::builder("sqlite::memory:").build().await?;
65/// let cli = ToastyCli::with_config(db, config);
66/// cli.parse_from(["toasty", "migration", "apply"]).await?;
67/// ```
68pub struct ToastyCli {
69    db: Db,
70    config: Config,
71}
72
73impl ToastyCli {
74    /// Create a new ToastyCli instance with the given database connection
75    pub fn new(db: Db) -> Self {
76        Self {
77            db,
78            config: Config::default(),
79        }
80    }
81
82    /// Create a new ToastyCli instance with a custom configuration
83    pub fn with_config(db: Db, config: Config) -> Self {
84        Self { db, config }
85    }
86
87    /// Get a reference to the configuration
88    pub fn config(&self) -> &Config {
89        &self.config
90    }
91
92    /// Parse and execute CLI commands from command-line arguments
93    pub async fn parse_and_run(&self) -> Result<()> {
94        let cli = Cli::parse();
95        self.run(cli).await
96    }
97
98    /// Parse and execute CLI commands from an iterator of arguments
99    pub async fn parse_from<I, T>(&self, args: I) -> Result<()>
100    where
101        I: IntoIterator<Item = T>,
102        T: Into<std::ffi::OsString> + Clone,
103    {
104        let cli = Cli::parse_from(args);
105        self.run(cli).await
106    }
107
108    async fn run(&self, cli: Cli) -> Result<()> {
109        match cli.command {
110            Command::Migration(cmd) => cmd.run(&self.db, &self.config).await,
111        }
112    }
113}
114
115#[derive(Parser, Debug)]
116#[command(name = "toasty")]
117#[command(about = "Toasty CLI - Database migration and management tool")]
118#[command(version)]
119struct Cli {
120    #[command(subcommand)]
121    command: Command,
122}
123
124#[derive(Parser, Debug)]
125enum Command {
126    /// Database migration commands
127    Migration(migration::MigrationCommand),
128}