Skip to main content

cratefield_cli/
apply.rs

1//! `fz migrations apply` (issue #18): applies the harness's module
2//! migrations directly to a Postgres database — the native counterpart of
3//! `wrangler d1 migrations apply`. Requires building `fz` with
4//! cratefield-cli's `postgres` feature so sqlx and tokio stay out of the
5//! default (wasm-safe) dependency graph.
6
7use cratefield_core::Harness;
8
9/// Applies the harness's migrations to the database at `url`.
10///
11/// # Errors
12///
13/// A human-readable message when the dialect is unsupported, the binary
14/// lacks the `postgres` feature, the server is unreachable, or a
15/// migration fails.
16pub fn apply(harness: &Harness, dialect: &str, url: &str) -> Result<(), String> {
17    if dialect != "postgres" {
18        return Err(format!(
19            "dialect {dialect:?} is not supported for apply (only postgres, issue #18)"
20        ));
21    }
22    #[cfg(not(feature = "postgres"))]
23    {
24        let _ = (harness, url);
25        Err(
26            "this fz binary was built without cratefield-cli's `postgres` feature — \
27             rebuild the fz bin with `--features cratefield-cli/postgres` to apply \
28             migrations to Postgres (sqlite/D1 migrations run through \
29             `wrangler d1 migrations apply`)"
30                .to_owned(),
31        )
32    }
33    #[cfg(feature = "postgres")]
34    apply_postgres(harness, url)
35}
36
37#[cfg(feature = "postgres")]
38fn apply_postgres(harness: &Harness, url: &str) -> Result<(), String> {
39    let runtime = tokio::runtime::Builder::new_current_thread()
40        .enable_all()
41        .build()
42        .map_err(|err| format!("cannot start the async runtime: {err}"))?;
43    // The URL is never echoed: connection strings carry credentials.
44    runtime.block_on(async {
45        let db = cratefield_adapter_postgres::Postgres::connect(url)
46            .await
47            .map_err(|err| format!("cannot connect (check --url): {err}"))?;
48        db.apply_harness_migrations(harness)
49            .await
50            .map_err(|err| format!("migrations failed: {err}"))
51    })
52}