Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,784 changes: 1,049 additions & 735 deletions Cargo.lock

Large diffs are not rendered by default.

24 changes: 21 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ members = [
"examples/postgres/transaction",
"examples/sqlite/todos",
"examples/sqlite/extension",
"tests/mysql/wasm-components/connect-test",
"tests/mysql/wasm-components/execute-query-test",
"tests/mysql/wasm-components/pool-crud-test",
"tests/mysql/wasm-components/prepared-query-test",
"tests/mysql/wasm-components/tls-connect-test",
]

[workspace.package]
Expand Down Expand Up @@ -106,6 +111,9 @@ tls-rustls-ring = ["tls-rustls-ring-webpki"] # For backwards compatibility
tls-rustls-ring-webpki = ["sqlx-core/_tls-rustls-ring-webpki", "sqlx-macros?/_tls-rustls-ring-webpki"]
tls-rustls-ring-native-roots = ["sqlx-core/_tls-rustls-ring-native-roots", "sqlx-macros?/_tls-rustls-ring-native-roots"]

# WASM-native TLS via wasi-tls host interface. Only effective on wasm32 targets.
tls-wasm = ["sqlx-core/_tls-wasm"]

# No-op feature used by the workflows to compile without TLS enabled. Not meant for general use.
tls-none = []

Expand Down Expand Up @@ -186,11 +194,13 @@ mac_address = "1.1.5"
rust_decimal = { version = "1.26.1", default-features = false, features = ["std"] }
time = { version = "0.3.36", features = ["formatting", "parsing", "macros"] }
uuid = "1.1.2"

tokio-util = { version = "*" }
# Common utility crates
cfg-if = "1.0.0"
dotenvy = { version = "0.15.0", default-features = false }
thiserror = { version = "2.0.17", default-features = false, features = ["std"] }
wasip3 = "0.5.0"
wit-bindgen = { version = "0.54", default-features = false, features = ["async", "async-spawn", "inter-task-wakeup", "macros"] }

# Runtimes
[workspace.dependencies.async-global-executor]
Expand All @@ -207,7 +217,7 @@ default-features = false

[workspace.dependencies.tokio]
version = "1"
features = ["time", "net", "sync", "fs", "io-util", "rt"]
features = ["time", "sync", "io-util", "rt"]
default-features = false

[dependencies]
Expand All @@ -223,6 +233,7 @@ anyhow = "1.0.52"
time_ = { version = "0.3.2", package = "time" }
futures-util = { version = "0.3.19", default-features = false, features = ["alloc"] }
env_logger = "0.11"
wasip3 = "0.5.0"
async-std = { workspace = true, features = ["attributes"] }
tokio = { version = "1.15.0", features = ["full"] }
dotenvy = "0.15.0"
Expand Down Expand Up @@ -254,6 +265,9 @@ cast_sign_loss = 'deny'
# See `clippy.toml`
disallowed_methods = 'deny'

# [patch.crates-io]
# whoami = { git = "https://github.com/Aditya1404Sal/whoami", branch = "v2" }


[lints.rust.unexpected_cfgs]
level = 'warn'
Expand Down Expand Up @@ -361,6 +375,10 @@ name = "mysql"
path = "tests/mysql/mysql.rs"
required-features = ["mysql"]

[[test]]
name = "wasi_integration_test"
path = "tests/mysql/wasi_integration_test.rs"

[[test]]
name = "mysql-types"
path = "tests/mysql/types.rs"
Expand Down Expand Up @@ -453,4 +471,4 @@ required-features = ["postgres"]
[[test]]
name = "postgres-rustsec"
path = "tests/postgres/rustsec.rs"
required-features = ["postgres", "macros", "migrate"]
required-features = ["postgres", "macros", "migrate"]
17 changes: 15 additions & 2 deletions sqlx-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ _tls-rustls-aws-lc-rs = ["_tls-rustls", "rustls/aws-lc-rs", "webpki-roots"]
_tls-rustls-ring-webpki = ["_tls-rustls", "rustls/ring", "webpki-roots"]
_tls-rustls-ring-native-roots = ["_tls-rustls", "rustls/ring", "rustls-native-certs"]
_tls-rustls = ["rustls"]
_tls-wasm = []
_tls-none = []

