feat(mysql): native SQL execution — fix #41 type decoding, in-process restore, .sql open-with (#42)

Fixes #41.

MySQL columns now decode by their declared type instead of a blind try_get chain,
so every non-string type (integers, DECIMAL, BIT, YEAR, DATE/TIME/DATETIME/TIMESTAMP)
renders its value instead of NULL. MySQL restore runs in-process over the sqlx driver
(no bundled MariaDB client, so MySQL 8 caching_sha2_password works) and the Clean toggle
is implemented. .sql files can be opened with Gridline from the OS file manager.

Verified: cargo test --lib 442 passed / 0 failed; bun run test 133 files / 1151 tests
exit 0; tsc clean; both live MySQL 8 integration tests pass with the bundled CLI hidden.
This commit is contained in:
2026-09-29 08:52:47 +08:00
committed by GitHub
parent ce4a73b0bb
commit 88e7e45818
36 changed files with 2265 additions and 141 deletions
+10 -1
View File
@@ -33,7 +33,9 @@ tokio = { version = "1", features = ["full"] }
tokio-postgres = { version = "0.7", features = ["with-chrono-0_4", "with-uuid-1", "with-serde_json-1"] }
bytes = "1"
futures-util = "0.3"
sqlx = { version = "0.8", features = ["runtime-tokio", "mysql", "tls-rustls", "json"] }
# chrono/bigdecimal: MySQL DECIMAL and DATE/TIME/DATETIME/TIMESTAMP have no
# decoder without them, so those columns silently rendered as NULL (#41).
sqlx = { version = "0.8", features = ["runtime-tokio", "mysql", "tls-rustls", "json", "chrono", "bigdecimal"] }
redis = { version = "0.27", features = ["tokio-comp"] }
# async-ssh2 is not available at v0.4; using synchronous ssh2 via tokio::task::spawn_blocking per plan's fallback
# vendored-openssl: link OpenSSL statically so the release binary has NO
@@ -59,3 +61,10 @@ security-framework-sys = "2.17"
# (already a transitive dep of security-framework; pinned to the same 0.10 line)
core-foundation = "0.10"
# Windows/Linux deliver an OS "open with" request as argv. Without this a
# second double-click would launch a second app instead of forwarding the path
# to the running one. macOS needs no equivalent: LaunchServices routes to the
# running app via RunEvent::Opened.
[target.'cfg(any(target_os = "windows", target_os = "linux"))'.dependencies]
tauri-plugin-single-instance = "2"