pub mod advisor;
pub mod checksum;
pub mod commands;
pub mod config;
pub mod db;
pub mod dependency;
pub mod dialect;
pub mod directive;
pub mod engines;
pub mod error;
pub mod guard;
pub mod history;
pub mod hooks;
pub mod migration;
pub mod multi;
pub mod placeholder;
pub mod preflight;
pub mod reversal;
pub mod safety;
pub mod schema;
pub mod sql_parser;
use std::path::PathBuf;
use config::WaypointConfig;
use db::DbClient;
use error::Result;
#[cfg(feature = "postgres")]
use tokio_postgres::Client;
pub use advisor::AdvisorReport;
pub use commands::changelog::ChangelogReport;
pub use commands::check_conflicts::ConflictReport;
pub use commands::diff::DiffReport;
pub use commands::drift::DriftReport;
pub use commands::explain::ExplainReport;
pub use commands::info::{MigrationInfo, MigrationState};
pub use commands::lint::LintReport;
pub use commands::migrate::MigrateReport;
pub use commands::repair::RepairReport;
pub use commands::safety::SafetyCommandReport;
pub use commands::simulate::SimulationReport;
pub use commands::snapshot::{RestoreReport, SnapshotReport};
pub use commands::undo::{UndoReport, UndoTarget};
pub use commands::validate::ValidateReport;
pub use config::CliOverrides;
pub use dialect::{DatabaseDialect, DialectKind};
pub use multi::MultiWaypoint;
pub use preflight::PreflightReport;
pub use safety::SafetyReport;
pub struct Waypoint {
pub config: WaypointConfig,
client: DbClient,
}
impl Waypoint {
pub async fn new(config: WaypointConfig) -> Result<Self> {
let conn_string = config.connection_string()?;
let client = connect_for_url(&conn_string, &config).await?;
Ok(Self { config, client })
}
#[cfg(feature = "postgres")]
pub fn with_client(config: WaypointConfig, client: Client) -> Self {
Self {
config,
client: DbClient::with_postgres(client),
}
}
pub fn with_db_client(config: WaypointConfig, client: DbClient) -> Self {
Self { config, client }
}
pub fn client(&self) -> &DbClient {
&self.client
}
#[cfg(feature = "postgres")]
pub fn postgres_client(&self) -> Result<&Client> {
self.client.as_postgres()
}
pub async fn migrate(&self, target_version: Option<&str>) -> Result<MigrateReport> {
self.migrate_with_options(target_version, false).await
}
pub async fn migrate_with_options(
&self,
target_version: Option<&str>,
force: bool,
) -> Result<MigrateReport> {
match self.client.dialect_kind() {
#[cfg(feature = "postgres")]
DialectKind::Postgres => {
commands::migrate::execute_with_options(
self.client.as_postgres()?,
&self.config,
target_version,
force,
)
.await
}
#[cfg(not(feature = "postgres"))]
DialectKind::Postgres => Err(error::WaypointError::ConfigError(
"PostgreSQL support is not compiled in (enable the `postgres` feature)".into(),
)),
#[cfg(feature = "mysql")]
DialectKind::Mysql => {
commands::migrate::execute_mysql_with_options(
&self.client,
&self.config,
target_version,
force,
)
.await
}
#[cfg(not(feature = "mysql"))]
DialectKind::Mysql => Err(error::WaypointError::ConfigError(
"MySQL support is not compiled in (enable the `mysql` feature)".into(),
)),
}
}
pub async fn info(&self) -> Result<Vec<MigrationInfo>> {
commands::info::execute_db(&self.client, &self.config).await
}
pub async fn validate(&self) -> Result<ValidateReport> {
commands::validate::execute_db(&self.client, &self.config).await
}
pub async fn repair(&self) -> Result<RepairReport> {
commands::repair::execute_db(&self.client, &self.config).await
}
pub async fn baseline(&self, version: Option<&str>, description: Option<&str>) -> Result<()> {
commands::baseline::execute_db(&self.client, &self.config, version, description).await
}
pub async fn undo(&self, target: UndoTarget) -> Result<UndoReport> {
commands::undo::execute_db(&self.client, &self.config, target).await
}
pub async fn clean(&self, allow_clean: bool) -> Result<Vec<String>> {
commands::clean::execute_db(&self.client, &self.config, allow_clean).await
}
pub fn lint(locations: &[PathBuf], disabled_rules: &[String]) -> Result<LintReport> {
commands::lint::execute(locations, disabled_rules)
}
pub fn changelog(
locations: &[PathBuf],
from: Option<&str>,
to: Option<&str>,
) -> Result<ChangelogReport> {
commands::changelog::execute(locations, from, to)
}
pub async fn diff(&self, target: commands::diff::DiffTarget) -> Result<DiffReport> {
commands::diff::execute_db(&self.client, &self.config, target).await
}
pub async fn drift(&self) -> Result<DriftReport> {
commands::drift::execute_db(&self.client, &self.config).await
}
pub async fn snapshot(
&self,
snapshot_config: &commands::snapshot::SnapshotConfig,
) -> Result<SnapshotReport> {
commands::snapshot::execute_snapshot_db(&self.client, &self.config, snapshot_config).await
}
pub async fn restore(
&self,
snapshot_config: &commands::snapshot::SnapshotConfig,
snapshot_id: &str,
) -> Result<RestoreReport> {
commands::snapshot::execute_restore_db(
&self.client,
&self.config,
snapshot_config,
snapshot_id,
)
.await
}
pub async fn explain(&self) -> Result<ExplainReport> {
commands::explain::execute_db(&self.client, &self.config).await
}
pub async fn preflight(&self) -> Result<PreflightReport> {
preflight::run_preflight_db(&self.client, &self.config.preflight).await
}
pub fn check_conflicts(locations: &[PathBuf], base_branch: &str) -> Result<ConflictReport> {
commands::check_conflicts::execute(locations, base_branch)
}
pub async fn safety(&self) -> Result<SafetyCommandReport> {
commands::safety::execute_db(&self.client, &self.config).await
}
pub async fn advise(&self) -> Result<AdvisorReport> {
commands::advisor::execute_db(&self.client, &self.config).await
}
pub async fn simulate(&self) -> Result<SimulationReport> {
commands::simulate::execute_db(&self.client, &self.config).await
}
}
async fn connect_for_url(
conn_string: &str,
#[cfg_attr(not(feature = "postgres"), allow(unused_variables))] config: &WaypointConfig,
) -> Result<DbClient> {
let kind = DialectKind::from_url(conn_string).unwrap_or(DialectKind::Postgres);
match kind {
#[cfg(feature = "postgres")]
DialectKind::Postgres => {
let client = db::connect_with_full_config(
conn_string,
&config.database.ssl_mode,
config.database.connect_retries,
config.database.connect_timeout_secs,
config.database.statement_timeout_secs,
config.database.keepalive_secs,
)
.await?;
Ok(DbClient::with_postgres(client))
}
#[cfg(not(feature = "postgres"))]
DialectKind::Postgres => Err(error::WaypointError::ConfigError(
"PostgreSQL support is not compiled in (enable the `postgres` feature)".into(),
)),
#[cfg(feature = "mysql")]
DialectKind::Mysql => {
let pool = mysql_async::Pool::from_url(conn_string).map_err(|e| {
error::WaypointError::ConfigError(format!("Invalid MySQL connection URL: {}", e))
})?;
Ok(DbClient::with_mysql(pool))
}
#[cfg(not(feature = "mysql"))]
DialectKind::Mysql => Err(error::WaypointError::ConfigError(
"MySQL support is not compiled in (enable the `mysql` feature)".into(),
)),
}
}