# support offline/decoupled building (enables serialization of `Describe`)
Expand Down Expand Up @@ -92,8 +93,7 @@ serde = { version = "1.0.132", features = ["derive", "rc"], optional = true }
serde_json = { version = "1.0.73", features = ["raw_value"], optional = true }
toml = { version = "0.8.16", optional = true }
sha2 = { version = "0.10.0", default-features = false, optional = true }
#sqlformat = "0.2.0"
tokio-stream = { version = "0.1.8", features = ["fs"], optional = true }
tokio-stream = { version = "0.1.8", optional = true }
tracing = { version = "0.1.37", features = ["log"] }
smallvec = "1.7.0"
url = { version = "2.2.2" }
Expand All @@ -105,6 +105,19 @@ hashbrown = "0.16.0"

thiserror.workspace = true

# WASM/WASIP3 dependencies (always enabled on wasm32)
[target.'cfg(target_arch = "wasm32")'.dependencies]
tokio = { workspace = true, features = ["sync", "rt"] }
tokio-util = { workspace = true }
wasip3 = { workspace = true }
wit-bindgen = { workspace = true }
futures = "0.3"

# Non-WASM dependencies with platform-specific features
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
tokio = { workspace = true, features = ["net", "fs"], optional = true }
tokio-stream = { version = "0.1.8", features = ["fs"], optional = true }

[dev-dependencies]
tokio = { version = "1", features = ["rt"] }

Expand Down
128 changes: 94 additions & 34 deletions sqlx-core/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,17 @@ use std::fs::Metadata;
use std::io;
use std::path::{Path, PathBuf};

#[cfg(not(target_arch = "wasm32"))]
use crate::rt;

pub struct ReadDir {
#[cfg(not(target_arch = "wasm32"))]
inner: Option<std::fs::ReadDir>,

// On wasm32, all entries are collected upfront into a VecDeque so
// next() can pop them one at a time without needing an async stream handle.
#[cfg(target_arch = "wasm32")]
pub(crate) entries: std::collections::VecDeque<DirEntry>,
}

pub struct DirEntry {
Expand All @@ -23,34 +30,77 @@ pub struct DirEntry {

pub async fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
let path = PathBuf::from(path.as_ref());
rt::spawn_blocking(move || std::fs::read(path)).await
#[cfg(not(target_arch = "wasm32"))]
{
rt::spawn_blocking(move || std::fs::read(path)).await
}
#[cfg(target_arch = "wasm32")]
{
crate::wasm::fs::read(path).await
}
}

pub async fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
let path = PathBuf::from(path.as_ref());
rt::spawn_blocking(move || std::fs::read_to_string(path)).await
#[cfg(not(target_arch = "wasm32"))]
{
rt::spawn_blocking(move || std::fs::read_to_string(path)).await
}
#[cfg(target_arch = "wasm32")]
{
crate::wasm::fs::read_to_string(path).await
}
}

pub async fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = PathBuf::from(path.as_ref());
rt::spawn_blocking(move || std::fs::create_dir_all(path)).await
#[cfg(not(target_arch = "wasm32"))]
{
rt::spawn_blocking(move || std::fs::create_dir_all(path)).await
}
#[cfg(target_arch = "wasm32")]
{
crate::wasm::fs::create_dir_all(path).await
}
}

pub async fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = PathBuf::from(path.as_ref());
rt::spawn_blocking(move || std::fs::remove_file(path)).await
#[cfg(not(target_arch = "wasm32"))]
{
rt::spawn_blocking(move || std::fs::remove_file(path)).await
}
#[cfg(target_arch = "wasm32")]
{
crate::wasm::fs::remove_file(path).await
}
}

