You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by xu...@apache.org on 2024/08/26 15:05:31 UTC
(opendal) branch main updated: refactor: use sqlx for sql services (#5040)
This is an automated email from the ASF dual-hosted git repository.
xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal.git
The following commit(s) were added to refs/heads/main by this push:
new 69ed149109 refactor: use sqlx for sql services (#5040)
69ed149109 is described below
commit 69ed149109841e348232242a08baba324ee5e4f0
Author: tison <wa...@gmail.com>
AuthorDate: Mon Aug 26 23:05:24 2024 +0800
refactor: use sqlx for sql services (#5040)
* refactor: use sqlx for sql services
Signed-off-by: tison <wa...@gmail.com>
* migrate postgresql services
Signed-off-by: tison <wa...@gmail.com>
* migrate mysql services
Signed-off-by: tison <wa...@gmail.com>
* migrate sqlite services
Signed-off-by: tison <wa...@gmail.com>
* fixup
Signed-off-by: tison <wa...@gmail.com>
* docs
Signed-off-by: tison <wa...@gmail.com>
* fixup build by revert
Signed-off-by: tison <wa...@gmail.com>
* clippy
Signed-off-by: tison <wa...@gmail.com>
* f tokio runtime
Signed-off-by: tison <wa...@gmail.com>
* build bindings
Signed-off-by: tison <wa...@gmail.com>
* tidy
Signed-off-by: tison <wa...@gmail.com>
* fixup
Signed-off-by: tison <wa...@gmail.com>
* Update cargo.lock
Signed-off-by: Xuanwo <gi...@xuanwo.io>
---------
Signed-off-by: tison <wa...@gmail.com>
Signed-off-by: Xuanwo <gi...@xuanwo.io>
Co-authored-by: Xuanwo <gi...@xuanwo.io>
---
bindings/c/src/operator.rs | 4 +-
bindings/cpp/src/lib.rs | 5 +-
bindings/dotnet/src/lib.rs | 4 +-
bindings/haskell/src/lib.rs | 2 +-
bindings/java/src/async_operator.rs | 2 +-
bindings/lua/src/lib.rs | 4 +-
bindings/nodejs/src/lib.rs | 2 +-
bindings/ocaml/src/lib.rs | 2 +-
bindings/php/src/lib.rs | 2 +-
bindings/ruby/src/lib.rs | 2 +-
core/Cargo.lock | 773 ++++++++++++--------------------
core/Cargo.toml | 29 +-
core/src/docs/upgrade.md | 8 +
core/src/services/mysql/backend.rs | 159 +++----
core/src/services/mysql/config.rs | 13 +-
core/src/services/postgresql/backend.rs | 198 +++-----
core/src/services/postgresql/config.rs | 9 +-
core/src/services/sqlite/backend.rs | 234 ++++------
core/src/services/sqlite/config.rs | 8 +-
integrations/cloudfilter/src/lib.rs | 20 +-
20 files changed, 559 insertions(+), 921 deletions(-)
diff --git a/bindings/c/src/operator.rs b/bindings/c/src/operator.rs
index a8d9266024..71a1e52e68 100644
--- a/bindings/c/src/operator.rs
+++ b/bindings/c/src/operator.rs
@@ -102,7 +102,7 @@ fn build_operator(
schema: core::Scheme,
map: HashMap<String, String>,
) -> core::Result<core::Operator> {
- let mut op = match core::Operator::via_map(schema, map) {
+ let mut op = match core::Operator::via_iter(schema, map) {
Ok(o) => o,
Err(e) => return Err(e),
};
@@ -173,7 +173,7 @@ pub unsafe extern "C" fn opendal_operator_new(
}
};
- let mut map = HashMap::default();
+ let mut map = HashMap::<String, String>::default();
if !options.is_null() {
for (k, v) in (*options).as_ref() {
map.insert(k.to_string(), v.to_string());
diff --git a/bindings/cpp/src/lib.rs b/bindings/cpp/src/lib.rs
index 8d86947821..f8b4a77d25 100644
--- a/bindings/cpp/src/lib.rs
+++ b/bindings/cpp/src/lib.rs
@@ -19,6 +19,7 @@ mod lister;
mod reader;
mod types;
+use std::collections::HashMap;
use std::str::FromStr;
use anyhow::Result;
@@ -101,12 +102,12 @@ pub struct Operator(od::BlockingOperator);
fn new_operator(scheme: &str, configs: Vec<ffi::HashMapValue>) -> Result<Box<Operator>> {
let scheme = od::Scheme::from_str(scheme)?;
- let map = configs
+ let map: HashMap<String, String> = configs
.into_iter()
.map(|value| (value.key, value.value))
.collect();
- let op = Box::new(Operator(od::Operator::via_map(scheme, map)?.blocking()));
+ let op = Box::new(Operator(od::Operator::via_iter(scheme, map)?.blocking()));
Ok(op)
}
diff --git a/bindings/dotnet/src/lib.rs b/bindings/dotnet/src/lib.rs
index de2c1a5f37..acfd5834a2 100644
--- a/bindings/dotnet/src/lib.rs
+++ b/bindings/dotnet/src/lib.rs
@@ -36,9 +36,9 @@ pub unsafe extern "C" fn blocking_operator_construct(
Err(_) => return std::ptr::null(),
};
- let mut map = HashMap::default();
+ let mut map = HashMap::<String, String>::default();
map.insert("root".to_string(), "/tmp".to_string());
- let op = match opendal::Operator::via_map(scheme, map) {
+ let op = match opendal::Operator::via_iter(scheme, map) {
Ok(op) => op.blocking(),
Err(err) => {
println!("err={err:?}");
diff --git a/bindings/haskell/src/lib.rs b/bindings/haskell/src/lib.rs
index 17f7313b27..c470699d09 100644
--- a/bindings/haskell/src/lib.rs
+++ b/bindings/haskell/src/lib.rs
@@ -99,7 +99,7 @@ pub unsafe extern "C" fn via_map_ffi(
}
}
- let res = match od::Operator::via_map(scheme, map) {
+ let res = match od::Operator::via_iter(scheme, map) {
Ok(mut operator) => {
operator = operator.layer(RetryLayer::new());
if callback.is_some() {
diff --git a/bindings/java/src/async_operator.rs b/bindings/java/src/async_operator.rs
index d7b2ed77a1..b30fdc8df8 100644
--- a/bindings/java/src/async_operator.rs
+++ b/bindings/java/src/async_operator.rs
@@ -66,7 +66,7 @@ fn intern_constructor(
) -> Result<jlong> {
let scheme = Scheme::from_str(jstring_to_string(env, &scheme)?.as_str())?;
let map = jmap_to_hashmap(env, &map)?;
- let mut op = Operator::via_map(scheme, map)?;
+ let mut op = Operator::via_iter(scheme, map)?;
if !op.info().full_capability().blocking {
let layer = executor_or_default(env, executor)?.enter_with(BlockingLayer::create)?;
op = op.layer(layer);
diff --git a/bindings/lua/src/lib.rs b/bindings/lua/src/lib.rs
index 182fce8e3d..d220b9c927 100644
--- a/bindings/lua/src/lib.rs
+++ b/bindings/lua/src/lib.rs
@@ -44,7 +44,7 @@ fn operator_new<'a>(
return Err(LuaError::external("schema is empty"));
}
- let mut map = HashMap::default();
+ let mut map = HashMap::<String, String>::default();
for pair in option.pairs::<String, String>() {
let (key, value) = pair?;
map.insert(key, value);
@@ -55,7 +55,7 @@ fn operator_new<'a>(
Err(e) => return Err(LuaError::external(e)),
};
- let op = match od::Operator::via_map(od_schema, map) {
+ let op = match od::Operator::via_iter(od_schema, map) {
Ok(o) => o.blocking(),
Err(e) => return Err(LuaError::external(e)),
};
diff --git a/bindings/nodejs/src/lib.rs b/bindings/nodejs/src/lib.rs
index dcc45f15c9..bd6c688099 100644
--- a/bindings/nodejs/src/lib.rs
+++ b/bindings/nodejs/src/lib.rs
@@ -49,7 +49,7 @@ impl Operator {
.map_err(format_napi_error)?;
let options = options.unwrap_or_default();
- let mut op = opendal::Operator::via_map(scheme, options).map_err(format_napi_error)?;
+ let mut op = opendal::Operator::via_iter(scheme, options).map_err(format_napi_error)?;
if !op.info().full_capability().blocking {
if let Ok(handle) = tokio::runtime::Handle::try_current() {
diff --git a/bindings/ocaml/src/lib.rs b/bindings/ocaml/src/lib.rs
index a69c584f46..9a6ee61392 100644
--- a/bindings/ocaml/src/lib.rs
+++ b/bindings/ocaml/src/lib.rs
@@ -30,7 +30,7 @@ pub fn new_operator(
) -> Result<od::Operator, od::Error> {
let hm: HashMap<String, String> = map.into_iter().collect();
let scheme: od::Scheme = od::Scheme::from_str(&scheme_str)?;
- od::Operator::via_map(scheme, hm)
+ od::Operator::via_iter(scheme, hm)
}
pub fn map_res_error<T>(res: Result<T, od::Error>) -> Result<T, String> {
diff --git a/bindings/php/src/lib.rs b/bindings/php/src/lib.rs
index 2e5166935f..eb91bd004f 100644
--- a/bindings/php/src/lib.rs
+++ b/bindings/php/src/lib.rs
@@ -33,7 +33,7 @@ pub struct Operator(od::BlockingOperator);
impl Operator {
pub fn __construct(scheme_str: String, config: HashMap<String, String>) -> PhpResult<Self> {
let scheme = od::Scheme::from_str(&scheme_str).map_err(format_php_err)?;
- let op = od::Operator::via_map(scheme, config).map_err(format_php_err)?;
+ let op = od::Operator::via_iter(scheme, config).map_err(format_php_err)?;
Ok(Operator(op.blocking()))
}
diff --git a/bindings/ruby/src/lib.rs b/bindings/ruby/src/lib.rs
index a2c319a61c..c47e9af88a 100644
--- a/bindings/ruby/src/lib.rs
+++ b/bindings/ruby/src/lib.rs
@@ -42,7 +42,7 @@ impl Operator {
.map_err(format_magnus_error)?;
let options = options.unwrap_or_default();
- let op = od::Operator::via_map(scheme, options)
+ let op = od::Operator::via_iter(scheme, options)
.map_err(format_magnus_error)?
.blocking();
Ok(Operator(op))
diff --git a/core/Cargo.lock b/core/Cargo.lock
index 3980affb72..d25c6e29f7 100644
--- a/core/Cargo.lock
+++ b/core/Cargo.lock
@@ -472,6 +472,15 @@ dependencies = [
"rustc_version 0.4.0",
]
+[[package]]
+name = "atoi"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528"
+dependencies = [
+ "num-traits",
+]
+
[[package]]
name = "atomic-polyfill"
version = "1.0.3"
@@ -489,9 +498,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "atomic_lib"
-version = "0.38.0"
+version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99ab64938781097020b16f509869f6c3fa35062c43ea210bbcf90a96a9950c1b"
+checksum = "858bfa5f57658b74589eb3254a212446e8582c6072af4c05946e87be1d7e4694"
dependencies = [
"base64 0.21.7",
"rand 0.8.5",
@@ -599,33 +608,6 @@ dependencies = [
"zeroize",
]
-[[package]]
-name = "aws-lc-rs"
-version = "1.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ae74d9bd0a7530e8afd1770739ad34b36838829d6ad61818f9230f683f5ad77"
-dependencies = [
- "aws-lc-sys",
- "mirai-annotations",
- "paste",
- "zeroize",
-]
-
-[[package]]
-name = "aws-lc-sys"
-version = "0.20.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f0e249228c6ad2d240c2dc94b714d711629d52bad946075d8e9b2f5391f0703"
-dependencies = [
- "bindgen 0.69.4",
- "cc",
- "cmake",
- "dunce",
- "fs_extra",
- "libc",
- "paste",
-]
-
[[package]]
name = "aws-runtime"
version = "1.4.0"
@@ -1128,18 +1110,6 @@ dependencies = [
"tokio",
]
-[[package]]
-name = "bb8-postgres"
-version = "0.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56ac82c42eb30889b5c4ee4763a24b8c566518171ebea648cd7e3bc532c60680"
-dependencies = [
- "async-trait",
- "bb8",
- "tokio",
- "tokio-postgres",
-]
-
[[package]]
name = "bcrypt"
version = "0.15.1"
@@ -1153,19 +1123,6 @@ dependencies = [
"zeroize",
]
-[[package]]
-name = "bigdecimal"
-version = "0.4.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51d712318a27c7150326677b321a5fa91b55f6d9034ffd67f20319e147d40cee"
-dependencies = [
- "autocfg",
- "libm",
- "num-bigint",
- "num-integer",
- "num-traits",
-]
-
[[package]]
name = "bincode"
version = "1.3.3"
@@ -1219,24 +1176,6 @@ dependencies = [
"which",
]
-[[package]]
-name = "bindgen"
-version = "0.70.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f"
-dependencies = [
- "bitflags 2.6.0",
- "cexpr",
- "clang-sys",
- "itertools 0.13.0",
- "proc-macro2",
- "quote",
- "regex",
- "rustc-hash 1.1.0",
- "shlex",
- "syn 2.0.76",
-]
-
[[package]]
name = "bit-set"
version = "0.5.3"
@@ -1263,6 +1202,9 @@ name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+dependencies = [
+ "serde",
+]
[[package]]
name = "bitvec"
@@ -1371,15 +1313,6 @@ dependencies = [
"uuid",
]
-[[package]]
-name = "btoi"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9dd6407f73a9b8b6162d8a2ef999fe6afd7cc15902ebf42c5cd296addf17e0ad"
-dependencies = [
- "num-traits",
-]
-
[[package]]
name = "bumpalo"
version = "3.16.0"
@@ -1718,15 +1651,6 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
-[[package]]
-name = "cmake"
-version = "0.1.51"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb1e43aa7fd152b1f968787f7dbcdeb306d1867ff373c69955211876c053f91a"
-dependencies = [
- "cc",
-]
-
[[package]]
name = "coarsetime"
version = "0.1.34"
@@ -2068,19 +1992,6 @@ version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f64009896348fc5af4222e9cf7d7d82a95a256c634ebcf61c53e4ea461422242"
-[[package]]
-name = "crossbeam"
-version = "0.8.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8"
-dependencies = [
- "crossbeam-channel",
- "crossbeam-deque",
- "crossbeam-epoch",
- "crossbeam-queue",
- "crossbeam-utils",
-]
-
[[package]]
name = "crossbeam-channel"
version = "0.5.13"
@@ -2499,12 +2410,6 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653"
-[[package]]
-name = "dunce"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
-
[[package]]
name = "earcutr"
version = "0.4.3"
@@ -2561,6 +2466,9 @@ name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
+dependencies = [
+ "serde",
+]
[[package]]
name = "elliptic-curve"
@@ -2665,6 +2573,17 @@ dependencies = [
"tower-service",
]
+[[package]]
+name = "etcetera"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943"
+dependencies = [
+ "cfg-if",
+ "home",
+ "windows-sys 0.48.0",
+]
+
[[package]]
name = "event-listener"
version = "2.5.3"
@@ -2703,24 +2622,6 @@ dependencies = [
"rand 0.7.3",
]
-[[package]]
-name = "fallible-iterator"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
-
-[[package]]
-name = "fallible-iterator"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
-
-[[package]]
-name = "fallible-streaming-iterator"
-version = "0.1.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
-
[[package]]
name = "fastrace"
version = "0.7.2"
@@ -2904,58 +2805,6 @@ dependencies = [
"libc",
]
-[[package]]
-name = "frunk"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11a351b59e12f97b4176ee78497dff72e4276fb1ceb13e19056aca7fa0206287"
-dependencies = [
- "frunk_core",
- "frunk_derives",
- "frunk_proc_macros",
-]
-
-[[package]]
-name = "frunk_core"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af2469fab0bd07e64ccf0ad57a1438f63160c69b2e57f04a439653d68eb558d6"
-
-[[package]]
-name = "frunk_derives"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0fa992f1656e1707946bbba340ad244f0814009ef8c0118eb7b658395f19a2e"
-dependencies = [
- "frunk_proc_macro_helpers",
- "quote",
- "syn 2.0.76",
-]
-
-[[package]]
-name = "frunk_proc_macro_helpers"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35b54add839292b743aeda6ebedbd8b11e93404f902c56223e51b9ec18a13d2c"
-dependencies = [
- "frunk_core",
- "proc-macro2",
- "quote",
- "syn 2.0.76",
-]
-
-[[package]]
-name = "frunk_proc_macros"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71b85a1d4a9a6b300b41c05e8e13ef2feca03e0334127f29eca9506a7fe13a93"
-dependencies = [
- "frunk_core",
- "frunk_proc_macro_helpers",
- "quote",
- "syn 2.0.76",
-]
-
[[package]]
name = "fs2"
version = "0.4.3"
@@ -2966,12 +2815,6 @@ dependencies = [
"winapi",
]
-[[package]]
-name = "fs_extra"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
-
[[package]]
name = "fst"
version = "0.4.7"
@@ -3052,6 +2895,17 @@ dependencies = [
"futures-util",
]
+[[package]]
+name = "futures-intrusive"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f"
+dependencies = [
+ "futures-core",
+ "lock_api",
+ "parking_lot 0.12.3",
+]
+
[[package]]
name = "futures-io"
version = "0.3.30"
@@ -3541,6 +3395,15 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+[[package]]
+name = "hkdf"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
+dependencies = [
+ "hmac",
+]
+
[[package]]
name = "hmac"
version = "0.12.1"
@@ -4036,15 +3899,6 @@ dependencies = [
"simple_asn1",
]
-[[package]]
-name = "keyed_priority_queue"
-version = "0.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ee7893dab2e44ae5f9d0173f26ff4aa327c10b01b06a72b52dd9405b628640d"
-dependencies = [
- "indexmap 2.4.0",
-]
-
[[package]]
name = "kv-log-macro"
version = "1.0.7"
@@ -4191,9 +4045,9 @@ dependencies = [
[[package]]
name = "libsqlite3-sys"
-version = "0.30.1"
+version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
+checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f"
dependencies = [
"cc",
"pkg-config",
@@ -4484,12 +4338,6 @@ dependencies = [
"windows-sys 0.52.0",
]
-[[package]]
-name = "mirai-annotations"
-version = "1.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1"
-
[[package]]
name = "moka"
version = "0.12.8"
@@ -4613,97 +4461,6 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
-[[package]]
-name = "mysql-common-derive"
-version = "0.31.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afe0450cc9344afff34915f8328600ab5ae19260802a334d0f72d2d5bdda3bfe"
-dependencies = [
- "darling 0.20.10",
- "heck 0.4.1",
- "num-bigint",
- "proc-macro-crate",
- "proc-macro-error",
- "proc-macro2",
- "quote",
- "syn 2.0.76",
- "termcolor",
- "thiserror",
-]
-
-[[package]]
-name = "mysql_async"
-version = "0.34.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0b66e411c31265e879d9814d03721f2daa7ad07337b6308cb4bb0cde7e6fd47"
-dependencies = [
- "bytes",
- "crossbeam",
- "flate2",
- "futures-core",
- "futures-sink",
- "futures-util",
- "keyed_priority_queue",
- "lru",
- "mysql_common",
- "pem 3.0.4",
- "percent-encoding",
- "pin-project",
- "rand 0.8.5",
- "rustls 0.23.12",
- "rustls-pemfile 2.1.3",
- "serde",
- "serde_json",
- "socket2 0.5.7",
- "thiserror",
- "tokio",
- "tokio-rustls 0.26.0",
- "tokio-util",
- "twox-hash",
- "url",
- "webpki",
- "webpki-roots 0.26.3",
-]
-
-[[package]]
-name = "mysql_common"
-version = "0.32.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "478b0ff3f7d67b79da2b96f56f334431aef65e15ba4b29dd74a4236e29582bdc"
-dependencies = [
- "base64 0.21.7",
- "bigdecimal",
- "bindgen 0.70.1",
- "bitflags 2.6.0",
- "bitvec",
- "btoi",
- "byteorder",
- "bytes",
- "cc",
- "cmake",
- "crc32fast",
- "flate2",
- "frunk",
- "lazy_static",
- "mysql-common-derive",
- "num-bigint",
- "num-traits",
- "rand 0.8.5",
- "regex",
- "rust_decimal",
- "saturating",
- "serde",
- "serde_json",
- "sha1",
- "sha2",
- "smallvec",
- "subprocess",
- "thiserror",
- "time",
- "uuid",
- "zstd",
-]
-
[[package]]
name = "nanoid"
version = "0.4.0"
@@ -4938,7 +4695,6 @@ dependencies = [
"backon",
"base64 0.22.1",
"bb8",
- "bb8-postgres",
"bytes",
"cacache",
"chrono",
@@ -4969,7 +4725,6 @@ dependencies = [
"moka",
"mongodb",
"monoio",
- "mysql_async",
"once_cell",
"openssh",
"openssh-sftp-client",
@@ -4982,25 +4737,23 @@ dependencies = [
"prometheus-client",
"prost 0.13.1",
"quick-xml 0.36.1",
- "r2d2",
"rand 0.8.5",
"redb",
"redis",
"reqsign",
"reqwest 0.12.7",
"rocksdb",
- "rusqlite",
"serde",
"serde_json",
"sha1",
"sha2",
"size",
"sled",
+ "sqlx",
"suppaftp",
"surrealdb",
"tikv-client",
"tokio",
- "tokio-postgres",
"tracing",
"tracing-subscriber",
"uuid",
@@ -5078,9 +4831,9 @@ dependencies = [
[[package]]
name = "openssh"
-version = "0.10.5"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "330f4b61092456dc0aaa0cf9a205d956cae07d8127a69ffeff6760a72549c77f"
+checksum = "0f27389e5da64700a3efb7f925e442f824f6e3d4b1c27f75e115a92ad3aecbb1"
dependencies = [
"libc",
"once_cell",
@@ -5088,14 +4841,13 @@ dependencies = [
"tempfile",
"thiserror",
"tokio",
- "tokio-pipe",
]
[[package]]
name = "openssh-sftp-client"
-version = "0.14.6"
+version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f472c9c38ea60bc161f8b5df4d04c79057003cdc12572eaad7f6dcc74e6fca5"
+checksum = "048be8afec5f72161c77f940db18a27acd99e26b532433e480361615830d03ae"
dependencies = [
"bytes",
"derive_destructure2",
@@ -5114,9 +4866,9 @@ dependencies = [
[[package]]
name = "openssh-sftp-client-lowlevel"
-version = "0.6.0"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a84f1a52761901fcf5b10885544085348a872e57294531ec9188145d9a83042"
+checksum = "12a5728cca10461b3842f715fb3d8acd7ef11e2635a0aff0eb5eceab2e1f1e4a"
dependencies = [
"awaitable",
"bytes",
@@ -5131,9 +4883,9 @@ dependencies = [
[[package]]
name = "openssh-sftp-error"
-version = "0.4.0"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "61a5aea093d714df10186f481a6003e3f906f6fc8360c026737a841f4f182996"
+checksum = "87ee6d9ea97e1fd08435222dd1eab26aa6a86674f0ff1a9583b48c98d1ef4801"
dependencies = [
"awaitable-error",
"openssh",
@@ -5445,15 +5197,6 @@ dependencies = [
"rustc_version 0.4.0",
]
-[[package]]
-name = "phf"
-version = "0.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
-dependencies = [
- "phf_shared 0.11.2",
-]
-
[[package]]
name = "phf_shared"
version = "0.10.0"
@@ -5463,15 +5206,6 @@ dependencies = [
"siphasher",
]
-[[package]]
-name = "phf_shared"
-version = "0.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
-dependencies = [
- "siphasher",
-]
-
[[package]]
name = "pico-args"
version = "0.5.0"
@@ -5640,35 +5374,6 @@ version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265"
-[[package]]
-name = "postgres-protocol"
-version = "0.6.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acda0ebdebc28befa84bee35e651e4c5f09073d668c7aed4cf7e23c3cda84b23"
-dependencies = [
- "base64 0.22.1",
- "byteorder",
- "bytes",
- "fallible-iterator 0.2.0",
- "hmac",
- "md-5",
- "memchr",
- "rand 0.8.5",
- "sha2",
- "stringprep",
-]
-
-[[package]]
-name = "postgres-types"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02048d9e032fb3cc3413bbf7b83a15d84a5d419778e2628751896d856498eee9"
-dependencies = [
- "bytes",
- "fallible-iterator 0.2.0",
- "postgres-protocol",
-]
-
[[package]]
name = "powerfmt"
version = "0.2.0"
@@ -6068,17 +5773,6 @@ dependencies = [
"proc-macro2",
]
-[[package]]
-name = "r2d2"
-version = "0.8.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93"
-dependencies = [
- "log",
- "parking_lot 0.12.3",
- "scheduled-thread-pool",
-]
-
[[package]]
name = "radium"
version = "0.7.0"
@@ -6672,20 +6366,6 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3f94e84c073f3b85d4012b44722fa8842b9986d741590d4f2636ad0a5b14143"
-[[package]]
-name = "rusqlite"
-version = "0.32.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e"
-dependencies = [
- "bitflags 2.6.0",
- "fallible-iterator 0.3.0",
- "fallible-streaming-iterator",
- "hashlink",
- "libsqlite3-sys",
- "smallvec",
-]
-
[[package]]
name = "rust-ini"
version = "0.21.1"
@@ -6823,7 +6503,6 @@ version = "0.23.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044"
dependencies = [
- "aws-lc-rs",
"log",
"once_cell",
"ring 0.17.8",
@@ -6899,7 +6578,6 @@ version = "0.102.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e"
dependencies = [
- "aws-lc-rs",
"ring 0.17.8",
"rustls-pki-types",
"untrusted 0.9.0",
@@ -6941,12 +6619,6 @@ dependencies = [
"winapi-util",
]
-[[package]]
-name = "saturating"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ece8e78b2f38ec51c51f5d475df0a7187ba5111b2a28bdc761ee05b075d40a71"
-
[[package]]
name = "schannel"
version = "0.1.23"
@@ -6956,15 +6628,6 @@ dependencies = [
"windows-sys 0.52.0",
]
-[[package]]
-name = "scheduled-thread-pool"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19"
-dependencies = [
- "parking_lot 0.12.3",
-]
-
[[package]]
name = "scoped-tls"
version = "1.0.1"
@@ -7353,6 +7016,9 @@ name = "smallvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+dependencies = [
+ "serde",
+]
[[package]]
name = "smol_str"
@@ -7467,6 +7133,213 @@ dependencies = [
"der 0.7.9",
]
+[[package]]
+name = "sqlformat"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f895e3734318cc55f1fe66258926c9b910c124d47520339efecbb6c59cec7c1f"
+dependencies = [
+ "nom",
+ "unicode_categories",
+]
+
+[[package]]
+name = "sqlx"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27144619c6e5802f1380337a209d2ac1c431002dd74c6e60aebff3c506dc4f0c"
+dependencies = [
+ "sqlx-core",
+ "sqlx-macros",
+ "sqlx-mysql",
+ "sqlx-postgres",
+ "sqlx-sqlite",
+]
+
+[[package]]
+name = "sqlx-core"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a999083c1af5b5d6c071d34a708a19ba3e02106ad82ef7bbd69f5e48266b613b"
+dependencies = [
+ "atoi",
+ "byteorder",
+ "bytes",
+ "crc",
+ "crossbeam-queue",
+ "either",
+ "event-listener 5.3.1",
+ "futures-channel",
+ "futures-core",
+ "futures-intrusive",
+ "futures-io",
+ "futures-util",
+ "hashbrown 0.14.5",
+ "hashlink",
+ "hex",
+ "indexmap 2.4.0",
+ "log",
+ "memchr",
+ "once_cell",
+ "paste",
+ "percent-encoding",
+ "rustls 0.21.12",
+ "rustls-pemfile 1.0.4",
+ "serde",
+ "serde_json",
+ "sha2",
+ "smallvec",
+ "sqlformat",
+ "thiserror",
+ "tokio",
+ "tokio-stream",
+ "tracing",
+ "url",
+ "webpki-roots 0.25.4",
+]
+
+[[package]]
+name = "sqlx-macros"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a23217eb7d86c584b8cbe0337b9eacf12ab76fe7673c513141ec42565698bb88"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "sqlx-core",
+ "sqlx-macros-core",
+ "syn 2.0.76",
+]
+
+[[package]]
+name = "sqlx-macros-core"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a099220ae541c5db479c6424bdf1b200987934033c2584f79a0e1693601e776"
+dependencies = [
+ "dotenvy",
+ "either",
+ "heck 0.5.0",
+ "hex",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "serde_json",
+ "sha2",
+ "sqlx-core",
+ "sqlx-mysql",
+ "sqlx-postgres",
+ "sqlx-sqlite",
+ "syn 2.0.76",
+ "tempfile",
+ "tokio",
+ "url",
+]
+
+[[package]]
+name = "sqlx-mysql"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5afe4c38a9b417b6a9a5eeffe7235d0a106716495536e7727d1c7f4b1ff3eba6"
+dependencies = [
+ "atoi",
+ "base64 0.22.1",
+ "bitflags 2.6.0",
+ "byteorder",
+ "bytes",
+ "crc",
+ "digest",
+ "dotenvy",
+ "either",
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-util",
+ "generic-array",
+ "hex",
+ "hkdf",
+ "hmac",
+ "itoa",
+ "log",
+ "md-5",
+ "memchr",
+ "once_cell",
+ "percent-encoding",
+ "rand 0.8.5",
+ "rsa",
+ "serde",
+ "sha1",
+ "sha2",
+ "smallvec",
+ "sqlx-core",
+ "stringprep",
+ "thiserror",
+ "tracing",
+ "whoami",
+]
+
+[[package]]
+name = "sqlx-postgres"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1dbb157e65f10dbe01f729339c06d239120221c9ad9fa0ba8408c4cc18ecf21"
+dependencies = [
+ "atoi",
+ "base64 0.22.1",
+ "bitflags 2.6.0",
+ "byteorder",
+ "crc",
+ "dotenvy",
+ "etcetera",
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-util",
+ "hex",
+ "hkdf",
+ "hmac",
+ "home",
+ "itoa",
+ "log",
+ "md-5",
+ "memchr",
+ "once_cell",
+ "rand 0.8.5",
+ "serde",
+ "serde_json",
+ "sha2",
+ "smallvec",
+ "sqlx-core",
+ "stringprep",
+ "thiserror",
+ "tracing",
+ "whoami",
+]
+
+[[package]]
+name = "sqlx-sqlite"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b2cdd83c008a622d94499c0006d8ee5f821f36c89b7d625c900e5dc30b5c5ee"
+dependencies = [
+ "atoi",
+ "flume",
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-intrusive",
+ "futures-util",
+ "libsqlite3-sys",
+ "log",
+ "percent-encoding",
+ "serde",
+ "serde_urlencoded",
+ "sqlx-core",
+ "tracing",
+ "url",
+]
+
[[package]]
name = "ssh_format"
version = "0.14.1"
@@ -7550,7 +7423,7 @@ dependencies = [
"new_debug_unreachable",
"once_cell",
"parking_lot 0.12.3",
- "phf_shared 0.10.0",
+ "phf_shared",
"precomputed-hash",
]
@@ -7599,16 +7472,6 @@ dependencies = [
"syn 2.0.76",
]
-[[package]]
-name = "subprocess"
-version = "0.2.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c2e86926081dda636c546d8c5e641661049d7562a68f5488be4a1f7f66f6086"
-dependencies = [
- "libc",
- "winapi",
-]
-
[[package]]
name = "subtle"
version = "2.6.1"
@@ -8087,42 +7950,6 @@ dependencies = [
"tokio",
]
-[[package]]
-name = "tokio-pipe"
-version = "0.2.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f213a84bffbd61b8fa0ba8a044b4bbe35d471d0b518867181e82bd5c15542784"
-dependencies = [
- "libc",
- "tokio",
-]
-
-[[package]]
-name = "tokio-postgres"
-version = "0.7.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03adcf0147e203b6032c0b2d30be1415ba03bc348901f3ff1cc0df6a733e60c3"
-dependencies = [
- "async-trait",
- "byteorder",
- "bytes",
- "fallible-iterator 0.2.0",
- "futures-channel",
- "futures-util",
- "log",
- "parking_lot 0.12.3",
- "percent-encoding",
- "phf",
- "pin-project-lite",
- "postgres-protocol",
- "postgres-types",
- "rand 0.8.5",
- "socket2 0.5.7",
- "tokio",
- "tokio-util",
- "whoami",
-]
-
[[package]]
name = "tokio-retry"
version = "0.3.0"
@@ -8325,6 +8152,7 @@ version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [
+ "log",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
@@ -8485,17 +8313,6 @@ dependencies = [
"utf-8",
]
-[[package]]
-name = "twox-hash"
-version = "1.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
-dependencies = [
- "cfg-if",
- "rand 0.8.5",
- "static_assertions",
-]
-
[[package]]
name = "typed-builder"
version = "0.10.0"
@@ -8589,6 +8406,12 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a"
+[[package]]
+name = "unicode_categories"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
+
[[package]]
name = "unsigned-varint"
version = "0.8.0"
@@ -9375,20 +9198,6 @@ name = "zeroize"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
-dependencies = [
- "zeroize_derive",
-]
-
-[[package]]
-name = "zeroize_derive"
-version = "1.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.76",
-]
[[package]]
name = "zigzag"
@@ -9398,31 +9207,3 @@ checksum = "70b40401a28d86ce16a330b863b86fd7dbee4d7c940587ab09ab8c019f9e3fdf"
dependencies = [
"num-traits",
]
-
-[[package]]
-name = "zstd"
-version = "0.13.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9"
-dependencies = [
- "zstd-safe",
-]
-
-[[package]]
-name = "zstd-safe"
-version = "7.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059"
-dependencies = [
- "zstd-sys",
-]
-
-[[package]]
-name = "zstd-sys"
-version = "2.0.13+zstd.1.5.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa"
-dependencies = [
- "cc",
- "pkg-config",
-]
diff --git a/core/Cargo.toml b/core/Cargo.toml
index 5bf9ec2f62..aa7e475ecf 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -161,7 +161,7 @@ services-mini-moka = ["dep:mini-moka"]
services-moka = ["dep:moka"]
services-mongodb = ["dep:mongodb"]
services-monoiofs = ["dep:monoio", "dep:flume"]
-services-mysql = ["dep:mysql_async"]
+services-mysql = ["dep:sqlx", "sqlx?/mysql"]
services-obs = [
"dep:reqsign",
"reqsign?/services-huaweicloud",
@@ -175,7 +175,7 @@ services-oss = [
]
services-pcloud = []
services-persy = ["dep:persy", "internal-tokio-rt"]
-services-postgresql = ["dep:tokio-postgres", "dep:bb8", "dep:bb8-postgres"]
+services-postgresql = ["dep:sqlx", "sqlx?/postgres"]
services-redb = ["dep:redb", "internal-tokio-rt"]
services-redis = ["dep:redis", "redis?/tokio-rustls-comp"]
services-redis-native-tls = ["services-redis", "redis?/tokio-native-tls-comp"]
@@ -189,7 +189,7 @@ services-s3 = [
services-seafile = []
services-sftp = ["dep:openssh", "dep:openssh-sftp-client", "dep:bb8"]
services-sled = ["dep:sled", "internal-tokio-rt"]
-services-sqlite = ["dep:rusqlite", "dep:r2d2", "internal-tokio-rt"]
+services-sqlite = ["dep:sqlx", "sqlx?/sqlite"]
services-supabase = []
services-surrealdb = ["dep:surrealdb"]
services-swift = []
@@ -263,18 +263,15 @@ rand = { version = "0.8", optional = true }
# general dependencies.
bb8 = { version = "0.8", optional = true }
prost = { version = "0.13", optional = true }
-r2d2 = { version = "0.8", optional = true }
sha1 = { version = "0.10.6", optional = true }
sha2 = { version = "0.10", optional = true }
+sqlx = { version = "0.8.0", features = ["runtime-tokio-rustls"], optional = true }
# For http based services.
reqsign = { version = "0.16", default-features = false, optional = true }
# for services-atomic-server
-atomic_lib = { version = "0.38", optional = true }
-# for services-postgres
-bb8-postgres = { version = "0.8.1", optional = true }
-tokio-postgres = { version = "0.7.8", optional = true }
+atomic_lib = { version = "0.39.0", optional = true }
# for services-cacache
cacache = { version = "13.0", default-features = false, features = [
"tokio-runtime",
@@ -301,15 +298,11 @@ mini-moka = { version = "0.10", optional = true }
moka = { version = "0.12", optional = true, features = ["future", "sync"] }
# for services-mongodb
mongodb = { version = "3", optional = true }
-# for services-mysql
-mysql_async = { version = "0.34", default-features = false, features = [
- "default-rustls",
-], optional = true }
# for services-sftp
-openssh = { version = "0.10.0", optional = true }
-openssh-sftp-client = { version = "0.14.0", optional = true, features = [
- "openssh",
- "tracing",
+openssh = { version = "0.11.0", optional = true }
+openssh-sftp-client = { version = "0.15.0", optional = true, features = [
+ "openssh",
+ "tracing",
] }
# for services-persy
persy = { version = "1.4.6", optional = true }
@@ -322,9 +315,7 @@ redis = { version = "0.26", features = [
"connection-manager",
], optional = true }
# for services-rocksdb
-rocksdb = { version = "0.21", default-features = false, optional = true }
-# for services-sqlite
-rusqlite = { version = "0.32", optional = true, features = ["bundled"] }
+rocksdb = { version = "0.21.0", default-features = false, optional = true }
# for services-sled
sled = { version = "0.34.7", optional = true }
# for services-ftp
diff --git a/core/src/docs/upgrade.md b/core/src/docs/upgrade.md
index fc22f78c3f..18d31ee269 100644
--- a/core/src/docs/upgrade.md
+++ b/core/src/docs/upgrade.md
@@ -1,3 +1,11 @@
+# Upgrade to v0.50
+
+## Public API
+
+### `services-postgresql`'s connect string now supports only URL format
+
+Previously, it supports both URL format and key-value format. After switching the implementation from `tokio-postgres` to `sqlx`, the service now supports only the URL format.
+
# Upgrade to v0.49
## Public API
diff --git a/core/src/services/mysql/backend.rs b/core/src/services/mysql/backend.rs
index 9e55d02f64..a7774e7730 100644
--- a/core/src/services/mysql/backend.rs
+++ b/core/src/services/mysql/backend.rs
@@ -15,16 +15,15 @@
// specific language governing permissions and limitations
// under the License.
-use std::fmt::Debug;
-
-use mysql_async::prelude::*;
-use mysql_async::Opts;
-use mysql_async::Pool;
-
use crate::raw::adapters::kv;
use crate::raw::*;
use crate::services::MysqlConfig;
use crate::*;
+use sqlx::mysql::MySqlConnectOptions;
+use sqlx::MySqlPool;
+use std::fmt::Debug;
+use std::str::FromStr;
+use tokio::sync::OnceCell;
impl Configurator for MysqlConfig {
type Builder = MysqlBuilder;
@@ -61,7 +60,7 @@ impl MysqlBuilder {
/// - `mysql://user:password@localhost:3306`
/// - `mysql://user:password@localhost:3306/db`
///
- /// For more information, please refer to [mysql client](https://dev.mysql.com/doc/refman/8.0/en/connecting-using-uri-or-key-value-pairs.html)
+ /// For more information, please refer to <https://docs.rs/sqlx/latest/sqlx/mysql/struct.MySqlConnectOptions.html>.
pub fn connection_string(mut self, v: &str) -> Self {
if !v.is_empty() {
self.config.connection_string = Some(v.to_string());
@@ -116,7 +115,7 @@ impl Builder for MysqlBuilder {
type Config = MysqlConfig;
fn build(self) -> Result<impl Access> {
- let conn = match self.config.connection_string.clone() {
+ let conn = match self.config.connection_string {
Some(v) => v,
None => {
return Err(
@@ -126,38 +125,31 @@ impl Builder for MysqlBuilder {
}
};
- let config = Opts::from_url(&conn).map_err(|err| {
+ let config = MySqlConnectOptions::from_str(&conn).map_err(|err| {
Error::new(ErrorKind::ConfigInvalid, "connection_string is invalid")
.with_context("service", Scheme::Mysql)
.set_source(err)
})?;
- let table = match self.config.table.clone() {
+ let table = match self.config.table {
Some(v) => v,
None => {
return Err(Error::new(ErrorKind::ConfigInvalid, "table is empty")
.with_context("service", Scheme::Mysql))
}
};
- let key_field = match self.config.key_field.clone() {
- Some(v) => v,
- None => "key".to_string(),
- };
- let value_field = match self.config.value_field.clone() {
- Some(v) => v,
- None => "value".to_string(),
- };
- let root = normalize_root(
- self.config
- .root
- .clone()
- .unwrap_or_else(|| "/".to_string())
- .as_str(),
- );
- let pool = Pool::new(config.clone());
+
+ let key_field = self.config.key_field.unwrap_or_else(|| "key".to_string());
+
+ let value_field = self
+ .config
+ .value_field
+ .unwrap_or_else(|| "value".to_string());
+
+ let root = normalize_root(self.config.root.unwrap_or_else(|| "/".to_string()).as_str());
Ok(MySqlBackend::new(Adapter {
- connection_pool: pool,
+ pool: OnceCell::new(),
config,
table,
key_field,
@@ -170,25 +162,26 @@ impl Builder for MysqlBuilder {
/// Backend for mysql service
pub type MySqlBackend = kv::Backend<Adapter>;
-#[derive(Clone)]
+#[derive(Debug, Clone)]
pub struct Adapter {
- connection_pool: Pool,
- config: Opts,
+ pool: OnceCell<MySqlPool>,
+ config: MySqlConnectOptions,
table: String,
key_field: String,
value_field: String,
}
-impl Debug for Adapter {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.debug_struct("Adapter")
- .field("connection_pool", &self.connection_pool)
- .field("config", &self.config)
- .field("table", &self.table)
- .field("key_field", &self.key_field)
- .field("value_field", &self.value_field)
- .finish()
+impl Adapter {
+ async fn get_client(&self) -> Result<&MySqlPool> {
+ self.pool
+ .get_or_try_init(|| async {
+ let pool = MySqlPool::connect_with(self.config.clone())
+ .await
+ .map_err(parse_mysql_error)?;
+ Ok(pool)
+ })
+ .await
}
}
@@ -206,81 +199,53 @@ impl kv::Adapter for Adapter {
}
async fn get(&self, path: &str) -> Result<Option<Buffer>> {
- let query = format!(
- "SELECT `{}` FROM `{}` WHERE `{}` = :path LIMIT 1",
+ let pool = self.get_client().await?;
+
+ let value: Option<Vec<u8>> = sqlx::query_scalar(&format!(
+ "SELECT `{}` FROM `{}` WHERE `{}` = ? LIMIT 1",
self.value_field, self.table, self.key_field
- );
- let mut conn = self
- .connection_pool
- .get_conn()
- .await
- .map_err(parse_mysql_error)?;
- let statement = conn.prep(query).await.map_err(parse_mysql_error)?;
- let result: Option<Vec<u8>> = conn
- .exec_first(
- statement,
- params! {
- "path" => path,
- },
- )
- .await
- .map_err(parse_mysql_error)?;
- match result {
- Some(v) => Ok(Some(Buffer::from(v))),
- None => Ok(None),
- }
+ ))
+ .bind(path)
+ .fetch_optional(pool)
+ .await
+ .map_err(parse_mysql_error)?;
+
+ Ok(value.map(Buffer::from))
}
async fn set(&self, path: &str, value: Buffer) -> Result<()> {
- let query = format!(
- "INSERT INTO `{}` (`{}`, `{}`)
- VALUES (:path, :value)
- ON DUPLICATE KEY UPDATE `{}` = VALUES({})",
+ let pool = self.get_client().await?;
+
+ sqlx::query(&format!(
+ r#"INSERT INTO `{}` (`{}`, `{}`) VALUES (?, ?)
+ ON DUPLICATE KEY UPDATE `{}` = VALUES({})"#,
self.table, self.key_field, self.value_field, self.value_field, self.value_field
- );
- let mut conn = self
- .connection_pool
- .get_conn()
- .await
- .map_err(parse_mysql_error)?;
- let statement = conn.prep(query).await.map_err(parse_mysql_error)?;
-
- conn.exec_drop(
- statement,
- params! {
- "path" => path,
- "value" => value.to_vec(),
- },
- )
+ ))
+ .bind(path)
+ .bind(value.to_vec())
+ .execute(pool)
.await
.map_err(parse_mysql_error)?;
+
Ok(())
}
async fn delete(&self, path: &str) -> Result<()> {
- let query = format!(
- "DELETE FROM `{}` WHERE `{}` = :path",
- self.table, self.key_field
- );
- let mut conn = self
- .connection_pool
- .get_conn()
- .await
- .map_err(parse_mysql_error)?;
- let statement = conn.prep(query).await.map_err(parse_mysql_error)?;
+ let pool = self.get_client().await?;
- conn.exec_drop(
- statement,
- params! {
- "path" => path,
- },
- )
+ sqlx::query(&format!(
+ "DELETE FROM `{}` WHERE `{}` = ?",
+ self.table, self.key_field
+ ))
+ .bind(path)
+ .execute(pool)
.await
.map_err(parse_mysql_error)?;
+
Ok(())
}
}
-fn parse_mysql_error(err: mysql_async::Error) -> Error {
+fn parse_mysql_error(err: sqlx::Error) -> Error {
Error::new(ErrorKind::Unexpected, "unhandled error from mysql").set_source(err)
}
diff --git a/core/src/services/mysql/config.rs b/core/src/services/mysql/config.rs
index a27037b935..1c63229443 100644
--- a/core/src/services/mysql/config.rs
+++ b/core/src/services/mysql/config.rs
@@ -23,7 +23,18 @@ use std::fmt::{Debug, Formatter};
#[serde(default)]
#[non_exhaustive]
pub struct MysqlConfig {
- /// The connection string for mysql.
+ /// This connection string is used to connect to the mysql service. There are url based formats:
+ ///
+ /// ## Url
+ ///
+ /// This format resembles the url format of the mysql client. The format is: `[scheme://][user[:[password]]@]host[:port][/schema][?attribute1=value1&attribute2=value2...`
+ ///
+ /// - `mysql://user@localhost`
+ /// - `mysql://user:password@localhost`
+ /// - `mysql://user:password@localhost:3306`
+ /// - `mysql://user:password@localhost:3306/db`
+ ///
+ /// For more information, please refer to <https://docs.rs/sqlx/latest/sqlx/mysql/struct.MySqlConnectOptions.html>.
pub connection_string: Option<String>,
/// The table name for mysql.
diff --git a/core/src/services/postgresql/backend.rs b/core/src/services/postgresql/backend.rs
index bc3544d359..7759963bf5 100644
--- a/core/src/services/postgresql/backend.rs
+++ b/core/src/services/postgresql/backend.rs
@@ -15,20 +15,16 @@
// specific language governing permissions and limitations
// under the License.
-use std::fmt::Debug;
-use std::fmt::Formatter;
-use std::str::FromStr;
-use std::sync::Arc;
-
-use bb8::Pool;
-use bb8_postgres::PostgresConnectionManager;
-use tokio::sync::OnceCell;
-use tokio_postgres::Config;
-
use crate::raw::adapters::kv;
use crate::raw::*;
use crate::services::PostgresqlConfig;
use crate::*;
+use sqlx::postgres::PgConnectOptions;
+use sqlx::PgPool;
+use std::fmt::Debug;
+use std::fmt::Formatter;
+use std::str::FromStr;
+use tokio::sync::OnceCell;
impl Configurator for PostgresqlConfig {
type Builder = PostgresqlBuilder;
@@ -54,36 +50,16 @@ impl Debug for PostgresqlBuilder {
}
impl PostgresqlBuilder {
- /// Set the connection_string of the postgresql service.
- ///
- /// This connection string is `libpq-style connection strings`. There are two formats:
- ///
- /// ## Key Value
+ /// Set the connection url string of the postgresql service.
///
- /// This format consists of space-separated key-value pairs. Values which are either the empty
- /// string or contain whitespace should be wrapped in '. ' and \ characters should be
- /// backslash-escaped.
- ///
- /// - `host=localhost user=postgres connect_timeout=10 keepalives=0`
- /// - `host=/var/lib/postgresql,localhost port=1234 user=postgres password='password with spaces'`
- /// - `host=host1,host2,host3 port=1234,,5678 user=postgres target_session_attrs=read-write`
- ///
- /// Available keys could found at: <https://docs.rs/postgres/latest/postgres/config/struct.Config.html>
- ///
- /// ## Url
- ///
- /// This format resembles a URL with a scheme of either `postgres://` or `postgresql://`.
+ /// The URL should be with a scheme of either `postgres://` or `postgresql://`.
///
/// - `postgresql://user@localhost`
/// - `postgresql://user:password@%2Fvar%2Flib%2Fpostgresql/mydb?connect_timeout=10`
/// - `postgresql://user@host1:1234,host2,host3:5678?target_session_attrs=read-write`
/// - `postgresql:///mydb?user=user&host=/var/lib/postgresql`
///
- /// # Notes
- ///
- /// If connection_string has been specified, other parameters will be ignored.
- ///
- /// For more information, please visit <https://docs.rs/postgres/latest/postgres/config/struct.Config.html>
+ /// For more information, please visit <https://docs.rs/sqlx/latest/sqlx/postgres/struct.PgConnectOptions.html>.
pub fn connection_string(mut self, v: &str) -> Self {
if !v.is_empty() {
self.config.connection_string = Some(v.to_string());
@@ -91,7 +67,7 @@ impl PostgresqlBuilder {
self
}
- /// set the working directory, all operations will be performed under it.
+ /// Set the working directory, all operations will be performed under it.
///
/// default: "/"
pub fn root(mut self, root: &str) -> Self {
@@ -138,7 +114,7 @@ impl Builder for PostgresqlBuilder {
type Config = PostgresqlConfig;
fn build(self) -> Result<impl Access> {
- let conn = match self.config.connection_string.clone() {
+ let conn = match self.config.connection_string {
Some(v) => v,
None => {
return Err(
@@ -148,34 +124,28 @@ impl Builder for PostgresqlBuilder {
}
};
- let config = Config::from_str(&conn).map_err(|err| {
+ let config = PgConnectOptions::from_str(&conn).map_err(|err| {
Error::new(ErrorKind::ConfigInvalid, "connection_string is invalid")
.with_context("service", Scheme::Postgresql)
.set_source(err)
})?;
- let table = match self.config.table.clone() {
+ let table = match self.config.table {
Some(v) => v,
None => {
return Err(Error::new(ErrorKind::ConfigInvalid, "table is empty")
.with_context("service", Scheme::Postgresql))
}
};
- let key_field = match self.config.key_field.clone() {
- Some(v) => v,
- None => "key".to_string(),
- };
- let value_field = match self.config.value_field.clone() {
- Some(v) => v,
- None => "value".to_string(),
- };
- let root = normalize_root(
- self.config
- .root
- .clone()
- .unwrap_or_else(|| "/".to_string())
- .as_str(),
- );
+
+ let key_field = self.config.key_field.unwrap_or_else(|| "key".to_string());
+
+ let value_field = self
+ .config
+ .value_field
+ .unwrap_or_else(|| "value".to_string());
+
+ let root = normalize_root(self.config.root.unwrap_or_else(|| "/".to_string()).as_str());
Ok(PostgresqlBackend::new(Adapter {
pool: OnceCell::new(),
@@ -191,38 +161,26 @@ impl Builder for PostgresqlBuilder {
/// Backend for Postgresql service
pub type PostgresqlBackend = kv::Backend<Adapter>;
-#[derive(Clone)]
+#[derive(Debug, Clone)]
pub struct Adapter {
- pool: OnceCell<Arc<Pool<PostgresConnectionManager<tokio_postgres::NoTls>>>>,
- config: Config,
+ pool: OnceCell<PgPool>,
+ config: PgConnectOptions,
table: String,
key_field: String,
value_field: String,
}
-impl Debug for Adapter {
- fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
- let mut ds = f.debug_struct("Adapter");
- ds.finish_non_exhaustive()
- }
-}
-
impl Adapter {
- async fn get_client(&self) -> Result<&Pool<PostgresConnectionManager<tokio_postgres::NoTls>>> {
+ async fn get_client(&self) -> Result<&PgPool> {
self.pool
.get_or_try_init(|| async {
- // TODO: add tls support.
- let manager =
- PostgresConnectionManager::new(self.config.clone(), tokio_postgres::NoTls);
- let pool = Pool::builder()
- .build(manager)
+ let pool = PgPool::connect_with(self.config.clone())
.await
- .map_err(parse_postgre_error)?;
- Ok(Arc::new(pool))
+ .map_err(parse_postgres_error)?;
+ Ok(pool)
})
.await
- .map(|v| v.as_ref())
}
}
@@ -240,83 +198,57 @@ impl kv::Adapter for Adapter {
}
async fn get(&self, path: &str) -> Result<Option<Buffer>> {
- let query = format!(
- "SELECT {} FROM {} WHERE {} = $1 LIMIT 1",
+ let pool = self.get_client().await?;
+
+ let value: Option<Vec<u8>> = sqlx::query_scalar(&format!(
+ r#"SELECT "{}" FROM "{}" WHERE "{}" = $1 LIMIT 1"#,
self.value_field, self.table, self.key_field
- );
- let connection = self
- .get_client()
- .await?
- .get()
- .await
- .map_err(parse_bb8_error)?;
- let statement = connection
- .prepare(&query)
- .await
- .map_err(parse_postgre_error)?;
- let rows = connection
- .query(&statement, &[&path])
- .await
- .map_err(parse_postgre_error)?;
- if rows.is_empty() {
- return Ok(None);
- }
- let value: Vec<u8> = rows[0].get(0);
- Ok(Some(Buffer::from(value)))
+ ))
+ .bind(path)
+ .fetch_optional(pool)
+ .await
+ .map_err(parse_postgres_error)?;
+
+ Ok(value.map(Buffer::from))
}
async fn set(&self, path: &str, value: Buffer) -> Result<()> {
+ let pool = self.get_client().await?;
+
let table = &self.table;
let key_field = &self.key_field;
let value_field = &self.value_field;
- let query = format!(
- "INSERT INTO {table} ({key_field}, {value_field}) \
- VALUES ($1, $2) \
- ON CONFLICT ({key_field}) \
- DO UPDATE SET {value_field} = EXCLUDED.{value_field}",
- );
- let connection = self
- .get_client()
- .await?
- .get()
- .await
- .map_err(parse_bb8_error)?;
- let statement = connection
- .prepare(&query)
- .await
- .map_err(parse_postgre_error)?;
- let _ = connection
- .query(&statement, &[&path, &value.to_vec()])
- .await
- .map_err(parse_postgre_error)?;
+ sqlx::query(&format!(
+ r#"INSERT INTO "{table}" ("{key_field}", "{value_field}")
+ VALUES ($1, $2)
+ ON CONFLICT ("{key_field}")
+ DO UPDATE SET "{value_field}" = EXCLUDED."{value_field}""#,
+ ))
+ .bind(path)
+ .bind(value.to_vec())
+ .execute(pool)
+ .await
+ .map_err(parse_postgres_error)?;
+
Ok(())
}
async fn delete(&self, path: &str) -> Result<()> {
- let query = format!("DELETE FROM {} WHERE {} = $1", self.table, self.key_field);
- let connection = self
- .get_client()
- .await?
- .get()
- .await
- .map_err(parse_bb8_error)?;
- let statement = connection
- .prepare(&query)
- .await
- .map_err(parse_postgre_error)?;
+ let pool = self.get_client().await?;
+
+ sqlx::query(&format!(
+ "DELETE FROM {} WHERE {} = $1",
+ self.table, self.key_field
+ ))
+ .bind(path)
+ .execute(pool)
+ .await
+ .map_err(parse_postgres_error)?;
- let _ = connection
- .query(&statement, &[&path])
- .await
- .map_err(parse_postgre_error)?;
Ok(())
}
}
-fn parse_bb8_error(err: bb8::RunError<tokio_postgres::Error>) -> Error {
- Error::new(ErrorKind::Unexpected, "unhandled error from postgresql").set_source(err)
-}
-
-fn parse_postgre_error(err: tokio_postgres::Error) -> Error {
+fn parse_postgres_error(err: sqlx::Error) -> Error {
Error::new(ErrorKind::Unexpected, "unhandled error from postgresql").set_source(err)
}
diff --git a/core/src/services/postgresql/config.rs b/core/src/services/postgresql/config.rs
index 2a3dde90b8..2aee7d7d56 100644
--- a/core/src/services/postgresql/config.rs
+++ b/core/src/services/postgresql/config.rs
@@ -29,7 +29,14 @@ pub struct PostgresqlConfig {
///
/// Default to `/` if not set.
pub root: Option<String>,
- /// the connection string of postgres server
+ /// The URL should be with a scheme of either `postgres://` or `postgresql://`.
+ ///
+ /// - `postgresql://user@localhost`
+ /// - `postgresql://user:password@%2Fvar%2Flib%2Fpostgresql/mydb?connect_timeout=10`
+ /// - `postgresql://user@host1:1234,host2,host3:5678?target_session_attrs=read-write`
+ /// - `postgresql:///mydb?user=user&host=/var/lib/postgresql`
+ ///
+ /// For more information, please visit <https://docs.rs/sqlx/latest/sqlx/postgres/struct.PgConnectOptions.html>.
pub connection_string: Option<String>,
/// the table of postgresql
pub table: Option<String>,
diff --git a/core/src/services/sqlite/backend.rs b/core/src/services/sqlite/backend.rs
index 32ec4629a9..a8f182a901 100644
--- a/core/src/services/sqlite/backend.rs
+++ b/core/src/services/sqlite/backend.rs
@@ -15,17 +15,16 @@
// specific language governing permissions and limitations
// under the License.
-use std::fmt::Debug;
-use std::fmt::Formatter;
-
-use rusqlite::params;
-use rusqlite::Connection;
-use tokio::task;
-
use crate::raw::adapters::kv;
use crate::raw::*;
use crate::services::SqliteConfig;
use crate::*;
+use sqlx::sqlite::SqliteConnectOptions;
+use sqlx::SqlitePool;
+use std::fmt::Debug;
+use std::fmt::Formatter;
+use std::str::FromStr;
+use tokio::sync::OnceCell;
impl Configurator for SqliteConfig {
type Builder = SqliteBuilder;
@@ -56,11 +55,13 @@ impl SqliteBuilder {
///
/// ## Url
///
- /// This format resembles the url format of the sqlite client. The format is: `file://[path]?flag`
+ /// This format resembles the url format of the sqlite client:
///
- /// - `file://data.db`
+ /// - `sqlite::memory:`
+ /// - `sqlite:data.db`
+ /// - `sqlite://data.db`
///
- /// For more information, please refer to [Opening A New Database Connection](http://www.sqlite.org/c3ref/open.html)
+ /// For more information, please visit <https://docs.rs/sqlx/latest/sqlx/sqlite/struct.SqliteConnectOptions.html>.
pub fn connection_string(mut self, v: &str) -> Self {
if !v.is_empty() {
self.config.connection_string = Some(v.to_string());
@@ -115,7 +116,7 @@ impl Builder for SqliteBuilder {
type Config = SqliteConfig;
fn build(self) -> Result<impl Access> {
- let connection_string = match self.config.connection_string.clone() {
+ let conn = match self.config.connection_string {
Some(v) => v,
None => {
return Err(Error::new(
@@ -125,35 +126,33 @@ impl Builder for SqliteBuilder {
.with_context("service", Scheme::Sqlite));
}
};
- let table = match self.config.table.clone() {
+
+ let config = SqliteConnectOptions::from_str(&conn).map_err(|err| {
+ Error::new(ErrorKind::ConfigInvalid, "connection_string is invalid")
+ .with_context("service", Scheme::Sqlite)
+ .set_source(err)
+ })?;
+
+ let table = match self.config.table {
Some(v) => v,
None => {
return Err(Error::new(ErrorKind::ConfigInvalid, "table is empty")
.with_context("service", Scheme::Sqlite));
}
};
- let key_field = match self.config.key_field.clone() {
- Some(v) => v,
- None => "key".to_string(),
- };
- let value_field = match self.config.value_field.clone() {
- Some(v) => v,
- None => "value".to_string(),
- };
- let root = normalize_root(
- self.config
- .root
- .clone()
- .unwrap_or_else(|| "/".to_string())
- .as_str(),
- );
- let mgr = SqliteConnectionManager { connection_string };
- let pool = r2d2::Pool::new(mgr).map_err(|err| {
- Error::new(ErrorKind::Unexpected, "sqlite pool init failed").set_source(err)
- })?;
+
+ let key_field = self.config.key_field.unwrap_or_else(|| "key".to_string());
+
+ let value_field = self
+ .config
+ .value_field
+ .unwrap_or_else(|| "value".to_string());
+
+ let root = normalize_root(self.config.root.as_deref().unwrap_or("/"));
Ok(SqliteBackend::new(Adapter {
- pool,
+ pool: OnceCell::new(),
+ config,
table,
key_field,
value_field,
@@ -162,46 +161,28 @@ impl Builder for SqliteBuilder {
}
}
-struct SqliteConnectionManager {
- connection_string: String,
-}
-
-impl r2d2::ManageConnection for SqliteConnectionManager {
- type Connection = Connection;
- type Error = Error;
-
- fn connect(&self) -> Result<Connection> {
- Connection::open(&self.connection_string)
- .map_err(|err| Error::new(ErrorKind::Unexpected, "sqlite open error").set_source(err))
- }
-
- fn is_valid(&self, conn: &mut Connection) -> Result<()> {
- conn.execute_batch("").map_err(parse_rusqlite_error)
- }
-
- fn has_broken(&self, _: &mut Connection) -> bool {
- false
- }
-}
-
pub type SqliteBackend = kv::Backend<Adapter>;
-#[derive(Clone)]
+#[derive(Debug, Clone)]
pub struct Adapter {
- pool: r2d2::Pool<SqliteConnectionManager>,
+ pool: OnceCell<SqlitePool>,
+ config: SqliteConnectOptions,
table: String,
key_field: String,
value_field: String,
}
-impl Debug for Adapter {
- fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
- let mut ds = f.debug_struct("SqliteAdapter");
- ds.field("table", &self.table);
- ds.field("key_field", &self.key_field);
- ds.field("value_field", &self.value_field);
- ds.finish()
+impl Adapter {
+ async fn get_client(&self) -> Result<&SqlitePool> {
+ self.pool
+ .get_or_try_init(|| async {
+ let pool = SqlitePool::connect_with(self.config.clone())
+ .await
+ .map_err(parse_sqlite_error)?;
+ Ok(pool)
+ })
+ .await
}
}
@@ -214,7 +195,6 @@ impl kv::Adapter for Adapter {
read: true,
write: true,
delete: true,
- blocking: true,
list: true,
..Default::default()
},
@@ -222,108 +202,68 @@ impl kv::Adapter for Adapter {
}
async fn get(&self, path: &str) -> Result<Option<Buffer>> {
- let this = self.clone();
- let path = path.to_string();
-
- task::spawn_blocking(move || this.blocking_get(&path))
- .await
- .map_err(new_task_join_error)?
- }
+ let pool = self.get_client().await?;
- fn blocking_get(&self, path: &str) -> Result<Option<Buffer>> {
- let conn = self.pool.get().map_err(parse_r2d2_error)?;
-
- let query = format!(
- "SELECT {} FROM {} WHERE `{}` = $1 LIMIT 1",
+ let value: Option<Vec<u8>> = sqlx::query_scalar(&format!(
+ "SELECT `{}` FROM `{}` WHERE `{}` = $1 LIMIT 1",
self.value_field, self.table, self.key_field
- );
- let mut statement = conn.prepare(&query).map_err(parse_rusqlite_error)?;
- let result: rusqlite::Result<Vec<u8>> = statement.query_row([path], |row| row.get(0));
- match result {
- Ok(v) => Ok(Some(Buffer::from(v))),
- Err(rusqlite::Error::QueryReturnedNoRows) => Ok(None),
- Err(err) => Err(parse_rusqlite_error(err)),
- }
- }
+ ))
+ .bind(path)
+ .fetch_optional(pool)
+ .await
+ .map_err(parse_sqlite_error)?;
- async fn set(&self, path: &str, value: Buffer) -> Result<()> {
- let this = self.clone();
- let path = path.to_string();
- task::spawn_blocking(move || this.blocking_set(&path, value))
- .await
- .map_err(new_task_join_error)?
+ Ok(value.map(Buffer::from))
}
- fn blocking_set(&self, path: &str, value: Buffer) -> Result<()> {
- let conn = self.pool.get().map_err(parse_r2d2_error)?;
+ async fn set(&self, path: &str, value: Buffer) -> Result<()> {
+ let pool = self.get_client().await?;
- let query = format!(
+ sqlx::query(&format!(
"INSERT OR REPLACE INTO `{}` (`{}`, `{}`) VALUES ($1, $2)",
- self.table, self.key_field, self.value_field
- );
- let mut statement = conn.prepare(&query).map_err(parse_rusqlite_error)?;
- statement
- .execute(params![path, value.to_vec()])
- .map_err(parse_rusqlite_error)?;
+ self.table, self.key_field, self.value_field,
+ ))
+ .bind(path)
+ .bind(value.to_vec())
+ .execute(pool)
+ .await
+ .map_err(parse_sqlite_error)?;
+
Ok(())
}
async fn delete(&self, path: &str) -> Result<()> {
- let this = self.clone();
- let path = path.to_string();
-
- task::spawn_blocking(move || this.blocking_delete(&path))
- .await
- .map_err(new_task_join_error)?
- }
+ let pool = self.get_client().await?;
- fn blocking_delete(&self, path: &str) -> Result<()> {
- let conn = self.pool.get().map_err(parse_r2d2_error)?;
+ sqlx::query(&format!(
+ "DELETE FROM `{}` WHERE `{}` = $1",
+ self.table, self.key_field
+ ))
+ .bind(path)
+ .execute(pool)
+ .await
+ .map_err(parse_sqlite_error)?;
- let query = format!("DELETE FROM {} WHERE `{}` = $1", self.table, self.key_field);
- let mut statement = conn.prepare(&query).map_err(parse_rusqlite_error)?;
- statement.execute([path]).map_err(parse_rusqlite_error)?;
Ok(())
}
async fn scan(&self, path: &str) -> Result<Vec<String>> {
- let this = self.clone();
- let path = path.to_string();
-
- task::spawn_blocking(move || this.blocking_scan(&path))
- .await
- .map_err(new_task_join_error)?
- }
-
- fn blocking_scan(&self, path: &str) -> Result<Vec<String>> {
- let conn = self.pool.get().map_err(parse_r2d2_error)?;
- let query = format!(
- "SELECT {} FROM {} WHERE `{}` LIKE $1",
- self.key_field, self.table, self.key_field
- );
- let mut statement = conn.prepare(&query).map_err(parse_rusqlite_error)?;
- let like_param = format!("{}%", path);
- let result = statement.query(params![like_param]);
-
- match result {
- Ok(mut rows) => {
- let mut keys: Vec<String> = Vec::new();
- while let Some(row) = rows.next().map_err(parse_rusqlite_error)? {
- let item = row.get(0).map_err(parse_rusqlite_error)?;
- keys.push(item);
- }
- Ok(keys)
- }
- Err(rusqlite::Error::QueryReturnedNoRows) => Ok(vec![]),
- Err(err) => Err(parse_rusqlite_error(err)),
- }
+ let pool = self.get_client().await?;
+
+ let value = sqlx::query_scalar(&format!(
+ "SELECT `{}` FROM `{}` WHERE `{}` LIKE $1 and `{}` <> $2",
+ self.key_field, self.table, self.key_field, self.key_field
+ ))
+ .bind(format!("{path}%"))
+ .bind(path)
+ .fetch_all(pool)
+ .await
+ .map_err(parse_sqlite_error)?;
+
+ Ok(value)
}
}
-fn parse_rusqlite_error(err: rusqlite::Error) -> Error {
+fn parse_sqlite_error(err: sqlx::Error) -> Error {
Error::new(ErrorKind::Unexpected, "unhandled error from sqlite").set_source(err)
}
-
-fn parse_r2d2_error(err: r2d2::Error) -> Error {
- Error::new(ErrorKind::Unexpected, "unhandled error from r2d2").set_source(err)
-}
diff --git a/core/src/services/sqlite/config.rs b/core/src/services/sqlite/config.rs
index 55b2fd35eb..ca6cc659a3 100644
--- a/core/src/services/sqlite/config.rs
+++ b/core/src/services/sqlite/config.rs
@@ -29,11 +29,13 @@ pub struct SqliteConfig {
///
/// ## Url
///
- /// This format resembles the url format of the sqlite client. The format is: `file://[path]?flag`
+ /// This format resembles the url format of the sqlite client:
///
- /// - `file://data.db`
+ /// - `sqlite::memory:`
+ /// - `sqlite:data.db`
+ /// - `sqlite://data.db`
///
- /// For more information, please refer to [Opening A New Database Connection](http://www.sqlite.org/c3ref/open.html)
+ /// For more information, please visit <https://docs.rs/sqlx/latest/sqlx/sqlite/struct.SqliteConnectOptions.html>.
pub connection_string: Option<String>,
/// Set the table name of the sqlite service to read/write.
diff --git a/integrations/cloudfilter/src/lib.rs b/integrations/cloudfilter/src/lib.rs
index 05c34cf67a..e2170a02f4 100644
--- a/integrations/cloudfilter/src/lib.rs
+++ b/integrations/cloudfilter/src/lib.rs
@@ -19,9 +19,9 @@
//! It provides a way to access various cloud storage on Windows.
//!
//! Note that `cloudfilter_opendal` is a read-only service, and it is not recommended to use it in production.
-//!
+//!
//! # Example
-//!
+//!
//! ```no_run
//! use anyhow::Result;
//! use cloud_filter::root::PopulationType;
@@ -33,7 +33,7 @@
//! use opendal::Operator;
//! use tokio::runtime::Handle;
//! use tokio::signal;
-//!
+//!
//! #[tokio::main]
//! async fn main() -> Result<()> {
//! // Create any service desired
@@ -45,14 +45,14 @@
//! ("region".to_string(), "my_region".to_string()),
//! ])?
//! .finish();
-//!
+//!
//! let client_path = std::env::var("CLIENT_PATH").expect("$CLIENT_PATH is set");
-//!
+//!
//! // Create a sync root id
//! let sync_root_id = SyncRootIdBuilder::new("cloudfilter_opendal")
//! .user_security_id(SecurityId::current_user()?)
//! .build();
-//!
+//!
//! // Register the sync root if not exists
//! if !sync_root_id.is_registered()? {
//! sync_root_id.register(
@@ -65,20 +65,20 @@
//! .with_path(&client_path)?,
//! )?;
//! }
-//!
+//!
//! let handle = Handle::current();
//! let connection = Session::new().connect_async(
//! &client_path,
//! cloudfilter_opendal::CloudFilter::new(op, client_path.clone().into()),
//! move |f| handle.block_on(f),
//! )?;
-//!
+//!
//! signal::ctrl_c().await?;
-//!
+//!
//! // Drop the connection before unregister the sync root
//! drop(connection);
//! sync_root_id.unregister()?;
-//!
+//!
//! Ok(())
//! }
//! ``````