mirror of
https://github.com/perfect-panel/ppanel-web.git
synced 2026-08-29 05:52:08 -04:00
feat(migration)
This commit is contained in:
Generated
+216
-4
@@ -511,6 +511,26 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.71.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools 0.13.0",
|
||||
"log",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex 1.3.0",
|
||||
"syn 2.0.118",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.13.0"
|
||||
@@ -596,6 +616,24 @@ version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593"
|
||||
|
||||
[[package]]
|
||||
name = "cbindgen"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eadd868a2ce9ca38de7eeafdcec9c7065ef89b42b32f0839278d55f35c54d1ff"
|
||||
dependencies = [
|
||||
"heck 0.4.1",
|
||||
"indexmap 2.14.0",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 2.0.118",
|
||||
"tempfile",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.65"
|
||||
@@ -605,7 +643,16 @@ dependencies = [
|
||||
"find-msvc-tools",
|
||||
"jobserver",
|
||||
"libc",
|
||||
"shlex",
|
||||
"shlex 2.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom 7.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -655,6 +702,17 @@ dependencies = [
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.6.1"
|
||||
@@ -683,7 +741,7 @@ version = "4.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.118",
|
||||
@@ -1304,6 +1362,17 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs-set-times"
|
||||
version = "0.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94e7099f6313ecacbe1256e8ff9d617b75d1bcb16a6fddef94866d225a01a14a"
|
||||
dependencies = [
|
||||
"io-lifetimes",
|
||||
"rustix",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fs_extra"
|
||||
version = "1.3.0"
|
||||
@@ -1726,6 +1795,12 @@ dependencies = [
|
||||
"hashbrown 0.16.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
@@ -2197,6 +2272,12 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06432fb54d3be7964ecd3649233cddf80db2832f47fec34c01f65b3d9d774983"
|
||||
|
||||
[[package]]
|
||||
name = "ip"
|
||||
version = "0.1.0"
|
||||
@@ -2388,6 +2469,16 @@ version = "0.2.186"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.16"
|
||||
@@ -2486,6 +2577,14 @@ version = "2.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
|
||||
|
||||
[[package]]
|
||||
name = "migrate"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rust2go",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.3.17"
|
||||
@@ -3148,6 +3247,7 @@ dependencies = [
|
||||
"hex",
|
||||
"jwt",
|
||||
"md5 0.7.0",
|
||||
"migrate",
|
||||
"oauth",
|
||||
"opentelemetry",
|
||||
"opentelemetry-otlp",
|
||||
@@ -3240,7 +3340,7 @@ version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03da047801ff44bb6a4d407d4860c05fd70bb81714e6b2f3812603d5b145b042"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"heck 0.5.0",
|
||||
"itertools 0.14.0",
|
||||
"log",
|
||||
"multimap",
|
||||
@@ -3735,6 +3835,62 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust2go"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "021695cb0d56dbef5f29b24d2dd9a23552464500574260a41c198fe17c78a3fe"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"fs-set-times",
|
||||
"rust2go-cli",
|
||||
"rust2go-convert",
|
||||
"rust2go-macro",
|
||||
"syn 2.0.118",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust2go-cli"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8490df1c618176bfd681c0e27b46fa98f42739c441c12a8f7bc85eb6550e54fe"
|
||||
dependencies = [
|
||||
"cbindgen",
|
||||
"clap",
|
||||
"itertools 0.14.0",
|
||||
"rust2go-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust2go-common"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a27eb858d3df960a07bc7f7e43f642d6a8368cc32110d7daacb6aa069eb7f9c5"
|
||||
dependencies = [
|
||||
"heck 0.5.0",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.118",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust2go-convert"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21ee4d6efac91720550e564892b1fddfe103683f7f0b19196f59dae1621e6e83"
|
||||
|
||||
[[package]]
|
||||
name = "rust2go-macro"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a694d2aa8c7265126b0f3c712bd8411e5415d5e5f906fa2996a10beb81b5efca"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rust2go-common",
|
||||
"syn 2.0.118",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.3"
|
||||
@@ -4027,6 +4183,15 @@ dependencies = [
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
@@ -4143,6 +4308,12 @@ dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "2.0.1"
|
||||
@@ -4382,7 +4553,7 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"dotenvy",
|
||||
"either",
|
||||
"heck",
|
||||
"heck 0.5.0",
|
||||
"hex",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -4777,6 +4948,47 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
|
||||
dependencies = [
|
||||
"indexmap 2.14.0",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_write",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_write"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
|
||||
|
||||
[[package]]
|
||||
name = "tonic"
|
||||
version = "0.12.3"
|
||||
|
||||
@@ -46,3 +46,4 @@ sms = { path = "crates/sms" }
|
||||
email = { path = "crates/email" }
|
||||
turnstile = { path = "crates/turnstile" }
|
||||
reqwest = { version = "0.12", features = ["json"] }
|
||||
migrate = { path = "crates/migrate" }
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "migrate"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
# The name of the lib target. We expose `ppanel_migrate` so the main
|
||||
# binary can `use ppanel_migrate::*`. The actual library name in
|
||||
# Cargo's eyes is "migrate" (matches [package].name), but the
|
||||
# `crate-type = ["staticlib"]` is what rust2go::Builder compiles the
|
||||
# Go code into for FFI.
|
||||
crate-type = ["staticlib", "rlib"]
|
||||
|
||||
[features]
|
||||
# Default: build with the FFI bridge compiled in. The Go side is compiled
|
||||
# by build.rs via rust2go::Builder.
|
||||
default = []
|
||||
|
||||
[dependencies]
|
||||
rust2go = "0.4"
|
||||
tracing = "0.1"
|
||||
|
||||
[build-dependencies]
|
||||
rust2go = { version = "0.4", features = ["build"] }
|
||||
@@ -0,0 +1,19 @@
|
||||
// rust2go build script.
|
||||
//
|
||||
// Wires up the Go source tree (./go/r2g) into the Rust build:
|
||||
// - Embeds the Go source path so the Builder can compile it via CGO.
|
||||
// - Wires `src/idl.rs` (Rust IDL) → `./go/r2g/gen.go`
|
||||
// (auto-generated Go glue).
|
||||
//
|
||||
// On every `cargo build` the Builder regenerates gen.go if the IDL
|
||||
// changed, then compiles the Go code into a static library that the
|
||||
// Rust crate is linked against.
|
||||
fn main() {
|
||||
rust2go::Builder::new()
|
||||
.with_go_src("./go/r2g")
|
||||
// gen.go is written relative to the build script's CWD (the
|
||||
// crate root), so we spell out the path under go/r2g/ where
|
||||
// the Go package lives.
|
||||
.with_regen("src/idl.rs", "go/r2g/gen.go")
|
||||
.build();
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
//! End-to-end test for the rust2go FFI migration path.
|
||||
//!
|
||||
//! Usage:
|
||||
//! GODEBUG=invalidptr=0,cgocheck=0 cargo run --example test_migrate -- \
|
||||
//! postgres://user:pass@host:5432/dbname?sslmode=disable
|
||||
//!
|
||||
//! Resets the database, runs `migrate::up()` via the FFI bridge, and
|
||||
//! verifies the resulting schema. Exits with non-zero status on any
|
||||
//! failure.
|
||||
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
let dsn = env::args()
|
||||
.nth(1)
|
||||
.expect("usage: test_migrate <postgres-dsn>");
|
||||
|
||||
// Make sure the schema is empty so we can verify migration works
|
||||
// from a fresh state. We do this with a side connection in pure
|
||||
// SQL — we don't want to import the sqlx stack just for the test.
|
||||
// The drop must run as a superuser since `ppanel_test` does not
|
||||
// own the public schema.
|
||||
println!("== dropping schema public (as postgres superuser) ==");
|
||||
let admin_dsn = env::var("PPANEL_ADMIN_DSN")
|
||||
.unwrap_or_else(|_| "postgres://postgres@localhost:5432/postgres".to_string());
|
||||
let drop_sql = format!(
|
||||
"DROP SCHEMA public CASCADE; CREATE SCHEMA public; \
|
||||
GRANT ALL ON SCHEMA public TO public; \
|
||||
ALTER DATABASE ppanel_rust2go_test OWNER TO ppanel_test;",
|
||||
);
|
||||
exec_via_psql(&admin_dsn, &drop_sql);
|
||||
|
||||
println!("== calling migrate::up() via FFI ==");
|
||||
let outcome = migrate::up("postgres", &dsn);
|
||||
println!(
|
||||
" -> version={}, dirty={}, error={:?}",
|
||||
outcome.version, outcome.dirty, outcome.error
|
||||
);
|
||||
if !outcome.error.is_empty() {
|
||||
eprintln!("MIGRATION FAILED: {}", outcome.error);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
println!("== verifying schema ==");
|
||||
let count_sql = "SELECT count(*) FROM information_schema.tables \
|
||||
WHERE table_schema = 'public' AND table_type = 'BASE TABLE';";
|
||||
let n: u32 = query_via_psql(&dsn, count_sql)
|
||||
.parse()
|
||||
.expect("count should parse as u32");
|
||||
println!(" -> {} public tables", n);
|
||||
if n < 20 {
|
||||
eprintln!("expected at least 20 tables, got {}", n);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
println!("== verifying schema_migrations state ==");
|
||||
let ver_sql = "SELECT version::text || '|' || dirty::text FROM schema_migrations;";
|
||||
let state = query_via_psql(&dsn, ver_sql);
|
||||
println!(" -> version,dirty = {}", state);
|
||||
if !state.starts_with("2131|") {
|
||||
eprintln!("expected version 2131, got {}", state);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
println!("== testing idempotency: re-run up() ==");
|
||||
let outcome2 = migrate::up("postgres", &dsn);
|
||||
println!(
|
||||
" -> version={}, dirty={}, error={:?}",
|
||||
outcome2.version, outcome2.dirty, outcome2.error
|
||||
);
|
||||
if !outcome2.error.is_empty() {
|
||||
eprintln!("IDEMPOTENT RUN FAILED: {}", outcome2.error);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
println!("\n✅ ALL CHECKS PASSED");
|
||||
}
|
||||
|
||||
/// Run a SQL statement via `psql` and return its trimmed stdout.
|
||||
fn exec_via_psql(dsn: &str, sql: &str) -> String {
|
||||
let out = std::process::Command::new("psql")
|
||||
.arg(dsn)
|
||||
.arg("-c")
|
||||
.arg(sql)
|
||||
.arg("-A")
|
||||
.arg("-t")
|
||||
.output()
|
||||
.expect("failed to invoke psql (is it installed and on PATH?)");
|
||||
if !out.status.success() {
|
||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||
panic!("psql failed: {}\n{}", out.status, stderr);
|
||||
}
|
||||
String::from_utf8_lossy(&out.stdout).trim().to_string()
|
||||
}
|
||||
|
||||
fn query_via_psql(dsn: &str, sql: &str) -> String {
|
||||
exec_via_psql(dsn, sql)
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
gomigrate "github.com/golang-migrate/migrate/v4"
|
||||
|
||||
ppmigrate "github.com/perfect-panel/ppanel-backend/tools/migrate/migrate"
|
||||
ppmigrate "github.com/perfect-panel/ppanel-backend/crates/migrate/go/migrate"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -53,7 +53,7 @@ func main() {
|
||||
}
|
||||
|
||||
cmd := flag.Arg(0)
|
||||
sess := ppmigrate.Migrate(*driver, *dsn)
|
||||
sess := ppmigrate.MigrateOrPanic(*driver, *dsn)
|
||||
m := sess.Migrate
|
||||
|
||||
switch cmd {
|
||||
@@ -0,0 +1,16 @@
|
||||
module github.com/perfect-panel/ppanel-backend/crates/migrate/go
|
||||
|
||||
go 1.25.0
|
||||
|
||||
require (
|
||||
github.com/golang-migrate/migrate/v4 v4.19.1
|
||||
// rust2go has no tagged releases; pin to the latest commit on master.
|
||||
// Bump by re-running `go get github.com/ihciah/rust2go@master`.
|
||||
github.com/ihciah/rust2go v0.0.0-20260706074211-1c851bd436aa
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.8.1 // indirect
|
||||
github.com/lib/pq v1.10.9 // indirect
|
||||
)
|
||||
@@ -32,6 +32,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA=
|
||||
github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE=
|
||||
github.com/ihciah/rust2go v0.0.0-20260706074211-1c851bd436aa h1:u8Mzn+6v64BdSV6ry7OGXt2lbSjHQh4711+0whU/sYE=
|
||||
github.com/ihciah/rust2go v0.0.0-20260706074211-1c851bd436aa/go.mod h1:SpcZZoVYDXYhx373JZ1onR8dnEcalKA0H61x/FJ9O0s=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||
@@ -23,6 +23,10 @@ var sqlFiles embed.FS
|
||||
// NoChange is re-exported so callers don't have to import golang-migrate directly.
|
||||
var NoChange = migrate.ErrNoChange
|
||||
|
||||
// ErrNilVersion is re-exported for the same reason — it is the sentinel
|
||||
// returned by Version() when the schema_migrations table is empty.
|
||||
var ErrNilVersion = migrate.ErrNilVersion
|
||||
|
||||
// Session bundles a configured golang-migrate instance alongside the parsed
|
||||
// source-version list so callers can introspect what migrations exist.
|
||||
type Session struct {
|
||||
@@ -37,7 +41,10 @@ type Session struct {
|
||||
// dsn: golang-migrate URL (e.g. postgres://user:pass@host:port/db?sslmode=disable).
|
||||
//
|
||||
// If dsn does not include a URL scheme, the driver is prepended automatically.
|
||||
func Migrate(driver, dsn string) *Session {
|
||||
//
|
||||
// Returns an error (no panics) so the function is safe to call across an FFI
|
||||
// boundary.
|
||||
func Migrate(driver, dsn string) (*Session, error) {
|
||||
sourcePath := "sql/postgres"
|
||||
databaseURL := dsn
|
||||
switch driver {
|
||||
@@ -47,20 +54,30 @@ func Migrate(driver, dsn string) *Session {
|
||||
case "postgres":
|
||||
databaseURL = ensureScheme("postgres://", dsn)
|
||||
default:
|
||||
panic(fmt.Errorf("[Migrate] unsupported database driver: %s", driver))
|
||||
return nil, fmt.Errorf("[Migrate] unsupported database driver: %s", driver)
|
||||
}
|
||||
d, err := iofs.New(sqlFiles, sourcePath)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("[Migrate] iofs.New error: %v", err))
|
||||
return nil, fmt.Errorf("[Migrate] iofs.New error: %v", err)
|
||||
}
|
||||
client, err := migrate.NewWithSourceInstance("iofs", d, databaseURL)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("[Migrate] NewWithSourceInstance error: %v", err))
|
||||
return nil, fmt.Errorf("[Migrate] NewWithSourceInstance error: %v", err)
|
||||
}
|
||||
return &Session{
|
||||
Migrate: client,
|
||||
Versions: scanVersions(sourcePath),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MigrateOrPanic is a panic-on-error variant retained for the standalone CLI
|
||||
// (`cmd/migrate/main.go`). Production code (FFI callers) must use Migrate.
|
||||
func MigrateOrPanic(driver, dsn string) *Session {
|
||||
s, err := Migrate(driver, dsn)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// sourceVersionRe matches migration filenames like "02131_xxx.up.sql" / ".down.sql".
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user