pub async fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = PathBuf::from(path.as_ref());
rt::spawn_blocking(move || std::fs::remove_dir(path)).await
#[cfg(not(target_arch = "wasm32"))]
{
rt::spawn_blocking(move || std::fs::remove_dir(path)).await
}
#[cfg(target_arch = "wasm32")]
{
crate::wasm::fs::remove_dir(path).await
}
}

pub async fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = PathBuf::from(path.as_ref());
rt::spawn_blocking(move || std::fs::remove_dir_all(path)).await
#[cfg(not(target_arch = "wasm32"))]
{
rt::spawn_blocking(move || std::fs::remove_dir_all(path)).await
}
#[cfg(target_arch = "wasm32")]
{
crate::wasm::fs::remove_dir_all(path).await
}
}

#[cfg(not(target_arch = "wasm32"))]
pub async fn read_dir(path: PathBuf) -> io::Result<ReadDir> {
let read_dir = rt::spawn_blocking(move || std::fs::read_dir(path)).await?;

Expand All @@ -59,38 +109,48 @@ pub async fn read_dir(path: PathBuf) -> io::Result<ReadDir> {
})
}

#[cfg(target_arch = "wasm32")]
pub async fn read_dir(path: PathBuf) -> io::Result<ReadDir> {
crate::wasm::fs::read_dir(path).await
}

impl ReadDir {
pub async fn next(&mut self) -> io::Result<Option<DirEntry>> {
if let Some(mut read_dir) = self.inner.take() {
let maybe = rt::spawn_blocking(move || {
let entry = read_dir.next().transpose()?;

entry
.map(|entry| -> io::Result<_> {
Ok((
read_dir,
DirEntry {
path: entry.path(),
file_name: entry.file_name(),
// We always want the metadata as well so might as well fetch
// it in the same blocking call.
metadata: entry.metadata()?,
},
))
})
.transpose()
})
.await?;

match maybe {
Some((read_dir, entry)) => {
self.inner = Some(read_dir);
Ok(Some(entry))
#[cfg(not(target_arch = "wasm32"))]
{
if let Some(mut read_dir) = self.inner.take() {
let maybe = rt::spawn_blocking(move || {
let entry = read_dir.next().transpose()?;

entry
.map(|entry| -> io::Result<_> {
Ok((
read_dir,
DirEntry {
path: entry.path(),
file_name: entry.file_name(),
// We always want the metadata as well so might as well fetch
// it in the same blocking call.
metadata: entry.metadata()?,
},
))
})
.transpose()
})
.await?;

match maybe {
Some((read_dir, entry)) => {
self.inner = Some(read_dir);
Ok(Some(entry))
}
None => Ok(None),
}
None => Ok(None),
} else {
Ok(None)
}
} else {
Ok(None)
}
#[cfg(target_arch = "wasm32")]
crate::wasm::fs::next(self).await
}
}
3 changes: 3 additions & 0 deletions sqlx-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
// <https://doc.rust-lang.org/unstable-book/language-features/doc-cfg.html>
#![cfg_attr(docsrs, feature(doc_cfg))]

#[cfg(target_arch = "wasm32")]
pub mod wasm;

#[macro_use]
pub mod ext;

Expand Down
1 change: 1 addition & 0 deletions sqlx-core/src/migrate/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ pub fn checksum(sql: &str) -> Vec<u8> {
Vec::from(Sha384::digest(sql).as_slice())
}

#[cfg(not(target_arch = "wasm32"))]
pub fn checksum_fragments<'a>(fragments: impl Iterator<Item = &'a str>) -> Vec<u8> {
let mut digest = Sha384::new();

Expand Down
4 changes: 4 additions & 0 deletions sqlx-core/src/migrate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,9 @@ pub use migration_type::MigrationType;
pub use migrator::Migrator;
pub use source::{MigrationSource, ResolveConfig, ResolveWith};

#[cfg(target_arch = "wasm32")]
#[doc(hidden)]
pub use source::resolve;
#[cfg(not(target_arch = "wasm32"))]
#[doc(hidden)]
pub use source::{resolve_blocking, resolve_blocking_with_config};
Loading
Loading