diff --git a/Cargo.lock b/Cargo.lock index e1a821e760a8d8abb302932b3f164b6086d3811f..0c13ea8484621a7530a8cd8645e6434124afa495 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -129,7 +129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom", + "getrandom 0.2.15", "once_cell", "version_check", "zerocopy", @@ -350,6 +350,18 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-native-tls" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d57d4cec3c647232e1094dc013546c0b33ce785d8aeb251e1f20dfaf8a9a13fe" +dependencies = [ + "futures-util", + "native-tls", + "thiserror", + "url", +] + [[package]] name = "async-process" version = "1.8.1" @@ -413,6 +425,19 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "asynchronous-codec" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4057f2c32adbb2fc158e22fb38433c8e9bbf76b75a4732c7c0cbaf695fb65568" +dependencies = [ + "bytes", + "futures-sink", + "futures-util", + "memchr", + "pin-project-lite", +] + [[package]] name = "atoi" version = "2.0.0" @@ -835,7 +860,7 @@ dependencies = [ "cocoa-foundation", "core-foundation", "core-graphics", - "foreign-types", + "foreign-types 0.5.0", "libc", "objc", ] @@ -901,6 +926,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "connection-string" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "510ca239cf13b7f8d16a2b48f263de7b4f8c566f0af58d901031473c76afb1e3" + [[package]] name = "const-field-offset" version = "0.1.5" @@ -973,7 +1004,7 @@ dependencies = [ "bitflags 1.3.2", "core-foundation", "core-graphics-types", - "foreign-types", + "foreign-types 0.5.0", "libc", ] @@ -996,7 +1027,7 @@ checksum = "c9d2790b5c08465d49f8dc05c8bcae9fea467855947db39b0f8145c091aaced5" dependencies = [ "core-foundation", "core-graphics", - "foreign-types", + "foreign-types 0.5.0", "libc", ] @@ -1343,6 +1374,70 @@ dependencies = [ "serde", ] +[[package]] +name = "encoding" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec" +dependencies = [ + "encoding-index-japanese", + "encoding-index-korean", + "encoding-index-simpchinese", + "encoding-index-singlebyte", + "encoding-index-tradchinese", +] + +[[package]] +name = "encoding-index-japanese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-korean" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-simpchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-singlebyte" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding-index-tradchinese" +version = "1.20141219.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18" +dependencies = [ + "encoding_index_tests", +] + +[[package]] +name = "encoding_index_tests" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569" + [[package]] name = "enumflags2" version = "0.7.10" @@ -1588,6 +1683,15 @@ dependencies = [ "ttf-parser 0.20.0", ] +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + [[package]] name = "foreign-types" version = "0.5.0" @@ -1595,7 +1699,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", - "foreign-types-shared", + "foreign-types-shared 0.3.1", ] [[package]] @@ -1609,6 +1713,12 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "foreign-types-shared" version = "0.3.1" @@ -1788,6 +1898,17 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.15" @@ -1796,7 +1917,7 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] @@ -2232,7 +2353,7 @@ dependencies = [ "core-foundation", "core-graphics-types", "derive_more", - "foreign-types", + "foreign-types 0.5.0", "glow", "glutin", "i-slint-common", @@ -2784,6 +2905,12 @@ dependencies = [ "digest", ] +[[package]] +name = "md5" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e6bcd6433cff03a4bfc3d9834d504467db1f1cf6d0ea765d37d330249ed629d" + [[package]] name = "memchr" version = "2.7.4" @@ -2835,7 +2962,7 @@ dependencies = [ "bitflags 2.5.0", "block", "core-graphics-types", - "foreign-types", + "foreign-types 0.5.0", "log", "objc", "paste", @@ -2864,10 +2991,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.48.0", ] +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "ndk" version = "0.8.0" @@ -2944,7 +3088,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand", + "rand 0.8.5", "smallvec", "zeroize", ] @@ -3106,6 +3250,50 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "openssl" +version = "0.10.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +dependencies = [ + "bitflags 2.5.0", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "orbclient" version = "0.3.47" @@ -3325,6 +3513,12 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "pretty-hex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5" + [[package]] name = "prettyplease" version = "0.2.20" @@ -3401,6 +3595,19 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + [[package]] name = "rand" version = "0.8.5" @@ -3408,8 +3615,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", ] [[package]] @@ -3419,7 +3636,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", ] [[package]] @@ -3428,7 +3654,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", ] [[package]] @@ -3574,7 +3809,7 @@ dependencies = [ "num-traits", "pkcs1", "pkcs8", - "rand_core", + "rand_core 0.6.4", "signature", "spki", "subtle", @@ -3675,6 +3910,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -3706,6 +3950,29 @@ dependencies = [ "tiny-skia", ] +[[package]] +name = "security-framework" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +dependencies = [ + "bitflags 2.5.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "1.0.23" @@ -3807,7 +4074,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -4003,7 +4270,7 @@ dependencies = [ "cocoa", "core-graphics", "fastrand 2.1.0", - "foreign-types", + "foreign-types 0.5.0", "js-sys", "log", "memmap2 0.9.4", @@ -4067,7 +4334,9 @@ dependencies = [ "serde", "sqlx", "thiserror", + "tiberius", "tokio", + "tokio-util", ] [[package]] @@ -4199,7 +4468,7 @@ dependencies = [ "memchr", "once_cell", "percent-encoding", - "rand", + "rand 0.8.5", "rsa", "serde", "sha1", @@ -4238,7 +4507,7 @@ dependencies = [ "md-5", "memchr", "once_cell", - "rand", + "rand 0.8.5", "serde", "serde_json", "sha2", @@ -4440,6 +4709,31 @@ dependencies = [ "syn 2.0.66", ] +[[package]] +name = "tiberius" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6e2bf3e4b5be181a2a2ceff4b9b12e2684010d436a6958bd564fbc8094d44d" +dependencies = [ + "async-native-tls", + "async-trait", + "asynchronous-codec", + "byteorder", + "bytes", + "connection-string", + "encoding", + "enumflags2", + "futures-util", + "num-traits", + "once_cell", + "pin-project-lite", + "pretty-hex", + "thiserror", + "tracing", + "uuid", + "winauth", +] + [[package]] name = "tiff" version = "0.9.1" @@ -4556,6 +4850,20 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" version = "0.8.14" @@ -4831,6 +5139,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439" + [[package]] name = "vcpkg" version = "0.2.15" @@ -4882,6 +5196,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -5167,6 +5487,19 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winauth" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f820cd208ce9c6b050812dc2d724ba98c6c1e9db5ce9b3f58d925ae5723a5e6" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "md5", + "rand 0.7.3", + "winapi", +] + [[package]] name = "windows" version = "0.54.0" @@ -5701,7 +6034,7 @@ dependencies = [ "nix 0.26.4", "once_cell", "ordered-stream", - "rand", + "rand 0.8.5", "serde", "serde_repr", "sha1", diff --git a/Cargo.toml b/Cargo.toml index e86f70cdf4c84e7098cc487694578f347a3516ea..74504e0b2224e8c7ef994d2e3d91d47f6d772436 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sql2doc" -version = "0.1.0" +version = "0.2.0" edition = "2021" publish = ["crates-io"] diff --git a/cli/Cargo.toml b/cli/Cargo.toml index b7a3120c98934a338fd0eae6d61e9a39dd857e48..002b134da39fe2af120906d7a9238998c210aa2d 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "s2d" -version = "0.1.0" +version = "0.2.0" edition = "2021" [dependencies] diff --git a/cli/src/main.rs b/cli/src/main.rs index 217a1e3403466c31a8a2fde505515faaf802799d..a90d95e452ba365fc2b8b3fc78deaec3011710ba 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,13 +1,13 @@ -use clap::Parser; -use sql2doc_core::{run, MysqlConfig}; +use clap::{Parser, ValueEnum}; +use sql2doc_core::{run, SqlConfig, SqlType}; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct Args { #[arg(long)] host: String, - #[arg(long, default_value_t = 3306)] - port: u16, + #[arg(long)] + port: Option, #[arg(short, long)] user: String, #[arg(short, long)] @@ -16,13 +16,35 @@ struct Args { database: String, #[arg(short, long)] output: Option, + #[arg(short, long, value_enum,default_value_t = SqlEnum::Mysql)] + r#type: SqlEnum, +} + +#[derive(Debug, Clone, Copy, ValueEnum, Default)] +enum SqlEnum { + #[default] + Mysql, + Mssql, +} + +impl From for SqlType { + fn from(value: SqlEnum) -> Self { + match value { + SqlEnum::Mysql => SqlType::Mysql, + SqlEnum::Mssql => SqlType::Mssql, + } + } } impl Args { - fn to_mysql_config(&self) -> MysqlConfig { - MysqlConfig { + fn to_sql_config(&self) -> SqlConfig { + let port = match self.r#type { + SqlEnum::Mysql => 3306, + SqlEnum::Mssql => 1433, + }; + SqlConfig { host: self.host.clone(), - port: self.port, + port: self.port.unwrap_or(port), user: self.user.clone(), password: self.password.clone(), database: self.database.clone(), @@ -34,12 +56,13 @@ impl Args { #[tokio::main] async fn main() { let args = Args::parse(); - let config = args.to_mysql_config(); - let result = run(&config).await; + let config = args.to_sql_config(); + let sql_type = args.r#type.into(); + let result = run(sql_type, &config).await; result.map_or_else( |err| { eprintln!("错误:{:?}", err); - eprintln!("发生错误:{}", err.to_string()); + eprintln!("发生错误:{}", err); }, |path| println!("成功,文件保存在:{}", path), ) diff --git a/sql2doc_core/Cargo.toml b/sql2doc_core/Cargo.toml index b921fafc158bd99a1e62fb335b3c99839cf4e6fb..c62a4a0380c2f9696e421b717d0b315efc22c7dc 100644 --- a/sql2doc_core/Cargo.toml +++ b/sql2doc_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sql2doc_core" -version = "0.1.0" +version = "0.2.0" edition = "2021" [dependencies] @@ -9,4 +9,6 @@ docx-rs = { git = "https://github.com/hackers267/docx-rs.git", branch = "main" } serde = { version = "1.0.203", features = ["derive"] } sqlx = { version = "0.7.4", features = ["mysql", "runtime-tokio"] } thiserror = "1.0.61" +tiberius = "0.12.2" tokio = { version = "1.38.0", features = ["full"] } +tokio-util = { version = "0.7.11", features = ["compat"] } diff --git a/sql2doc_core/src/config.rs b/sql2doc_core/src/config.rs index b67e6ad8c367934d21cb9041c75d51da190fad1e..ff83606bfb899a10bfa6730cd1a7007acb31da7b 100644 --- a/sql2doc_core/src/config.rs +++ b/sql2doc_core/src/config.rs @@ -1,5 +1,7 @@ +use tiberius::Config; + #[derive(Debug)] -pub struct MysqlConfig { +pub struct SqlConfig { pub host: String, pub port: u16, pub user: String, @@ -8,11 +10,20 @@ pub struct MysqlConfig { pub output: Option, } -impl MysqlConfig { - pub(crate) fn to_option(&self) -> String { +impl SqlConfig { + pub(crate) fn to_mysql_option(&self) -> String { format!( "mysql://{}:{}@{}:{}/information_schema", self.user, self.password, self.host, self.port ) } + pub(crate) fn to_mssql_config(&self) -> Config { + let mut config = Config::new(); + config.host(&self.host); + config.port(self.port); + config.database(&self.database); + config.authentication(tiberius::AuthMethod::sql_server(&self.user, &self.password)); + config.trust_cert(); + config + } } diff --git a/sql2doc_core/src/lib.rs b/sql2doc_core/src/lib.rs index cb261c6cbe247eb2f004c87574a79cf5e24e6f22..44cbb9a80c39a25059721314a0dcfc5bb129cc8d 100644 --- a/sql2doc_core/src/lib.rs +++ b/sql2doc_core/src/lib.rs @@ -1,12 +1,13 @@ -pub use config::MysqlConfig; +pub use config::SqlConfig; use serde::Deserialize; -use sqlx::mysql::MySqlPoolOptions; use std::borrow::Cow; use std::collections::HashMap; use thiserror::Error; use to_word::write; mod config; +mod mssql; +mod mysql; mod to_word; #[derive(sqlx::FromRow, Debug, Deserialize)] @@ -23,13 +24,23 @@ struct Info { #[derive(Error, Debug)] pub enum RunError { #[error("执行sql查询时出错")] - Sql(#[from] sqlx::Error), + Sqlx(#[from] sqlx::Error), + #[error("执行sql查询时出错")] + MsSql(#[from] tiberius::error::Error), #[error("生成word文档时出错")] Doc(#[from] docx_rs::DocxError), } -pub async fn run(config: &MysqlConfig) -> Result { - let row = fetch_data(config).await?; +pub enum SqlType { + Mysql, + Mssql, +} + +pub async fn run(sql_type: SqlType, config: &SqlConfig) -> Result { + let row = match sql_type { + SqlType::Mysql => mysql::fetch_data(config).await?, + SqlType::Mssql => mssql::fetch_data(config).await?, + }; let row = row.iter().collect::>(); let groups = group_table(&row); let output = &get_output(config); @@ -49,27 +60,10 @@ fn group_table<'a>(row: &'a [&'a Info]) -> HashMap<&'a String, Vec<&'a Info>> { const OUTPUT: &str = "./table.docx"; /// 获取输出路径 -fn get_output(config: &MysqlConfig) -> Cow<'static, str> { +fn get_output(config: &SqlConfig) -> Cow<'static, str> { config .output .as_ref() .map(|v| Cow::Owned(v.clone())) .unwrap_or(Cow::Borrowed(OUTPUT)) } - -/// 获取所有表的相关数据 -async fn fetch_data(config: &MysqlConfig) -> Result, sqlx::Error> { - let url = config.to_option(); - let pool = MySqlPoolOptions::new().connect(&url).await?; - sqlx::query_as::<_, Info>( - r#" - select ORDINAL_POSITION, TABLE_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_NAME, COLUMN_COMMENT - from information_schema.COLUMNS - where TABLE_SCHEMA = ? - order by TABLE_NAME; - "#, - ) - .bind(&config.database) - .fetch_all(&pool) - .await -} diff --git a/sql2doc_core/src/mssql.rs b/sql2doc_core/src/mssql.rs new file mode 100644 index 0000000000000000000000000000000000000000..aad65e2059a942aadd0e3a6d2fd2bac9ee327b7a --- /dev/null +++ b/sql2doc_core/src/mssql.rs @@ -0,0 +1,50 @@ +use tiberius::error::Error; +use tiberius::Client; +use tokio::net::TcpStream; +use tokio_util::compat::TokioAsyncWriteCompatExt; + +use crate::{Info, SqlConfig}; + +pub(crate) async fn fetch_data(config: &SqlConfig) -> Result, Error> { + let config = config.to_mssql_config(); + let addr = config.get_addr(); + let tcp = TcpStream::connect(addr).await?; + tcp.set_nodelay(true)?; + let mut client = Client::connect(config, tcp.compat_write()).await?; + let stream = client + .simple_query( + r#" + select tab.TABLE_NAME,COLUMN_NAME,ORDINAL_POSITION,DATA_TYPE,IS_NULLABLE +from INFORMATION_SCHEMA.TABLES tab + inner join INFORMATION_SCHEMA.COLUMNS col on tab.TABLE_NAME = col.TABLE_NAME +where TABLE_TYPE = 'base table' + "#, + ) + .await?; + let list = stream + .into_results() + .await? + .into_iter() + .flat_map(|v| { + v.iter() + .map(|v| { + let table_name: &str = v.get("TABLE_NAME").unwrap(); + let column_name: &str = v.get(1).unwrap(); + let ordinal_position: i32 = v.get(2).unwrap(); + let ordinal_position = ordinal_position as u64; + let data_type: &str = v.get(3).unwrap(); + let is_nullable: &str = v.get(4).unwrap(); + Info { + ordinal_position, + table_name: table_name.to_string(), + data_type: data_type.to_string(), + is_nullable: is_nullable.to_string(), + column_name: column_name.to_string(), + column_comment: None, + } + }) + .collect::>() + }) + .collect::>(); + Ok(list) +} diff --git a/sql2doc_core/src/mysql.rs b/sql2doc_core/src/mysql.rs new file mode 100644 index 0000000000000000000000000000000000000000..8d9e0f3415eea1978a5f1c54136566486776e8b0 --- /dev/null +++ b/sql2doc_core/src/mysql.rs @@ -0,0 +1,19 @@ +use crate::{Info, SqlConfig}; +use sqlx::mysql::MySqlPoolOptions; + +/// 获取所有表的相关数据 +pub(crate) async fn fetch_data(config: &SqlConfig) -> Result, sqlx::Error> { + let url = config.to_mysql_option(); + let pool = MySqlPoolOptions::new().connect(&url).await?; + sqlx::query_as::<_, Info>( + r#" + select ORDINAL_POSITION, TABLE_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_NAME, COLUMN_COMMENT + from information_schema.COLUMNS + where TABLE_SCHEMA = ? + order by TABLE_NAME; + "#, + ) + .bind(&config.database) + .fetch_all(&pool) + .await +} diff --git a/ui/Cargo.toml b/ui/Cargo.toml index fc1a30bf4ea9c6786be4053e9187eba5d4dfbd03..5843f631c36328cc8bb4b975da3bbd5b660b9d9c 100644 --- a/ui/Cargo.toml +++ b/ui/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ui" -version = "0.1.0" +version = "0.2.0" edition = "2021" build = "build.rs" diff --git a/ui/src/main.rs b/ui/src/main.rs index 118c13ceed5491d36b99ec97f20db4afd142dcfa..76295aada740cf56892ea8e42429b5e7a931297c 100644 --- a/ui/src/main.rs +++ b/ui/src/main.rs @@ -1,12 +1,12 @@ use slint::spawn_local; -use sql2doc_core::{run, MysqlConfig}; +use sql2doc_core::{run, SqlConfig, SqlType}; slint::include_modules!(); fn main() { let app = App::new().unwrap(); let weak_app = app.as_weak(); app.global::().on_confirm(move |config| { - let mysql_config = MysqlConfig { + let mysql_config = SqlConfig { host: config.host.to_string(), port: config.port.to_string().parse::().unwrap_or(3306), user: config.user.to_string(), @@ -18,9 +18,15 @@ fn main() { let res = weak_app.upgrade().unwrap(); res.set_open(true); res.set_message("运行中...".into()); + let sql_type = config.sqltype.to_string(); + let sql_type = if sql_type == "Mysql" { + SqlType::Mysql + } else { + SqlType::Mssql + }; let _ = spawn_local(async move { let result = tokio_runtime - .spawn(async move { run(&mysql_config).await }) + .spawn(async move { run(sql_type, &mysql_config).await }) .await .unwrap(); result.map_or_else( diff --git a/ui/ui/form.slint b/ui/ui/form.slint index 5e406d7b297201e0f5ad02725566fd0422154403..896a4d1bb355474fef4eecf289cea2af9631120b 100644 --- a/ui/ui/form.slint +++ b/ui/ui/form.slint @@ -1,5 +1,6 @@ -import { FormItem } from "form_item.slint"; +import { InputItem } from "input_item.slint"; import { Button } from "std-widgets.slint"; +import { SelectItem } from "select_item.slint"; export struct Config { host: string, @@ -7,6 +8,7 @@ export struct Config { user: string, password: string, database: string, + sqltype: string, } export component Form { @@ -15,33 +17,40 @@ export component Form { in-out property user: ""; in-out property password: ""; in-out property database: ""; + in-out property datatype: "mysql"; out property config; callback confirm(Config); VerticalLayout { spacing: 16px; - h := FormItem { + + dt := SelectItem { + label: "类型:"; + value: datatype; + } + + h := InputItem { label: "地址: "; value: host; } - pp := FormItem { + pp := InputItem { label: "端口: "; value: port; } - u := FormItem { + u := InputItem { label: "用户名: "; value: user; } - pw := FormItem { + pw := InputItem { label: "密码: "; value: password; } - db := FormItem { + db := InputItem { label: "数据库: "; value: database; } @@ -56,6 +65,7 @@ export component Form { user: u.value, password: pw.value, database: db.value, + sqltype: dt.value, }; confirm(root.config); } diff --git a/ui/ui/form_item.slint b/ui/ui/input_item.slint similarity index 96% rename from ui/ui/form_item.slint rename to ui/ui/input_item.slint index 16d4678d5d9694fe50ece7f070bb3fad699e4c89..b11475cfe578b654a657230ab3676b5ff111a9d6 100644 --- a/ui/ui/form_item.slint +++ b/ui/ui/input_item.slint @@ -1,4 +1,4 @@ -export component FormItem { +export component InputItem { in property label; in-out property value; HorizontalLayout { diff --git a/ui/ui/select_item.slint b/ui/ui/select_item.slint new file mode 100644 index 0000000000000000000000000000000000000000..9b1332ed85a93e9a3a20a569e333f281f312249e --- /dev/null +++ b/ui/ui/select_item.slint @@ -0,0 +1,35 @@ +import { ComboBox } from "std-widgets.slint"; +export component SelectItem { + in property label; + in-out property value; + HorizontalLayout { + spacing: 4px; + Rectangle { + width: 64px; + height: 36px; + Text { + width: 64px; + horizontal-alignment: TextHorizontalAlignment.left; + font-size: 18px; + text: root.label; + } + } + + Rectangle { + border-color: #aaa; + border-width: 1px; + border-radius: 5px; + width: 480px; + height: 36px; + ComboBox { + width: 100%; + height: 100%; + current-value: value; + model: ["Mysql","Sql Server"]; + selected => { + root.value = self.current-value; + } + } + } + } +}