mirror of
https://github.com/launchbadge/sqlx
synced 2024-11-14 00:07:05 +00:00
Use anihow
This commit is contained in:
parent
f00b7b48e1
commit
9a765e4e86
2 changed files with 53 additions and 43 deletions
|
@ -21,3 +21,4 @@ sqlx = { version = "0.3", path = "..", default-features = false, features = [ "r
|
|||
futures = "0.3"
|
||||
structopt = "0.3"
|
||||
chrono = "0.4"
|
||||
anyhow = "1.0"
|
||||
|
|
|
@ -10,6 +10,8 @@ use sqlx::PgPool;
|
|||
|
||||
use structopt::StructOpt;
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
const MIGRATION_FOLDER: &'static str = "migrations";
|
||||
|
||||
/// Sqlx commandline tool
|
||||
|
@ -41,32 +43,30 @@ enum MigrationCommand {
|
|||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
async fn main() -> Result<()> {
|
||||
let opt = Opt::from_args();
|
||||
|
||||
match opt {
|
||||
Opt::Migrate(command) => match command {
|
||||
// Opt::Init { database_name } => init_migrations(&database_name),
|
||||
MigrationCommand::Add { name } => add_migration_file(&name),
|
||||
MigrationCommand::Run => run_migrations().await,
|
||||
MigrationCommand::Add { name } => add_migration_file(&name)?,
|
||||
MigrationCommand::Run => run_migrations().await?,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
println!("All done!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// fn init_migrations(db_name: &str) {
|
||||
// println!("Initing the migrations so hard! db: {:#?}", db_name);
|
||||
// }
|
||||
|
||||
fn add_migration_file(name: &str) {
|
||||
fn add_migration_file(name: &str) -> Result<()> {
|
||||
use chrono::prelude::*;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
|
||||
if !Path::new(MIGRATION_FOLDER).exists() {
|
||||
fs::create_dir(MIGRATION_FOLDER).expect("Failed to create 'migrations' dir")
|
||||
}
|
||||
fs::create_dir_all(MIGRATION_FOLDER)?;
|
||||
|
||||
let dt = Utc::now();
|
||||
let mut file_name = dt.format("%Y-%m-%d_%H-%M-%S").to_string();
|
||||
|
@ -78,16 +78,12 @@ fn add_migration_file(name: &str) {
|
|||
path.push(MIGRATION_FOLDER);
|
||||
path.push(&file_name);
|
||||
|
||||
if path.exists() {
|
||||
eprintln!("Migration already exists!");
|
||||
return;
|
||||
}
|
||||
|
||||
let mut file = File::create(path).expect("Failed to create file");
|
||||
let mut file = File::create(path).context("Failed to create file")?;
|
||||
file.write_all(b"-- Add migration script here")
|
||||
.expect("Could not write to file");
|
||||
.context("Could not write to file")?;
|
||||
|
||||
println!("Created migration: '{}'", file_name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub struct Migration {
|
||||
|
@ -95,8 +91,8 @@ pub struct Migration {
|
|||
pub sql: String,
|
||||
}
|
||||
|
||||
fn load_migrations() -> Vec<Migration> {
|
||||
let entries = fs::read_dir(&MIGRATION_FOLDER).expect("Could not find 'migrations' dir");
|
||||
fn load_migrations() -> Result<Vec<Migration>> {
|
||||
let entries = fs::read_dir(&MIGRATION_FOLDER).context("Could not find 'migrations' dir")?;
|
||||
|
||||
let mut migrations = Vec::new();
|
||||
|
||||
|
@ -116,11 +112,11 @@ fn load_migrations() -> Vec<Migration> {
|
|||
continue;
|
||||
}
|
||||
|
||||
let mut file =
|
||||
File::open(e.path()).expect(&format!("Failed to open: '{:?}'", e.file_name()));
|
||||
let mut file = File::open(e.path())
|
||||
.with_context(|| format!("Failed to open: '{:?}'", e.file_name()))?;
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents)
|
||||
.expect(&format!("Failed to read: '{:?}'", e.file_name()));
|
||||
.with_context(|| format!("Failed to read: '{:?}'", e.file_name()))?;
|
||||
|
||||
migrations.push(Migration {
|
||||
name: e.file_name().to_str().unwrap().to_string(),
|
||||
|
@ -132,42 +128,48 @@ fn load_migrations() -> Vec<Migration> {
|
|||
|
||||
migrations.sort_by(|a, b| a.name.partial_cmp(&b.name).unwrap());
|
||||
|
||||
migrations
|
||||
Ok(migrations)
|
||||
}
|
||||
|
||||
async fn run_migrations() {
|
||||
// use sqlx_core::executor::Executor;
|
||||
|
||||
async fn run_migrations() -> Result<()> {
|
||||
dotenv().ok();
|
||||
let db_url = env::var("DATABASE_URL").expect("Failed to find 'DATABASE_URL'");
|
||||
let db_url = env::var("DATABASE_URL").context("Failed to find 'DATABASE_URL'")?;
|
||||
|
||||
let mut pool = PgPool::new(&db_url)
|
||||
.await
|
||||
.expect("Failed to connect to pool");
|
||||
.context("Failed to connect to pool")?;
|
||||
|
||||
create_migration_table(&mut pool).await;
|
||||
create_migration_table(&mut pool).await?;
|
||||
|
||||
let migrations = load_migrations();
|
||||
let migrations = load_migrations()?;
|
||||
|
||||
for mig in migrations.iter() {
|
||||
let mut tx = pool.begin().await.unwrap();
|
||||
let mut tx = pool.begin().await.context("Failed to start transaction")?;
|
||||
|
||||
if check_if_applied(&mut tx, &mig.name).await {
|
||||
if check_if_applied(&mut tx, &mig.name).await? {
|
||||
println!("Already applied migration: '{}'", mig.name);
|
||||
continue;
|
||||
}
|
||||
println!("Applying migration: '{}'", mig.name);
|
||||
|
||||
// tx.execute(&*mig.sql).await;
|
||||
|
||||
sqlx::query(&mig.sql)
|
||||
.execute(&mut tx)
|
||||
.await
|
||||
.expect(&format!("Failed to run migration {:?}", &mig.name));
|
||||
.with_context(|| format!("Failed to run migration {:?}", &mig.name))?;
|
||||
|
||||
save_applied_migration(&mut tx, &mig.name).await;
|
||||
save_applied_migration(&mut tx, &mig.name).await?;
|
||||
|
||||
tx.commit().await.unwrap();
|
||||
tx.commit().await.context("Failed to commit changes")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn create_migration_table(mut pool: &PgPool) {
|
||||
async fn create_migration_table(mut pool: &PgPool) -> Result<()> {
|
||||
sqlx::query(
|
||||
r#"
|
||||
CREATE TABLE IF NOT EXISTS __migrations (
|
||||
|
@ -178,25 +180,32 @@ CREATE TABLE IF NOT EXISTS __migrations (
|
|||
)
|
||||
.execute(&mut pool)
|
||||
.await
|
||||
.expect("Failed to create migration table");
|
||||
.context("Failed to create migration table")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn check_if_applied(pool: &mut PgConnection, migration: &str) -> bool {
|
||||
async fn check_if_applied(pool: &mut PgConnection, migration: &str) -> Result<bool> {
|
||||
use sqlx::postgres::PgRow;
|
||||
use sqlx::Row;
|
||||
|
||||
sqlx::query("select exists(select migration from __migrations where migration = $1) as exists")
|
||||
.bind(migration.to_string())
|
||||
.try_map(|row: PgRow| row.try_get("exists"))
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
.expect("Failed to check migration table")
|
||||
let result = sqlx::query(
|
||||
"select exists(select migration from __migrations where migration = $1) as exists",
|
||||
)
|
||||
.bind(migration.to_string())
|
||||
.try_map(|row: PgRow| row.try_get("exists"))
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
.context("Failed to check migration table")?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
async fn save_applied_migration(pool: &mut PgConnection, migration: &str) {
|
||||
async fn save_applied_migration(pool: &mut PgConnection, migration: &str) -> Result<()> {
|
||||
sqlx::query("insert into __migrations (migration) values ($1)")
|
||||
.bind(migration.to_string())
|
||||
.execute(pool)
|
||||
.await
|
||||
.expect("Failed to insert migration ");
|
||||
.context("Failed to insert migration")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue